Exemple #1
0
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) ;
        }
    }
}
Exemple #2
0
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) ;
    }
}
Exemple #3
0
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);
	}
    }
}
Exemple #4
0
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);
}
Exemple #6
0
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);
}
Exemple #7
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);
}
Exemple #8
0
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) ;
    }
}
Exemple #9
0
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;
    }
}
Exemple #10
0
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));
        }
    }
}
Exemple #11
0
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);
        }
    }
}