MS_SIM_COMMAND Trick::MSSharedMem::read_command() { MS_SIM_COMMAND command; double readtry_time = 0.0; struct timespec ts_Start; /** @par Detailed Design */ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_Start); if (getpid() == shm_addr->master_pid) { /** @li Get slave command from shared memory */ // I am master, so read slave command while (MSQ_ISEMPTY(shm_addr->slave_command)) { if (readtry_time >= sync_wait_limit) { break; } readtry_time = read_wait(&ts_Start); } if (!MSQ_ISEMPTY(shm_addr->slave_command)) { command = MSQ_FRONT(shm_addr->slave_command); //fprintf(stderr, "+++++read_command pid=%d command=%d (from slave)\n", getpid(), command); MSQ_POP(shm_addr->slave_command); return (command) ; /** @li If no new data before timeout limit, return "error" command */ } else { //fprintf(stderr, "+++++read_command pid=%d command=%d (from slave) ERROR readtry=%f\n", getpid(), command, readtry_time); return (MS_ErrorCmd) ; } } else { /** @li Get master command from shared memory */ // I am slave, so read master command while (MSQ_ISEMPTY(shm_addr->master_command)) { if (readtry_time >= sync_wait_limit) { break; } readtry_time = read_wait(&ts_Start); } if (!MSQ_ISEMPTY(shm_addr->master_command)) { command = MSQ_FRONT(shm_addr->master_command); //fprintf(stderr, "+++++read_command pid=%d command=%d (from master)\n", getpid(), command); MSQ_POP(shm_addr->master_command); return (command) ; /** @li If no new data before timeout limit, return "error" command */ } else { //fprintf(stderr, "+++++read_command pid=%d command=%d (from master) ERROR readtry=%f\n", getpid(), command, readtry_time); return (MS_ErrorCmd) ; } } }
int Trick::MSSharedMem::read_port() { int in_port; double readtry_time = 0.0; struct timespec ts_Start; /** @par Detailed Design */ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_Start); /** @li Get port number from shared memory */ while (shm_addr->slave_port == MS_ERROR_PORT) { if (readtry_time >= sync_wait_limit) { break; } readtry_time = read_wait(&ts_Start); } if (shm_addr->slave_port != MS_ERROR_PORT) { in_port = shm_addr->slave_port; shm_addr->slave_port = MS_ERROR_PORT; // default value return (in_port) ; /** @li If no new data before timeout limit, return "error" port */ } else { return (MS_ERROR_PORT) ; } }
ssize_t timed_read(int fd, void *buf, size_t len, int timeout, void *unused_context) { ssize_t ret; /* * Wait for a limited amount of time for something to happen. If nothing * happens, report an ETIMEDOUT error. * * XXX Solaris 8 read() fails with EAGAIN after read-select() returns * success. */ for (;;) { if (timeout > 0 && read_wait(fd, timeout) < 0) return (-1); if ((ret = read(fd, buf, len)) < 0 && timeout > 0 && errno == EAGAIN) { msg_warn("read() returns EAGAIN on a readable file descriptor!"); msg_warn("pausing to avoid going into a tight select/read loop!"); sleep(1); continue; } else if (ret < 0 && errno == EINTR) { continue; } else { return (ret); } } }
long long Trick::MSSharedMem::read_time() { long long in_time; double readtry_time = 0.0; struct timespec ts_Start; /** @par Detailed Design */ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_Start); /** @li Get time from shared memory */ while (MSQ_ISEMPTY(shm_addr->master_time)) { if (readtry_time >= sync_wait_limit) { break; } readtry_time = read_wait(&ts_Start); } if (!MSQ_ISEMPTY(shm_addr->master_time)) { in_time = MSQ_FRONT(shm_addr->master_time); //fprintf(stderr, "+++++read_time pid=%d time=%lld readtry=%f\n", getpid(), in_time, readtry_time); MSQ_POP(shm_addr->master_time); return (in_time) ; /** @li If no new data before timeout limit, return "error" time */ } else { //fprintf(stderr, "+++++read_time pid=%d time=%lld ERROR readtry=%f\n", getpid(), in_time, readtry_time,); fflush(stderr); return (MS_ERROR_TIME) ; } }
DELIVER_REQUEST *deliver_request_read(VSTREAM *stream) { DELIVER_REQUEST *request; /* * Tell the queue manager that we are ready for this request. */ if (deliver_request_initial(stream) != 0) return (0); /* * Be prepared for the queue manager to change its mind after contacting * us. This can happen when a transport or host goes bad. */ (void) read_wait(vstream_fileno(stream), -1); if (peekfd(vstream_fileno(stream)) <= 0) return (0); /* * Allocate and read the queue manager's delivery request. */ #define XXX_DEFER_STATUS -1 request = deliver_request_alloc(); if (deliver_request_get(stream, request) < 0) { deliver_request_done(stream, request, XXX_DEFER_STATUS); request = 0; } return (request); }
static int flush_request_receive(VSTREAM *client_stream, VSTRING *request) { int count; /* * Kluge: choose the protocol depending on the request size. */ if (read_wait(vstream_fileno(client_stream), var_ipc_timeout) < 0) { msg_warn("timeout while waiting for data from %s", VSTREAM_PATH(client_stream)); return (-1); } if ((count = peekfd(vstream_fileno(client_stream))) < 0) { msg_warn("cannot examine read buffer of %s: %m", VSTREAM_PATH(client_stream)); return (-1); } /* * Short request: master trigger. Use the string+null protocol. */ if (count <= 2) { if (vstring_get_null(request, client_stream) == VSTREAM_EOF) { msg_warn("end-of-input while reading request from %s: %m", VSTREAM_PATH(client_stream)); return (-1); } } /* * Long request: real flush client. Use the attribute list protocol. */ else { if (attr_scan(client_stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT, RECV_ATTR_STR(MAIL_ATTR_REQ, request), ATTR_TYPE_END) != 1) { return (-1); } } return (0); }
static void trigger_server_accept_pass(int unused_event, char *context) { const char *myname = "trigger_server_accept_pass"; int listen_fd = CAST_CHAR_PTR_TO_INT(context); int time_left = 0; int fd; if (msg_verbose) msg_info("%s: trigger arrived", myname); /* * Read a message from a socket. Be prepared for accept() to fail because * some other process already got the connection. The socket is * non-blocking so we won't get stuck when multiple processes wake up. * Don't get stuck when the client connects but sends no data. Restart * the idle timer if this was a false alarm. */ if (var_idle_limit > 0) time_left = event_cancel_timer(trigger_server_timeout, (char *) 0); if (trigger_server_pre_accept) trigger_server_pre_accept(trigger_server_name, trigger_server_argv); fd = pass_accept(listen_fd); if (trigger_server_lock != 0 && myflock(vstream_fileno(trigger_server_lock), INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) msg_fatal("select unlock: %m"); if (fd < 0) { if (errno != EAGAIN) msg_error("accept connection: %m"); if (time_left >= 0) event_request_timer(trigger_server_timeout, (char *) 0, time_left); return; } close_on_exec(fd, CLOSE_ON_EXEC); if (read_wait(fd, 10) == 0) trigger_server_wakeup(fd); else if (time_left >= 0) event_request_timer(trigger_server_timeout, (char *) 0, time_left); close(fd); }
char Trick::MSSharedMem::read_name(char * read_data, size_t size) { double readtry_time = 0.0; struct timespec ts_Start; /** @par Detailed Design */ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_Start); /** @li Get name (character array) from shared memory */ while (shm_addr->chkpnt_name[0] == MS_ERROR_NAME) { if (readtry_time >= sync_wait_limit) { break; } readtry_time = read_wait(&ts_Start); } if (shm_addr->chkpnt_name[0] != MS_ERROR_NAME) { memcpy(read_data, shm_addr->chkpnt_name, size); shm_addr->chkpnt_name[0] = MS_ERROR_NAME; // default value return (0) ; /** @li If no new data before timeout limit, return "error" name */ } else { return (MS_ERROR_NAME) ; } }
static void tlsp_get_request_event(int event, void *context) { const char *myname = "tlsp_get_request_event"; TLSP_STATE *state = (TLSP_STATE *) context; VSTREAM *plaintext_stream = state->plaintext_stream; int plaintext_fd = vstream_fileno(plaintext_stream); static VSTRING *remote_endpt; static VSTRING *server_id; int req_flags; int timeout; int ready; /* * One-time initialization. */ if (remote_endpt == 0) { remote_endpt = vstring_alloc(10); server_id = vstring_alloc(10); } /* * At this point we still manually manage plaintext read/write/timeout * events. Turn off timer events. Below we disable read events on error, * and redefine read events on success. */ if (event != EVENT_TIME) event_cancel_timer(tlsp_get_request_event, (void *) state); else errno = ETIMEDOUT; /* * We must send some data, after receiving the request attributes and * before receiving the remote file descriptor. We can't assume * UNIX-domain socket semantics here. */ if (event != EVENT_READ || attr_scan(plaintext_stream, ATTR_FLAG_STRICT, RECV_ATTR_STR(MAIL_ATTR_REMOTE_ENDPT, remote_endpt), RECV_ATTR_INT(MAIL_ATTR_FLAGS, &req_flags), RECV_ATTR_INT(MAIL_ATTR_TIMEOUT, &timeout), RECV_ATTR_STR(MAIL_ATTR_SERVER_ID, server_id), ATTR_TYPE_END) != 4) { msg_warn("%s: receive request attributes: %m", myname); event_disable_readwrite(plaintext_fd); tlsp_state_free(state); return; } /* * If the requested TLS engine is unavailable, hang up after making sure * that the plaintext peer has received our "sorry" indication. */ ready = ((req_flags & TLS_PROXY_FLAG_ROLE_SERVER) != 0 && tlsp_server_ctx != 0); if (attr_print(plaintext_stream, ATTR_FLAG_NONE, SEND_ATTR_INT(MAIL_ATTR_STATUS, ready), ATTR_TYPE_END) != 0 || vstream_fflush(plaintext_stream) != 0 || ready == 0) { read_wait(plaintext_fd, TLSP_INIT_TIMEOUT); /* XXX */ event_disable_readwrite(plaintext_fd); tlsp_state_free(state); return; } /* * XXX We use the same fixed timeout throughout the entire session for * both plaintext and ciphertext communication. This timeout is just a * safety feature; the real timeout will be enforced by our plaintext * peer. */ else { state->remote_endpt = mystrdup(STR(remote_endpt)); state->server_id = mystrdup(STR(server_id)); msg_info("CONNECT %s %s", (req_flags & TLS_PROXY_FLAG_ROLE_SERVER) ? "from" : (req_flags & TLS_PROXY_FLAG_ROLE_CLIENT) ? "to" : "(bogus_direction)", state->remote_endpt); state->req_flags = req_flags; state->timeout = timeout + 10; /* XXX */ event_enable_read(plaintext_fd, tlsp_get_fd_event, (void *) state); event_request_timer(tlsp_get_fd_event, (void *) state, TLSP_INIT_TIMEOUT); return; } }
void RC_UART::loop() { union { uint16_t period[NUM_CHANNELS]; uint8_t bytes[NUM_CHANNELS*2]; } u; // wait for magic while (true) { uint8_t c = read_wait(); if (c == ESC_MAGIC) break; // hal.console->printf("c=0x%02x\n", (unsigned)c); } uint8_t nbytes=0; // wait for periods while (nbytes < NUM_CHANNELS*2) { u.bytes[nbytes++] = read_wait(); } // and CRC union { uint8_t crc[2]; uint16_t crc16; } u2; u2.crc[0] = read_wait(); u2.crc[1] = read_wait(); uint16_t crc2 = crc_calculate(u.bytes, NUM_CHANNELS*2); if (crc2 != u2.crc16) { hal.console->printf("bad CRC 0x%04x should be 0x%04x\n", (unsigned)crc2, (unsigned)u2.crc16); return; } // and output for (uint8_t i=0; i<NUM_CHANNELS; i++) { if (u.period[i] == 0) { continue; } if (!(enable_mask & 1U<<i)) { if (enable_mask == 0) { hal.rcout->force_safety_off(); } rc[i].enable_out(); enable_mask |= 1U<<i; } rc[i].set_radio_out(u.period[i]); rc[i].output(); } // report periods to console for debug counter++; if (counter % 100 == 0) { hal.console->printf("%4u %4u %4u %4u\n", (unsigned)u.period[0], (unsigned)u.period[1], (unsigned)u.period[2], (unsigned)u.period[3]); } // every 10th frame give an RCInput frame if possible if (counter % 10 == 0) { struct PACKED { uint8_t magic = 0xf6; uint16_t rcin[8]; uint16_t crc; } rcin; if (hal.rcin->new_input() && hal.rcin->read(rcin.rcin, 8) == 8) { rcin.crc = crc_calculate((uint8_t*)&rcin.rcin[0], 16); hal.UART->write((uint8_t*)&rcin, sizeof(rcin)); } } }
int tls_bio(int fd, int timeout, TLS_SESS_STATE *TLScontext, int (*hsfunc) (SSL *), int (*rfunc) (SSL *, void *, int), int (*wfunc) (SSL *, const void *, int), void *buf, int num) { const char *myname = "tls_bio"; int status; int err; int enable_deadline; struct timeval time_left; /* amount of time left */ struct timeval time_deadline; /* time of deadline */ struct timeval time_now; /* time after SSL_mumble() call */ /* * Compensation for interface mis-match: With VSTREAMs, timeout <= 0 * means wait forever; with the read/write_wait() calls below, we need to * specify timeout < 0 instead. * * Safety: no time limit means no deadline. */ if (timeout <= 0) { timeout = -1; enable_deadline = 0; } /* * Deadline management is simpler than with VSTREAMs, because we don't * need to decrement a per-stream time limit. We just work within the * budget that is available for this tls_bio() call. */ else { enable_deadline = vstream_fstat(TLScontext->stream, VSTREAM_FLAG_DEADLINE); if (enable_deadline) { GETTIMEOFDAY(&time_deadline); time_deadline.tv_sec += timeout; } } /* * If necessary, retry the SSL handshake or read/write operation after * handling any pending network I/O. */ for (;;) { if (hsfunc) status = hsfunc(TLScontext->con); else if (rfunc) status = rfunc(TLScontext->con, buf, num); else if (wfunc) status = wfunc(TLScontext->con, buf, num); else msg_panic("%s: nothing to do here", myname); err = SSL_get_error(TLScontext->con, status); #if (OPENSSL_VERSION_NUMBER <= 0x0090581fL) /* * There is a bug up to and including OpenSSL-0.9.5a: if an error * occurs while checking the peers certificate due to some * certificate error (e.g. as happend with a RSA-padding error), the * error is put onto the error stack. If verification is not * enforced, this error should be ignored, but the error-queue is not * cleared, so we can find this error here. The bug has been fixed on * May 28, 2000. * * This bug so far has only manifested as 4800:error:0407006A:rsa * routines:RSA_padding_check_PKCS1_type_1:block type is not * 01:rsa_pk1.c:100: 4800:error:04067072:rsa * routines:RSA_EAY_PUBLIC_DECRYPT:padding check * failed:rsa_eay.c:396: 4800:error:0D079006:asn1 encoding * routines:ASN1_verify:bad get asn1 object call:a_verify.c:109: so * that we specifically test for this error. We print the errors to * the logfile and automatically clear the error queue. Then we retry * to get another error code. We cannot do better, since we can only * retrieve the last entry of the error-queue without actually * cleaning it on the way. * * This workaround is secure, as verify_result is set to "failed" * anyway. */ if (err == SSL_ERROR_SSL) { if (ERR_peek_error() == 0x0407006AL) { tls_print_errors(); msg_info("OpenSSL <= 0.9.5a workaround called: certificate errors ignored"); err = SSL_get_error(TLScontext->con, status); } } #endif /* * Correspondence between SSL_ERROR_* error codes and tls_bio_(read, * write, accept, connect, shutdown) return values (for brevity: * retval). * * SSL_ERROR_NONE corresponds with retval > 0. With SSL_(read, write) * this is the number of plaintext bytes sent or received. With * SSL_(accept, connect, shutdown) this means that the operation was * completed successfully. * * SSL_ERROR_WANT_(WRITE, READ) start a new loop iteration, or force * (retval = -1, errno = ETIMEDOUT) when the time limit is exceeded. * * All other SSL_ERROR_* cases correspond with retval <= 0. With * SSL_(read, write, accept, connect) retval == 0 means that the * remote party either closed the network connection or that it * requested TLS shutdown; with SSL_shutdown() retval == 0 means that * our own shutdown request is in progress. With all operations * retval < 0 means that there was an error. In the latter case, * SSL_ERROR_SYSCALL means that error details are returned via the * errno value. * * Find out if we must retry the operation and/or if there is pending * network I/O. * * XXX If we're the first to invoke SSL_shutdown(), then the operation * isn't really complete when the call returns. We could hide that * anomaly here and repeat the call. */ switch (err) { case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: if (enable_deadline) { GETTIMEOFDAY(&time_now); timersub(&time_deadline, &time_now, &time_left); timeout = time_left.tv_sec + (time_left.tv_usec > 0); if (timeout <= 0) { errno = ETIMEDOUT; return (-1); } } if (err == SSL_ERROR_WANT_WRITE) { if (write_wait(fd, timeout) < 0) return (-1); /* timeout error */ } else { if (read_wait(fd, timeout) < 0) return (-1); /* timeout error */ } break; /* * Unhandled cases: SSL_ERROR_WANT_(ACCEPT, CONNECT, X509_LOOKUP) * etc. Historically, Postfix silently treated these as ordinary * I/O errors so we don't really know how common they are. For * now, we just log a warning. */ default: msg_warn("%s: unexpected SSL_ERROR code %d", myname, err); /* FALLTHROUGH */ /* * With tls_timed_read() and tls_timed_write() the caller is the * VSTREAM library module which is unaware of TLS, so we log the * TLS error stack here. In a better world, each VSTREAM I/O * object would provide an error reporting method in addition to * the timed_read and timed_write methods, so that we would not * need to have ad-hoc code like this. */ case SSL_ERROR_SSL: if (rfunc || wfunc) tls_print_errors(); /* FALLTHROUGH */ case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_NONE: errno = 0; /* avoid bogus warnings */ /* FALLTHROUGH */ case SSL_ERROR_SYSCALL: return (status); } } }