static void start_connect(SESSION *session) { int fd; struct linger linger; /* * Some systems don't set the socket error when connect() fails early * (loopback) so we must deal with the error immediately, rather than * retrieving it later with getsockopt(). We can't use MSG_PEEK to * distinguish between server disconnect and connection refused. */ if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) msg_fatal("socket: %m"); (void) non_blocking(fd, NON_BLOCKING); linger.l_onoff = 1; linger.l_linger = 0; if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof(linger)) < 0) msg_warn("setsockopt SO_LINGER %d: %m", linger.l_linger); session->stream = vstream_fdopen(fd, O_RDWR); event_enable_write(fd, connect_done, (char *) session); smtp_timeout_setup(session->stream, var_timeout); if (inet_windowsize > 0) set_inet_windowsize(fd, inet_windowsize); if (sane_connect(fd, sa, sa_length) < 0 && errno != EINPROGRESS) fail_connect(session); }
void nbbio_enable_write(NBBIO *np, int timeout) { const char *myname = "nbbio_enable_write"; /* * Sanity checks. */ if (np->flags & NBBIO_MASK_ACTIVE) msg_panic("%s: socket fd=%d is enabled for %s", myname, np->fd, NBBIO_OP_NAME(np)); if (timeout <= 0) msg_panic("%s: socket fd=%d bad timeout %d", myname, np->fd, timeout); if (np->write_pend <= 0) msg_panic("%s: socket fd=%d: empty write buffer", myname, np->fd); /* * Enable events. */ event_enable_write(np->fd, nbbio_event, (char *) np); event_request_timer(nbbio_event, (char *) np, timeout); np->flags |= NBBIO_FLAG_WRITE; }
static int tlsp_eval_tls_error(TLSP_STATE *state, int err) { int ciphertext_fd = state->ciphertext_fd; /* * The ciphertext file descriptor is in non-blocking mode, meaning that * each SSL_accept/connect/read/write/shutdown request may return an * "error" indication that it needs to read or write more ciphertext. The * purpose of this routine is to translate those "error" indications into * the appropriate read/write/timeout event requests. */ switch (err) { /* * No error from SSL_read and SSL_write means that the plaintext * output buffer is full and that the plaintext input buffer is * empty. Stop read/write events on the ciphertext stream. Keep the * timer alive as a safety mechanism for the case that the plaintext * pseudothreads get stuck. */ case SSL_ERROR_NONE: if (state->ssl_last_err != SSL_ERROR_NONE) { event_disable_readwrite(ciphertext_fd); event_request_timer(tlsp_ciphertext_event, (void *) state, state->timeout); state->ssl_last_err = SSL_ERROR_NONE; } return (0); /* * The TLS engine wants to write to the network. Turn on * write/timeout events on the ciphertext stream. */ case SSL_ERROR_WANT_WRITE: if (state->ssl_last_err == SSL_ERROR_WANT_READ) event_disable_readwrite(ciphertext_fd); if (state->ssl_last_err != SSL_ERROR_WANT_WRITE) { event_enable_write(ciphertext_fd, tlsp_ciphertext_event, (void *) state); state->ssl_last_err = SSL_ERROR_WANT_WRITE; } event_request_timer(tlsp_ciphertext_event, (void *) state, state->timeout); return (0); /* * The TLS engine wants to read from the network. Turn on * read/timeout events on the ciphertext stream. */ case SSL_ERROR_WANT_READ: if (state->ssl_last_err == SSL_ERROR_WANT_WRITE) event_disable_readwrite(ciphertext_fd); if (state->ssl_last_err != SSL_ERROR_WANT_READ) { event_enable_read(ciphertext_fd, tlsp_ciphertext_event, (void *) state); state->ssl_last_err = SSL_ERROR_WANT_READ; } event_request_timer(tlsp_ciphertext_event, (void *) state, state->timeout); return (0); /* * Some error. Self-destruct. This automagically cleans up all * pending read/write and timeout event requests, making state a * dangling pointer. */ case SSL_ERROR_SSL: tls_print_errors(); /* FALLTHROUGH */ default: tlsp_state_free(state); return (-1); } }