diff options
Diffstat (limited to 'smtpd/ioev.c')
-rw-r--r-- | smtpd/ioev.c | 1064 |
1 files changed, 0 insertions, 1064 deletions
diff --git a/smtpd/ioev.c b/smtpd/ioev.c deleted file mode 100644 index e0a8a096..00000000 --- a/smtpd/ioev.c +++ /dev/null @@ -1,1064 +0,0 @@ -/* $OpenBSD: ioev.c,v 1.42 2019/06/12 17:42:53 eric Exp $ */ -/* - * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "includes.h" - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/socket.h> - -#include <err.h> -#include <errno.h> -#include <event.h> -#include <fcntl.h> -#include <inttypes.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <unistd.h> - -#include "ioev.h" -#include "iobuf.h" - -#ifdef IO_TLS -#include <openssl/err.h> -#include <openssl/ssl.h> -#endif - -enum { - IO_STATE_NONE, - IO_STATE_CONNECT, - IO_STATE_CONNECT_TLS, - IO_STATE_ACCEPT_TLS, - IO_STATE_UP, - - IO_STATE_MAX, -}; - -#define IO_PAUSE_IN IO_IN -#define IO_PAUSE_OUT IO_OUT -#define IO_READ 0x04 -#define IO_WRITE 0x08 -#define IO_RW (IO_READ | IO_WRITE) -#define IO_RESET 0x10 /* internal */ -#define IO_HELD 0x20 /* internal */ - -struct io { - int sock; - void *arg; - void (*cb)(struct io*, int, void *); - struct iobuf iobuf; - size_t lowat; - int timeout; - int flags; - int state; - struct event ev; - void *tls; - const char *error; /* only valid immediately on callback */ -}; - -const char* io_strflags(int); -const char* io_evstr(short); - -void _io_init(void); -void io_hold(struct io *); -void io_release(struct io *); -void io_callback(struct io*, int); -void io_dispatch(int, short, void *); -void io_dispatch_connect(int, short, void *); -size_t io_pending(struct io *); -size_t io_queued(struct io*); -void io_reset(struct io *, short, void (*)(int, short, void*)); -void io_frame_enter(const char *, struct io *, int); -void io_frame_leave(struct io *); - -#ifdef IO_TLS -void ssl_error(const char *); /* XXX external */ - -static const char* io_tls_error(void); -void io_dispatch_accept_tls(int, short, void *); -void io_dispatch_connect_tls(int, short, void *); -void io_dispatch_read_tls(int, short, void *); -void io_dispatch_write_tls(int, short, void *); -void io_reload_tls(struct io *io); -#endif - -static struct io *current = NULL; -static uint64_t frame = 0; -static int _io_debug = 0; - -#define io_debug(args...) do { if (_io_debug) printf(args); } while(0) - - -const char* -io_strio(struct io *io) -{ - static char buf[128]; - char ssl[128]; - - ssl[0] = '\0'; -#ifdef IO_TLS - if (io->tls) { - (void)snprintf(ssl, sizeof ssl, " tls=%s:%s:%d", - SSL_get_version(io->tls), - SSL_get_cipher_name(io->tls), - SSL_get_cipher_bits(io->tls, NULL)); - } -#endif - - (void)snprintf(buf, sizeof buf, - "<io:%p fd=%d to=%d fl=%s%s ib=%zu ob=%zu>", - io, io->sock, io->timeout, io_strflags(io->flags), ssl, - io_pending(io), io_queued(io)); - - return (buf); -} - -#define CASE(x) case x : return #x - -const char* -io_strevent(int evt) -{ - static char buf[32]; - - switch (evt) { - CASE(IO_CONNECTED); - CASE(IO_TLSREADY); - CASE(IO_DATAIN); - CASE(IO_LOWAT); - CASE(IO_DISCONNECTED); - CASE(IO_TIMEOUT); - CASE(IO_ERROR); - default: - (void)snprintf(buf, sizeof(buf), "IO_? %d", evt); - return buf; - } -} - -void -io_set_nonblocking(int fd) -{ - int flags; - - if ((flags = fcntl(fd, F_GETFL)) == -1) - err(1, "io_set_blocking:fcntl(F_GETFL)"); - - flags |= O_NONBLOCK; - - if (fcntl(fd, F_SETFL, flags) == -1) - err(1, "io_set_blocking:fcntl(F_SETFL)"); -} - -void -io_set_nolinger(int fd) -{ - struct linger l; - - memset(&l, 0, sizeof(l)); - if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) == -1) - err(1, "io_set_linger:setsockopt()"); -} - -/* - * Event framing must not rely on an io pointer to refer to the "same" io - * throughout the frame, because this is not always the case: - * - * 1) enter(addr0) -> free(addr0) -> leave(addr0) = SEGV - * 2) enter(addr0) -> free(addr0) -> malloc == addr0 -> leave(addr0) = BAD! - * - * In both case, the problem is that the io is freed in the callback, so - * the pointer becomes invalid. If that happens, the user is required to - * call io_clear, so we can adapt the frame state there. - */ -void -io_frame_enter(const char *where, struct io *io, int ev) -{ - io_debug("\n=== %" PRIu64 " ===\n" - "io_frame_enter(%s, %s, %s)\n", - frame, where, io_evstr(ev), io_strio(io)); - - if (current) - errx(1, "io_frame_enter: interleaved frames"); - - current = io; - - io_hold(io); -} - -void -io_frame_leave(struct io *io) -{ - io_debug("io_frame_leave(%" PRIu64 ")\n", frame); - - if (current && current != io) - errx(1, "io_frame_leave: io mismatch"); - - /* io has been cleared */ - if (current == NULL) - goto done; - - /* TODO: There is a possible optimization there: - * In a typical half-duplex request/response scenario, - * the io is waiting to read a request, and when done, it queues - * the response in the output buffer and goes to write mode. - * There, the write event is set and will be triggered in the next - * event frame. In most case, the write call could be done - * immediately as part of the last read frame, thus avoiding to go - * through the event loop machinery. So, as an optimisation, we - * could detect that case here and force an event dispatching. - */ - - /* Reload the io if it has not been reset already. */ - io_release(io); - current = NULL; - done: - io_debug("=== /%" PRIu64 "\n", frame); - - frame += 1; -} - -void -_io_init() -{ - static int init = 0; - - if (init) - return; - - init = 1; - _io_debug = getenv("IO_DEBUG") != NULL; -} - -struct io * -io_new(void) -{ - struct io *io; - - _io_init(); - - if ((io = calloc(1, sizeof(*io))) == NULL) - return NULL; - - io->sock = -1; - io->timeout = -1; - - if (iobuf_init(&io->iobuf, 0, 0) == -1) { - free(io); - return NULL; - } - - return io; -} - -void -io_free(struct io *io) -{ - io_debug("io_clear(%p)\n", io); - - /* the current io is virtually dead */ - if (io == current) - current = NULL; - -#ifdef IO_TLS - SSL_free(io->tls); - io->tls = NULL; -#endif - - if (event_initialized(&io->ev)) - event_del(&io->ev); - if (io->sock != -1) { - close(io->sock); - io->sock = -1; - } - - iobuf_clear(&io->iobuf); - free(io); -} - -void -io_hold(struct io *io) -{ - io_debug("io_enter(%p)\n", io); - - if (io->flags & IO_HELD) - errx(1, "io_hold: io is already held"); - - io->flags &= ~IO_RESET; - io->flags |= IO_HELD; -} - -void -io_release(struct io *io) -{ - if (!(io->flags & IO_HELD)) - errx(1, "io_release: io is not held"); - - io->flags &= ~IO_HELD; - if (!(io->flags & IO_RESET)) - io_reload(io); -} - -void -io_set_fd(struct io *io, int fd) -{ - io->sock = fd; - if (fd != -1) - io_reload(io); -} - -void -io_set_callback(struct io *io, void(*cb)(struct io *, int, void *), void *arg) -{ - io->cb = cb; - io->arg = arg; -} - -void -io_set_timeout(struct io *io, int msec) -{ - io_debug("io_set_timeout(%p, %d)\n", io, msec); - - io->timeout = msec; -} - -void -io_set_lowat(struct io *io, size_t lowat) -{ - io_debug("io_set_lowat(%p, %zu)\n", io, lowat); - - io->lowat = lowat; -} - -void -io_pause(struct io *io, int dir) -{ - io_debug("io_pause(%p, %x)\n", io, dir); - - io->flags |= dir & (IO_PAUSE_IN | IO_PAUSE_OUT); - io_reload(io); -} - -void -io_resume(struct io *io, int dir) -{ - io_debug("io_resume(%p, %x)\n", io, dir); - - io->flags &= ~(dir & (IO_PAUSE_IN | IO_PAUSE_OUT)); - io_reload(io); -} - -void -io_set_read(struct io *io) -{ - int mode; - - io_debug("io_set_read(%p)\n", io); - - mode = io->flags & IO_RW; - if (!(mode == 0 || mode == IO_WRITE)) - errx(1, "io_set_read(): full-duplex or reading"); - - io->flags &= ~IO_RW; - io->flags |= IO_READ; - io_reload(io); -} - -void -io_set_write(struct io *io) -{ - int mode; - - io_debug("io_set_write(%p)\n", io); - - mode = io->flags & IO_RW; - if (!(mode == 0 || mode == IO_READ)) - errx(1, "io_set_write(): full-duplex or writing"); - - io->flags &= ~IO_RW; - io->flags |= IO_WRITE; - io_reload(io); -} - -const char * -io_error(struct io *io) -{ - return io->error; -} - -void * -io_tls(struct io *io) -{ - return io->tls; -} - -int -io_fileno(struct io *io) -{ - return io->sock; -} - -int -io_paused(struct io *io, int what) -{ - return (io->flags & (IO_PAUSE_IN | IO_PAUSE_OUT)) == what; -} - -/* - * Buffered output functions - */ - -int -io_write(struct io *io, const void *buf, size_t len) -{ - int r; - - r = iobuf_queue(&io->iobuf, buf, len); - - io_reload(io); - - return r; -} - -int -io_writev(struct io *io, const struct iovec *iov, int iovcount) -{ - int r; - - r = iobuf_queuev(&io->iobuf, iov, iovcount); - - io_reload(io); - - return r; -} - -int -io_print(struct io *io, const char *s) -{ - return io_write(io, s, strlen(s)); -} - -int -io_printf(struct io *io, const char *fmt, ...) -{ - va_list ap; - int r; - - va_start(ap, fmt); - r = io_vprintf(io, fmt, ap); - va_end(ap); - - return r; -} - -int -io_vprintf(struct io *io, const char *fmt, va_list ap) -{ - - char *buf; - int len; - - len = vasprintf(&buf, fmt, ap); - if (len == -1) - return -1; - len = io_write(io, buf, len); - free(buf); - - return len; -} - -size_t -io_queued(struct io *io) -{ - return iobuf_queued(&io->iobuf); -} - -/* - * Buffered input functions - */ - -void * -io_data(struct io *io) -{ - return iobuf_data(&io->iobuf); -} - -size_t -io_datalen(struct io *io) -{ - return iobuf_len(&io->iobuf); -} - -char * -io_getline(struct io *io, size_t *sz) -{ - return iobuf_getline(&io->iobuf, sz); -} - -void -io_drop(struct io *io, size_t sz) -{ - return iobuf_drop(&io->iobuf, sz); -} - - -#define IO_READING(io) (((io)->flags & IO_RW) != IO_WRITE) -#define IO_WRITING(io) (((io)->flags & IO_RW) != IO_READ) - -/* - * Setup the necessary events as required by the current io state, - * honouring duplex mode and i/o pauses. - */ -void -io_reload(struct io *io) -{ - short events; - - /* io will be reloaded at release time */ - if (io->flags & IO_HELD) - return; - - iobuf_normalize(&io->iobuf); - -#ifdef IO_TLS - if (io->tls) { - io_reload_tls(io); - return; - } -#endif - - io_debug("io_reload(%p)\n", io); - - events = 0; - if (IO_READING(io) && !(io->flags & IO_PAUSE_IN)) - events = EV_READ; - if (IO_WRITING(io) && !(io->flags & IO_PAUSE_OUT) && io_queued(io)) - events |= EV_WRITE; - - io_reset(io, events, io_dispatch); -} - -/* Set the requested event. */ -void -io_reset(struct io *io, short events, void (*dispatch)(int, short, void*)) -{ - struct timeval tv, *ptv; - - io_debug("io_reset(%p, %s, %p) -> %s\n", - io, io_evstr(events), dispatch, io_strio(io)); - - /* - * Indicate that the event has already been reset so that reload - * is not called on frame_leave. - */ - io->flags |= IO_RESET; - - if (event_initialized(&io->ev)) - event_del(&io->ev); - - /* - * The io is paused by the user, so we don't want the timeout to be - * effective. - */ - if (events == 0) - return; - - event_set(&io->ev, io->sock, events, dispatch, io); - if (io->timeout >= 0) { - tv.tv_sec = io->timeout / 1000; - tv.tv_usec = (io->timeout % 1000) * 1000; - ptv = &tv; - } else - ptv = NULL; - - event_add(&io->ev, ptv); -} - -size_t -io_pending(struct io *io) -{ - return iobuf_len(&io->iobuf); -} - -const char* -io_strflags(int flags) -{ - static char buf[64]; - - buf[0] = '\0'; - - switch (flags & IO_RW) { - case 0: - (void)strlcat(buf, "rw", sizeof buf); - break; - case IO_READ: - (void)strlcat(buf, "R", sizeof buf); - break; - case IO_WRITE: - (void)strlcat(buf, "W", sizeof buf); - break; - case IO_RW: - (void)strlcat(buf, "RW", sizeof buf); - break; - } - - if (flags & IO_PAUSE_IN) - (void)strlcat(buf, ",F_PI", sizeof buf); - if (flags & IO_PAUSE_OUT) - (void)strlcat(buf, ",F_PO", sizeof buf); - - return buf; -} - -const char* -io_evstr(short ev) -{ - static char buf[64]; - char buf2[16]; - int n; - - n = 0; - buf[0] = '\0'; - - if (ev == 0) { - (void)strlcat(buf, "<NONE>", sizeof(buf)); - return buf; - } - - if (ev & EV_TIMEOUT) { - (void)strlcat(buf, "EV_TIMEOUT", sizeof(buf)); - ev &= ~EV_TIMEOUT; - n++; - } - - if (ev & EV_READ) { - if (n) - (void)strlcat(buf, "|", sizeof(buf)); - (void)strlcat(buf, "EV_READ", sizeof(buf)); - ev &= ~EV_READ; - n++; - } - - if (ev & EV_WRITE) { - if (n) - (void)strlcat(buf, "|", sizeof(buf)); - (void)strlcat(buf, "EV_WRITE", sizeof(buf)); - ev &= ~EV_WRITE; - n++; - } - - if (ev & EV_SIGNAL) { - if (n) - (void)strlcat(buf, "|", sizeof(buf)); - (void)strlcat(buf, "EV_SIGNAL", sizeof(buf)); - ev &= ~EV_SIGNAL; - n++; - } - - if (ev) { - if (n) - (void)strlcat(buf, "|", sizeof(buf)); - (void)strlcat(buf, "EV_?=0x", sizeof(buf)); - (void)snprintf(buf2, sizeof(buf2), "%hx", ev); - (void)strlcat(buf, buf2, sizeof(buf)); - } - - return buf; -} - -void -io_dispatch(int fd, short ev, void *humppa) -{ - struct io *io = humppa; - size_t w; - ssize_t n; - int saved_errno; - - io_frame_enter("io_dispatch", io, ev); - - if (ev == EV_TIMEOUT) { - io_callback(io, IO_TIMEOUT); - goto leave; - } - - if (ev & EV_WRITE && (w = io_queued(io))) { - if ((n = iobuf_write(&io->iobuf, io->sock)) < 0) { - if (n == IOBUF_WANT_WRITE) /* kqueue bug? */ - goto read; - if (n == IOBUF_CLOSED) - io_callback(io, IO_DISCONNECTED); - else { - saved_errno = errno; - io->error = strerror(errno); - errno = saved_errno; - io_callback(io, IO_ERROR); - } - goto leave; - } - if (w > io->lowat && w - n <= io->lowat) - io_callback(io, IO_LOWAT); - } - read: - - if (ev & EV_READ) { - iobuf_normalize(&io->iobuf); - if ((n = iobuf_read(&io->iobuf, io->sock)) < 0) { - if (n == IOBUF_CLOSED) - io_callback(io, IO_DISCONNECTED); - else { - saved_errno = errno; - io->error = strerror(errno); - errno = saved_errno; - io_callback(io, IO_ERROR); - } - goto leave; - } - if (n) - io_callback(io, IO_DATAIN); - } - -leave: - io_frame_leave(io); -} - -void -io_callback(struct io *io, int evt) -{ - io->cb(io, evt, io->arg); -} - -int -io_connect(struct io *io, const struct sockaddr *sa, const struct sockaddr *bsa) -{ - int sock, errno_save; - - if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) == -1) - goto fail; - - io_set_nonblocking(sock); - io_set_nolinger(sock); - - if (bsa && bind(sock, bsa, SA_LEN(bsa)) == -1) - goto fail; - - if (connect(sock, sa, SA_LEN(sa)) == -1) - if (errno != EINPROGRESS) - goto fail; - - io->sock = sock; - io_reset(io, EV_WRITE, io_dispatch_connect); - - return (sock); - - fail: - if (sock != -1) { - errno_save = errno; - close(sock); - errno = errno_save; - io->error = strerror(errno); - } - return (-1); -} - -void -io_dispatch_connect(int fd, short ev, void *humppa) -{ - struct io *io = humppa; - int r, e; - socklen_t sl; - - io_frame_enter("io_dispatch_connect", io, ev); - - if (ev == EV_TIMEOUT) { - close(fd); - io->sock = -1; - io_callback(io, IO_TIMEOUT); - } else { - sl = sizeof(e); - r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &e, &sl); - if (r == -1) { - warn("io_dispatch_connect: getsockopt"); - e = errno; - } - if (e) { - close(fd); - io->sock = -1; - io->error = strerror(e); - io_callback(io, e == ETIMEDOUT ? IO_TIMEOUT : IO_ERROR); - } - else { - io->state = IO_STATE_UP; - io_callback(io, IO_CONNECTED); - } - } - - io_frame_leave(io); -} - -#ifdef IO_TLS - -static const char* -io_tls_error(void) -{ - static char buf[128]; - unsigned long e; - - e = ERR_peek_last_error(); - if (e) { - ERR_error_string(e, buf); - return (buf); - } - - return ("No TLS error"); -} - -int -io_start_tls(struct io *io, void *tls) -{ - int mode; - - mode = io->flags & IO_RW; - if (mode == 0 || mode == IO_RW) - errx(1, "io_start_tls(): full-duplex or unset"); - - if (io->tls) - errx(1, "io_start_tls(): TLS already started"); - io->tls = tls; - - if (SSL_set_fd(io->tls, io->sock) == 0) { - ssl_error("io_start_tls:SSL_set_fd"); - return (-1); - } - - if (mode == IO_WRITE) { - io->state = IO_STATE_CONNECT_TLS; - SSL_set_connect_state(io->tls); - io_reset(io, EV_WRITE, io_dispatch_connect_tls); - } else { - io->state = IO_STATE_ACCEPT_TLS; - SSL_set_accept_state(io->tls); - io_reset(io, EV_READ, io_dispatch_accept_tls); - } - - return (0); -} - -void -io_dispatch_accept_tls(int fd, short event, void *humppa) -{ - struct io *io = humppa; - int e, ret; - - io_frame_enter("io_dispatch_accept_tls", io, event); - - if (event == EV_TIMEOUT) { - io_callback(io, IO_TIMEOUT); - goto leave; - } - - if ((ret = SSL_accept(io->tls)) > 0) { - io->state = IO_STATE_UP; - io_callback(io, IO_TLSREADY); - goto leave; - } - - switch ((e = SSL_get_error(io->tls, ret))) { - case SSL_ERROR_WANT_READ: - io_reset(io, EV_READ, io_dispatch_accept_tls); - break; - case SSL_ERROR_WANT_WRITE: - io_reset(io, EV_WRITE, io_dispatch_accept_tls); - break; - default: - io->error = io_tls_error(); - ssl_error("io_dispatch_accept_tls:SSL_accept"); - io_callback(io, IO_ERROR); - break; - } - - leave: - io_frame_leave(io); -} - -void -io_dispatch_connect_tls(int fd, short event, void *humppa) -{ - struct io *io = humppa; - int e, ret; - - io_frame_enter("io_dispatch_connect_tls", io, event); - - if (event == EV_TIMEOUT) { - io_callback(io, IO_TIMEOUT); - goto leave; - } - - if ((ret = SSL_connect(io->tls)) > 0) { - io->state = IO_STATE_UP; - io_callback(io, IO_TLSREADY); - goto leave; - } - - switch ((e = SSL_get_error(io->tls, ret))) { - case SSL_ERROR_WANT_READ: - io_reset(io, EV_READ, io_dispatch_connect_tls); - break; - case SSL_ERROR_WANT_WRITE: - io_reset(io, EV_WRITE, io_dispatch_connect_tls); - break; - default: - io->error = io_tls_error(); - ssl_error("io_dispatch_connect_ssl:SSL_connect"); - io_callback(io, IO_TLSERROR); - break; - } - - leave: - io_frame_leave(io); -} - -void -io_dispatch_read_tls(int fd, short event, void *humppa) -{ - struct io *io = humppa; - int n, saved_errno; - - io_frame_enter("io_dispatch_read_tls", io, event); - - if (event == EV_TIMEOUT) { - io_callback(io, IO_TIMEOUT); - goto leave; - } - -again: - iobuf_normalize(&io->iobuf); - switch ((n = iobuf_read_tls(&io->iobuf, (SSL*)io->tls))) { - case IOBUF_WANT_READ: - io_reset(io, EV_READ, io_dispatch_read_tls); - break; - case IOBUF_WANT_WRITE: - io_reset(io, EV_WRITE, io_dispatch_read_tls); - break; - case IOBUF_CLOSED: - io_callback(io, IO_DISCONNECTED); - break; - case IOBUF_ERROR: - saved_errno = errno; - io->error = strerror(errno); - errno = saved_errno; - io_callback(io, IO_ERROR); - break; - case IOBUF_TLSERROR: - io->error = io_tls_error(); - ssl_error("io_dispatch_read_tls:SSL_read"); - io_callback(io, IO_ERROR); - break; - default: - io_debug("io_dispatch_read_tls(...) -> r=%d\n", n); - io_callback(io, IO_DATAIN); - if (current == io && IO_READING(io) && SSL_pending(io->tls)) - goto again; - } - - leave: - io_frame_leave(io); -} - -void -io_dispatch_write_tls(int fd, short event, void *humppa) -{ - struct io *io = humppa; - int n, saved_errno; - size_t w2, w; - - io_frame_enter("io_dispatch_write_tls", io, event); - - if (event == EV_TIMEOUT) { - io_callback(io, IO_TIMEOUT); - goto leave; - } - - w = io_queued(io); - switch ((n = iobuf_write_tls(&io->iobuf, (SSL*)io->tls))) { - case IOBUF_WANT_READ: - io_reset(io, EV_READ, io_dispatch_write_tls); - break; - case IOBUF_WANT_WRITE: - io_reset(io, EV_WRITE, io_dispatch_write_tls); - break; - case IOBUF_CLOSED: - io_callback(io, IO_DISCONNECTED); - break; - case IOBUF_ERROR: - saved_errno = errno; - io->error = strerror(errno); - errno = saved_errno; - io_callback(io, IO_ERROR); - break; - case IOBUF_TLSERROR: - io->error = io_tls_error(); - ssl_error("io_dispatch_write_tls:SSL_write"); - io_callback(io, IO_ERROR); - break; - default: - io_debug("io_dispatch_write_tls(...) -> w=%d\n", n); - w2 = io_queued(io); - if (w > io->lowat && w2 <= io->lowat) - io_callback(io, IO_LOWAT); - break; - } - - leave: - io_frame_leave(io); -} - -void -io_reload_tls(struct io *io) -{ - short ev = 0; - void (*dispatch)(int, short, void*) = NULL; - - switch (io->state) { - case IO_STATE_CONNECT_TLS: - ev = EV_WRITE; - dispatch = io_dispatch_connect_tls; - break; - case IO_STATE_ACCEPT_TLS: - ev = EV_READ; - dispatch = io_dispatch_accept_tls; - break; - case IO_STATE_UP: - ev = 0; - if (IO_READING(io) && !(io->flags & IO_PAUSE_IN)) { - ev = EV_READ; - dispatch = io_dispatch_read_tls; - } - else if (IO_WRITING(io) && !(io->flags & IO_PAUSE_OUT) && - io_queued(io)) { - ev = EV_WRITE; - dispatch = io_dispatch_write_tls; - } - if (!ev) - return; /* paused */ - break; - default: - errx(1, "io_reload_tls(): bad state"); - } - - io_reset(io, ev, dispatch); -} - -#endif /* IO_TLS */ |