Exemplo n.º 1
0
ssize_t write_buf(int fd, const char *buf, ssize_t len, int timeout)
{
    const char *start = buf;
    ssize_t count;
    time_t  expire;
    int     time_left = timeout;

    if (time_left > 0)
	expire = time((time_t *) 0) + time_left;

    while (len > 0) {
	if (time_left > 0 && write_wait(fd, time_left) < 0)
	    return (-1);
	if ((count = write(fd, buf, len)) < 0) {
	    if ((errno == EAGAIN && time_left > 0) || errno == EINTR)
		 /* void */ ;
	    else
		return (-1);
	} else {
	    buf += count;
	    len -= count;
	}
	if (len > 0 && time_left > 0) {
	    time_left = expire - time((time_t *) 0);
	    if (time_left <= 0) {
		errno = ETIMEDOUT;
		return (-1);
	    }
	}
    }
    return (buf - start);
}
Exemplo n.º 2
0
int     timed_connect(int sock, struct sockaddr * sa, int len, int timeout)
{
    int     error;
    SOCKOPT_SIZE error_len;

    /*
     * Sanity check. Just like with timed_wait(), the timeout must be a
     * positive number.
     */
    if (timeout <= 0)
	msg_panic("timed_connect: bad timeout: %d", timeout);

    /*
     * Start the connection, and handle all possible results.
     */
    if (sane_connect(sock, sa, len) == 0)
	return (0);
    if (errno != EINPROGRESS)
	return (-1);

    /*
     * A connection is in progress. Wait for a limited amount of time for
     * something to happen. If nothing happens, report an error.
     */
    if (write_wait(sock, timeout) < 0)
	return (-1);

    /*
     * Something happened. Some Solaris 2 versions have getsockopt() itself
     * return the error, instead of returning it via the parameter list.
     */
    error = 0;
    error_len = sizeof(error);
    if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &error, &error_len) < 0)
	return (-1);
    if (error) {
	errno = error;
	return (-1);
    }

    /*
     * No problems.
     */
    return (0);
}
Exemplo n.º 3
0
int     write_buf(int fd, const char *buf, int len, int timeout)
{
    int     count;

    while (len > 0) {
	if (timeout > 0 && write_wait(fd, timeout) < 0)
	    return (-1);
	if ((count = write(fd, buf, len)) < 0) {
	    if (errno == EAGAIN && timeout > 0)
		continue;
	    return (-1);
	}
	if (count == 0)
	    msg_fatal("write returned 0");
	buf += count;
	len -= count;
    }
    return (len);
}
Exemplo n.º 4
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);
        }
    }
}
Exemplo n.º 5
0
static int generic_write( gpib_board_t *board, uint8_t *buffer, size_t length,
	int send_eoi, int send_commands, size_t *bytes_written)
{
	size_t count = 0;
	ssize_t retval = 0;
	tnt4882_private_t *tnt_priv = board->private_data;
	nec7210_private_t *nec_priv = &tnt_priv->nec7210_priv;
	unsigned int bits, imr0_bits, imr1_bits, imr2_bits;
	int32_t hw_count;
	unsigned long flags;

	*bytes_written = 0;
	// FIXME: really, DEV_CLEAR_BN should happen elsewhere to prevent race
	clear_bit(DEV_CLEAR_BN, &nec_priv->state);	
	imr1_bits = nec_priv->reg_bits[ IMR1 ];
	imr2_bits = nec_priv->reg_bits[ IMR2 ];
	nec7210_set_reg_bits( nec_priv, IMR1, 0xff, HR_ERRIE | HR_DECIE );
	if( nec_priv->type != TNT4882 )
		nec7210_set_reg_bits( nec_priv, IMR2, 0xff, HR_DMAO );
	else
		nec7210_set_reg_bits( nec_priv, IMR2, 0xff, 0 );
	imr0_bits = tnt_priv->imr0_bits;
	tnt_priv->imr0_bits &= ~TNT_ATNI_BIT;
	tnt_writeb(tnt_priv, tnt_priv->imr0_bits, IMR0);

	tnt_writeb( tnt_priv, RESET_FIFO, CMDR );
	udelay(1);

	bits = TNT_TLCHE | TNT_B_16BIT;
	if( send_eoi )
	{
		bits |= TNT_CCEN;
		if(nec_priv->type != TNT4882 )
			tnt_writeb( tnt_priv, AUX_SEOI, CCR );
	}
	if( send_commands )
		bits |= TNT_COMMAND;
	tnt_writeb( tnt_priv, bits, CFG );

	// load 2's complement of count into hardware counters
	hw_count = -length;
	tnt_writeb( tnt_priv, hw_count & 0xff, CNT0 );
	tnt_writeb( tnt_priv, ( hw_count >> 8 ) & 0xff, CNT1 );
	tnt_writeb( tnt_priv, ( hw_count >> 16 ) & 0xff, CNT2 );
	tnt_writeb( tnt_priv, ( hw_count >> 24 ) & 0xff, CNT3 );

	tnt_writeb( tnt_priv, GO, CMDR );
	udelay(1);

	spin_lock_irqsave( &board->spinlock, flags );
	tnt_priv->imr3_bits |= HR_DONE;
	tnt_writeb( tnt_priv, tnt_priv->imr3_bits, IMR3 );
	spin_unlock_irqrestore( &board->spinlock, flags );

	while( count < length  )
	{
		// wait until byte is ready to be sent
		retval = write_wait( board, tnt_priv, 0 );
		if( retval < 0 ) break;
		if( fifo_xfer_done( tnt_priv ) ) break;

		spin_lock_irqsave( &board->spinlock, flags );
		while( fifo_space_available( tnt_priv ) && count < length )
		{
			uint16_t word;

			word = buffer[ count++ ] & 0xff;
			if( count < length )
				word |= ( buffer[ count++ ] << 8 ) & 0xff00;
			tnt_priv->io_writew( word, nec_priv->iobase + FIFOB );
		}
		tnt_priv->imr3_bits |= HR_NFF;
		tnt_writeb( tnt_priv, tnt_priv->imr3_bits, IMR3 );
		spin_unlock_irqrestore( &board->spinlock, flags );

		if(need_resched())
			schedule();
	}
	// wait last byte has been sent
	if(retval == 0)
		retval = write_wait(board, tnt_priv, 1);

	tnt_writeb( tnt_priv, STOP, CMDR );
	udelay(1);

	nec7210_set_reg_bits( nec_priv, IMR1, 0xff, imr1_bits );
	nec7210_set_reg_bits( nec_priv, IMR2, 0xff, imr2_bits );
	tnt_priv->imr0_bits = imr0_bits;
	tnt_writeb(tnt_priv, tnt_priv->imr0_bits, IMR0);
	/* force handling of any interrupts that happened
	 * while they were masked (this appears to be needed)*/
	tnt4882_internal_interrupt(board);
	*bytes_written = length - tnt_transfer_count(tnt_priv);
	return retval;
}