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); }
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); }
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); }
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); } } }
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; }