There is actually no reason to defer calls to tls_accept_socket() and tls_connect_socket() in an event callback. The code can be simplified by a great deal. It also eliminates the issue of keeping a reference to the listener tls context in the io structure.
Eric. Index: ioev.c =================================================================== RCS file: /cvs/src/usr.sbin/smtpd/ioev.c,v retrieving revision 1.45 diff -u -p -r1.45 ioev.c --- ioev.c 5 Apr 2021 15:50:11 -0000 1.45 +++ ioev.c 21 Apr 2021 08:35:29 -0000 @@ -64,7 +64,6 @@ struct io { int state; struct event ev; struct tls *tls; - char *name; const char *error; /* only valid immediately on callback */ }; @@ -280,7 +279,6 @@ io_free(struct io *io) io->sock = -1; } - free(io->name); iobuf_clear(&io->iobuf); free(io); } @@ -817,14 +815,14 @@ io_connect_tls(struct io *io, struct tls if (io->tls) errx(1, "io_connect_tls: TLS already started"); - if (hostname) { - if ((io->name = strdup(hostname)) == NULL) - err(1, "io_connect_tls"); + if (tls_connect_socket(tls, io->sock, hostname) == -1) { + io->error = tls_error(tls); + return (-1); } io->tls = tls; io->state = IO_STATE_CONNECT_TLS; - io_reset(io, EV_WRITE, io_dispatch_connect_tls); + io_reset(io, EV_READ|EV_WRITE, io_dispatch_handshake_tls); return (0); } @@ -840,9 +838,14 @@ io_accept_tls(struct io *io, struct tls if (io->tls) errx(1, "io_accept_tls: TLS already started"); - io->tls = tls; + + if (tls_accept_socket(tls, &io->tls, io->sock) == -1) { + io->error = tls_error(tls); + return (-1); + } + io->state = IO_STATE_ACCEPT_TLS; - io_reset(io, EV_READ, io_dispatch_accept_tls); + io_reset(io, EV_READ|EV_WRITE, io_dispatch_handshake_tls); return (0); } @@ -880,60 +883,6 @@ io_dispatch_handshake_tls(int fd, short } void -io_dispatch_accept_tls(int fd, short event, void *humppa) -{ - struct io *io = humppa; - struct tls *tls = io->tls; - int ret; - - io_frame_enter("io_dispatch_accept_tls", io, event); - - /* Replaced by TLS context for accepted socket on success. */ - io->tls = NULL; - - if (event == EV_TIMEOUT) { - io_callback(io, IO_TIMEOUT); - goto leave; - } - - if ((ret = tls_accept_socket(tls, &io->tls, io->sock)) == 0) { - io_reset(io, EV_READ|EV_WRITE, io_dispatch_handshake_tls); - goto leave; - } - io->error = tls_error(tls); - io_callback(io, IO_ERROR); - - leave: - io_frame_leave(io); - return; -} - -void -io_dispatch_connect_tls(int fd, short event, void *humppa) -{ - struct io *io = humppa; - int ret; - - io_frame_enter("io_dispatch_connect_tls", io, event); - - if (event == EV_TIMEOUT) { - io_callback(io, IO_TIMEOUT); - goto leave; - } - - if ((ret = tls_connect_socket(io->tls, io->sock, io->name)) == 0) { - io_reset(io, EV_READ|EV_WRITE, io_dispatch_handshake_tls); - goto leave; - } - - io->error = tls_error(io->tls); - io_callback(io, IO_ERROR); - - leave: - io_frame_leave(io); -} - -void io_dispatch_read_tls(int fd, short event, void *humppa) { struct io *io = humppa; @@ -1017,37 +966,20 @@ io_dispatch_write_tls(int fd, short even 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: + if (io->state != IO_STATE_UP) errx(1, "io_reload_tls: bad state"); + + if (IO_READING(io) && !(io->flags & IO_PAUSE_IN)) { + io_reset(io, EV_READ, io_dispatch_read_tls); + return; + } + + if (IO_WRITING(io) && !(io->flags & IO_PAUSE_OUT) && io_queued(io)) { + io_reset(io, EV_WRITE, io_dispatch_write_tls); + return; } - io_reset(io, ev, dispatch); + /* paused */ } #endif /* IO_TLS */ Index: mta_session.c =================================================================== RCS file: /cvs/src/usr.sbin/smtpd/mta_session.c,v retrieving revision 1.140 diff -u -p -r1.140 mta_session.c --- mta_session.c 7 Mar 2021 20:56:41 -0000 1.140 +++ mta_session.c 21 Apr 2021 08:18:56 -0000 @@ -1596,7 +1596,11 @@ mta_tls_init(struct mta_session *s) return; } - io_connect_tls(s->io, tls, s->mxname); + if (io_connect_tls(s->io, tls, s->mxname) == -1) { + log_info("%016"PRIx64" mta closing reason=tls-connect-failed", s->id); + tls_free(tls); + mta_free(s); + } } static void Index: smtp_session.c =================================================================== RCS file: /cvs/src/usr.sbin/smtpd/smtp_session.c,v retrieving revision 1.429 diff -u -p -r1.429 smtp_session.c --- smtp_session.c 5 Mar 2021 12:37:32 -0000 1.429 +++ smtp_session.c 21 Apr 2021 08:20:44 -0000 @@ -1067,7 +1067,12 @@ static void smtp_tls_init(struct smtp_session *s) { io_set_read(s->io); - io_accept_tls(s->io, s->listener->tls); + if (io_accept_tls(s->io, s->listener->tls) == -1) { + log_info("%016"PRIx64" smtp disconnected " + "reason=tls-accept-failed", + s->id); + smtp_free(s, "accept failed"); + } } static void