xref: /openbsd-src/usr.sbin/smtpd/ioev.c (revision c57f8f28d76ce9cf9f59a0e970a9845793fc7af4)
1*c57f8f28Seric /*	$OpenBSD: ioev.c,v 1.32 2016/11/24 07:57:48 eric Exp $	*/
2d1ece852Seric /*
3d1ece852Seric  * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
4d1ece852Seric  *
5d1ece852Seric  * Permission to use, copy, modify, and distribute this software for any
6d1ece852Seric  * purpose with or without fee is hereby granted, provided that the above
7d1ece852Seric  * copyright notice and this permission notice appear in all copies.
8d1ece852Seric  *
9d1ece852Seric  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10d1ece852Seric  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11d1ece852Seric  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12d1ece852Seric  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13d1ece852Seric  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14d1ece852Seric  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15d1ece852Seric  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16d1ece852Seric  */
17d1ece852Seric 
18299c4efeSeric #include <sys/types.h>
19d1ece852Seric #include <sys/queue.h>
20d1ece852Seric #include <sys/socket.h>
21d1ece852Seric 
22d1ece852Seric #include <err.h>
23d1ece852Seric #include <errno.h>
24d1ece852Seric #include <fcntl.h>
250e63ed3bSchl #include <inttypes.h>
26d1ece852Seric #include <stdlib.h>
27d1ece852Seric #include <string.h>
28d1ece852Seric #include <stdio.h>
29d1ece852Seric #include <unistd.h>
30d1ece852Seric 
31d1ece852Seric #include "ioev.h"
32d1ece852Seric #include "iobuf.h"
33d1ece852Seric 
34d1ece852Seric #ifdef IO_SSL
3565c4fdfbSgilles #include <openssl/err.h>
36d1ece852Seric #include <openssl/ssl.h>
37d1ece852Seric #endif
38d1ece852Seric 
39d1ece852Seric enum {
40d1ece852Seric 	IO_STATE_NONE,
41d1ece852Seric 	IO_STATE_CONNECT,
42d1ece852Seric 	IO_STATE_CONNECT_SSL,
43d1ece852Seric 	IO_STATE_ACCEPT_SSL,
44d1ece852Seric 	IO_STATE_UP,
45d1ece852Seric 
46d1ece852Seric 	IO_STATE_MAX,
47d1ece852Seric };
48d1ece852Seric 
49d1ece852Seric const char* io_strflags(int);
50d1ece852Seric const char* io_evstr(short);
51d1ece852Seric 
52d1ece852Seric void	_io_init(void);
53d1ece852Seric void	io_hold(struct io *);
54d1ece852Seric void	io_release(struct io *);
55d1ece852Seric void	io_callback(struct io*, int);
56d1ece852Seric void	io_dispatch(int, short, void *);
57d1ece852Seric void	io_dispatch_connect(int, short, void *);
58d1ece852Seric size_t	io_pending(struct io *);
59d1ece852Seric size_t	io_queued(struct io*);
60d1ece852Seric void	io_reset(struct io *, short, void (*)(int, short, void*));
61d1ece852Seric void	io_frame_enter(const char *, struct io *, int);
62d1ece852Seric void	io_frame_leave(struct io *);
63d1ece852Seric 
64d1ece852Seric #ifdef IO_SSL
65d1ece852Seric void	ssl_error(const char *); /* XXX external */
66d1ece852Seric 
6765c4fdfbSgilles static const char* io_ssl_error(void);
68d1ece852Seric void	io_dispatch_accept_ssl(int, short, void *);
69d1ece852Seric void	io_dispatch_connect_ssl(int, short, void *);
70d1ece852Seric void	io_dispatch_read_ssl(int, short, void *);
71d1ece852Seric void	io_dispatch_write_ssl(int, short, void *);
72d1ece852Seric void	io_reload_ssl(struct io *io);
73d1ece852Seric #endif
74d1ece852Seric 
75d1ece852Seric static struct io	*current = NULL;
76d1ece852Seric static uint64_t		 frame = 0;
77d1ece852Seric static int		_io_debug = 0;
78d1ece852Seric 
79d1ece852Seric #define io_debug(args...) do { if (_io_debug) printf(args); } while(0)
80d1ece852Seric 
81d1ece852Seric 
82d1ece852Seric const char*
83d1ece852Seric io_strio(struct io *io)
84d1ece852Seric {
85d1ece852Seric 	static char	buf[128];
8605a218a6Seric 	char		ssl[128];
87d1ece852Seric 
8805a218a6Seric 	ssl[0] = '\0';
8905a218a6Seric #ifdef IO_SSL
9005a218a6Seric 	if (io->ssl) {
91fd77dd20Sgilles 		(void)snprintf(ssl, sizeof ssl, " ssl=%s:%s:%d",
92860088dfSsthen 		    SSL_get_version(io->ssl),
9305a218a6Seric 		    SSL_get_cipher_name(io->ssl),
9405a218a6Seric 		    SSL_get_cipher_bits(io->ssl, NULL));
9505a218a6Seric 	}
9605a218a6Seric #endif
9705a218a6Seric 
9805a218a6Seric 	if (io->iobuf == NULL)
99fd77dd20Sgilles 		(void)snprintf(buf, sizeof buf,
100d7bcae4dSeric 		    "<io:%p fd=%d to=%d fl=%s%s>",
10105a218a6Seric 		    io, io->sock, io->timeout, io_strflags(io->flags), ssl);
10205a218a6Seric 	else
103fd77dd20Sgilles 		(void)snprintf(buf, sizeof buf,
104d7bcae4dSeric 		    "<io:%p fd=%d to=%d fl=%s%s ib=%zu ob=%zu>",
10505a218a6Seric 		    io, io->sock, io->timeout, io_strflags(io->flags), ssl,
106d1ece852Seric 		    io_pending(io), io_queued(io));
10705a218a6Seric 
108d1ece852Seric 	return (buf);
109d1ece852Seric }
110d1ece852Seric 
111d1ece852Seric #define CASE(x) case x : return #x
112d1ece852Seric 
113d1ece852Seric const char*
114d1ece852Seric io_strevent(int evt)
115d1ece852Seric {
116d1ece852Seric 	static char buf[32];
117d1ece852Seric 
118d1ece852Seric 	switch (evt) {
119d1ece852Seric 	CASE(IO_CONNECTED);
120d1ece852Seric 	CASE(IO_TLSREADY);
121d1ece852Seric 	CASE(IO_DATAIN);
122d1ece852Seric 	CASE(IO_LOWAT);
123d1ece852Seric 	CASE(IO_DISCONNECTED);
124d1ece852Seric 	CASE(IO_TIMEOUT);
125d1ece852Seric 	CASE(IO_ERROR);
126d1ece852Seric 	default:
127fd77dd20Sgilles 		(void)snprintf(buf, sizeof(buf), "IO_? %d", evt);
128d1ece852Seric 		return buf;
129d1ece852Seric 	}
130d1ece852Seric }
131d1ece852Seric 
132d1ece852Seric void
133907c4b99Skrw io_set_nonblocking(int fd)
134d1ece852Seric {
135d1ece852Seric 	int	flags;
136d1ece852Seric 
137907c4b99Skrw 	if ((flags = fcntl(fd, F_GETFL)) == -1)
138d1ece852Seric 		err(1, "io_set_blocking:fcntl(F_GETFL)");
139d1ece852Seric 
140d1ece852Seric 	flags |= O_NONBLOCK;
141d1ece852Seric 
14232e1408cSmillert 	if (fcntl(fd, F_SETFL, flags) == -1)
143d1ece852Seric 		err(1, "io_set_blocking:fcntl(F_SETFL)");
144d1ece852Seric }
145d1ece852Seric 
146d1ece852Seric void
147907c4b99Skrw io_set_nolinger(int fd)
148d1ece852Seric {
149d1ece852Seric 	struct linger    l;
150d1ece852Seric 
151c1392a69Seric 	memset(&l, 0, sizeof(l));
152d1ece852Seric 	if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) == -1)
153d1ece852Seric 		err(1, "io_set_linger:setsockopt()");
154d1ece852Seric }
155d1ece852Seric 
156d1ece852Seric /*
157d1ece852Seric  * Event framing must not rely on an io pointer to refer to the "same" io
158af0dba2aSsobrado  * throughout the frame, because this is not always the case:
159d1ece852Seric  *
160d1ece852Seric  * 1) enter(addr0) -> free(addr0) -> leave(addr0) = SEGV
161d1ece852Seric  * 2) enter(addr0) -> free(addr0) -> malloc == addr0 -> leave(addr0) = BAD!
162d1ece852Seric  *
163d1ece852Seric  * In both case, the problem is that the io is freed in the callback, so
164d1ece852Seric  * the pointer becomes invalid. If that happens, the user is required to
165d1ece852Seric  * call io_clear, so we can adapt the frame state there.
166d1ece852Seric  */
167d1ece852Seric void
168d1ece852Seric io_frame_enter(const char *where, struct io *io, int ev)
169d1ece852Seric {
170d1ece852Seric 	io_debug("\n=== %" PRIu64 " ===\n"
171d1ece852Seric 	    "io_frame_enter(%s, %s, %s)\n",
172d1ece852Seric 	    frame, where, io_evstr(ev), io_strio(io));
173d1ece852Seric 
174d1ece852Seric 	if (current)
175d1ece852Seric 		errx(1, "io_frame_enter: interleaved frames");
176d1ece852Seric 
177d1ece852Seric 	current = io;
178d1ece852Seric 
179d1ece852Seric 	io_hold(io);
180d1ece852Seric }
181d1ece852Seric 
182d1ece852Seric void
183d1ece852Seric io_frame_leave(struct io *io)
184d1ece852Seric {
185d1ece852Seric 	io_debug("io_frame_leave(%" PRIu64 ")\n", frame);
186d1ece852Seric 
187d1ece852Seric 	if (current && current != io)
188d1ece852Seric 		errx(1, "io_frame_leave: io mismatch");
189d1ece852Seric 
190d1ece852Seric 	/* io has been cleared */
191d1ece852Seric 	if (current == NULL)
192d1ece852Seric 		goto done;
193d1ece852Seric 
194d1ece852Seric 	/* TODO: There is a possible optimization there:
195d1ece852Seric 	 * In a typical half-duplex request/response scenario,
196d1ece852Seric 	 * the io is waiting to read a request, and when done, it queues
197d1ece852Seric 	 * the response in the output buffer and goes to write mode.
198d1ece852Seric 	 * There, the write event is set and will be triggered in the next
199d1ece852Seric 	 * event frame.  In most case, the write call could be done
200af0dba2aSsobrado 	 * immediately as part of the last read frame, thus avoiding to go
201d1ece852Seric 	 * through the event loop machinery. So, as an optimisation, we
202d1ece852Seric 	 * could detect that case here and force an event dispatching.
203d1ece852Seric 	 */
204d1ece852Seric 
205d1ece852Seric 	/* Reload the io if it has not been reset already. */
206d1ece852Seric 	io_release(io);
207d1ece852Seric 	current = NULL;
208d1ece852Seric     done:
209d1ece852Seric 	io_debug("=== /%" PRIu64 "\n", frame);
210d1ece852Seric 
211d1ece852Seric 	frame += 1;
212d1ece852Seric }
213d1ece852Seric 
214d1ece852Seric void
215d1ece852Seric _io_init()
216d1ece852Seric {
217d1ece852Seric 	static int init = 0;
218d1ece852Seric 
219d1ece852Seric 	if (init)
220d1ece852Seric 		return;
221d1ece852Seric 
222d1ece852Seric 	init = 1;
223d1ece852Seric 	_io_debug = getenv("IO_DEBUG") != NULL;
224d1ece852Seric }
225d1ece852Seric 
226d1ece852Seric void
227f81b996bSeric io_init(struct io *io, struct iobuf *iobuf)
228d1ece852Seric {
229d1ece852Seric 	_io_init();
230d1ece852Seric 
231d1ece852Seric 	memset(io, 0, sizeof *io);
232d1ece852Seric 
233f81b996bSeric 	io->sock = -1;
234d1ece852Seric 	io->timeout = -1;
235d1ece852Seric 	io->iobuf = iobuf;
236d1ece852Seric }
237d1ece852Seric 
238d1ece852Seric void
239d1ece852Seric io_clear(struct io *io)
240d1ece852Seric {
241d1ece852Seric 	io_debug("io_clear(%p)\n", io);
242d1ece852Seric 
243d1ece852Seric 	/* the current io is virtually dead */
244d1ece852Seric 	if (io == current)
245d1ece852Seric 		current = NULL;
246d1ece852Seric 
247d1ece852Seric #ifdef IO_SSL
248d1ece852Seric 	if (io->ssl) {
249d1ece852Seric 		SSL_free(io->ssl);
250d1ece852Seric 		io->ssl = NULL;
251d1ece852Seric 	}
252d1ece852Seric #endif
253d1ece852Seric 
2549ad25316Seric 	if (event_initialized(&io->ev))
255d1ece852Seric 		event_del(&io->ev);
256d1ece852Seric 	if (io->sock != -1) {
257d1ece852Seric 		close(io->sock);
258d1ece852Seric 		io->sock = -1;
259d1ece852Seric 	}
260d1ece852Seric }
261d1ece852Seric 
262d1ece852Seric void
263d1ece852Seric io_hold(struct io *io)
264d1ece852Seric {
265d1ece852Seric 	io_debug("io_enter(%p)\n", io);
266d1ece852Seric 
267d1ece852Seric 	if (io->flags & IO_HELD)
268d1ece852Seric 		errx(1, "io_hold: io is already held");
269d1ece852Seric 
270d1ece852Seric 	io->flags &= ~IO_RESET;
271d1ece852Seric 	io->flags |= IO_HELD;
272d1ece852Seric }
273d1ece852Seric 
274d1ece852Seric void
275d1ece852Seric io_release(struct io *io)
276d1ece852Seric {
277d1ece852Seric 	if (!(io->flags & IO_HELD))
278d1ece852Seric 		errx(1, "io_release: io is not held");
279d1ece852Seric 
280d1ece852Seric 	io->flags &= ~IO_HELD;
281d1ece852Seric 	if (!(io->flags & IO_RESET))
282d1ece852Seric 		io_reload(io);
283d1ece852Seric }
284d1ece852Seric 
285d1ece852Seric void
286f81b996bSeric io_set_fd(struct io *io, int fd)
287f81b996bSeric {
288f81b996bSeric 	io->sock = fd;
289f81b996bSeric 	if (fd != -1)
290f81b996bSeric 		io_reload(io);
291f81b996bSeric }
292f81b996bSeric 
293f81b996bSeric void
294f81b996bSeric io_set_callback(struct io *io, void(*cb)(struct io *, int, void *), void *arg)
295f81b996bSeric {
296f81b996bSeric 	io->cb = cb;
297f81b996bSeric 	io->arg = arg;
298f81b996bSeric }
299f81b996bSeric 
300f81b996bSeric void
301d1ece852Seric io_set_timeout(struct io *io, int msec)
302d1ece852Seric {
303d7bcae4dSeric 	io_debug("io_set_timeout(%p, %d)\n", io, msec);
304d1ece852Seric 
305d1ece852Seric 	io->timeout = msec;
306d1ece852Seric }
307d1ece852Seric 
308d1ece852Seric void
309d1ece852Seric io_set_lowat(struct io *io, size_t lowat)
310d1ece852Seric {
311d1ece852Seric 	io_debug("io_set_lowat(%p, %zu)\n", io, lowat);
312d1ece852Seric 
313d1ece852Seric 	io->lowat = lowat;
314d1ece852Seric }
315d1ece852Seric 
316d1ece852Seric void
317d1ece852Seric io_pause(struct io *io, int dir)
318d1ece852Seric {
319d1ece852Seric 	io_debug("io_pause(%p, %x)\n", io, dir);
320d1ece852Seric 
321d1ece852Seric 	io->flags |= dir & (IO_PAUSE_IN | IO_PAUSE_OUT);
322d1ece852Seric 	io_reload(io);
323d1ece852Seric }
324d1ece852Seric 
325d1ece852Seric void
326d1ece852Seric io_resume(struct io *io, int dir)
327d1ece852Seric {
328d1ece852Seric 	io_debug("io_resume(%p, %x)\n", io, dir);
329d1ece852Seric 
330d1ece852Seric 	io->flags &= ~(dir & (IO_PAUSE_IN | IO_PAUSE_OUT));
331d1ece852Seric 	io_reload(io);
332d1ece852Seric }
333d1ece852Seric 
334d1ece852Seric void
335d1ece852Seric io_set_read(struct io *io)
336d1ece852Seric {
337d1ece852Seric 	int	mode;
338d1ece852Seric 
339d1ece852Seric 	io_debug("io_set_read(%p)\n", io);
340d1ece852Seric 
341d1ece852Seric 	mode = io->flags & IO_RW;
342d1ece852Seric 	if (!(mode == 0 || mode == IO_WRITE))
343d1ece852Seric 		errx(1, "io_set_read(): full-duplex or reading");
344d1ece852Seric 
345d1ece852Seric 	io->flags &= ~IO_RW;
346d1ece852Seric 	io->flags |= IO_READ;
347d1ece852Seric 	io_reload(io);
348d1ece852Seric }
349d1ece852Seric 
350d1ece852Seric void
351d1ece852Seric io_set_write(struct io *io)
352d1ece852Seric {
353d1ece852Seric 	int	mode;
354d1ece852Seric 
355d1ece852Seric 	io_debug("io_set_write(%p)\n", io);
356d1ece852Seric 
357d1ece852Seric 	mode = io->flags & IO_RW;
358d1ece852Seric 	if (!(mode == 0 || mode == IO_READ))
359d1ece852Seric 		errx(1, "io_set_write(): full-duplex or writing");
360d1ece852Seric 
361d1ece852Seric 	io->flags &= ~IO_RW;
362d1ece852Seric 	io->flags |= IO_WRITE;
363d1ece852Seric 	io_reload(io);
364d1ece852Seric }
365d1ece852Seric 
36666802da1Seric /*
36766802da1Seric  * Buffered output functions
36866802da1Seric  */
36966802da1Seric 
37066802da1Seric int
37166802da1Seric io_write(struct io *io, const void *buf, size_t len)
37266802da1Seric {
373*c57f8f28Seric 	int r;
374*c57f8f28Seric 
375*c57f8f28Seric 	r = iobuf_queue(io->iobuf, buf, len);
376*c57f8f28Seric 
377*c57f8f28Seric 	io_reload(io);
378*c57f8f28Seric 
379*c57f8f28Seric 	return r;
38066802da1Seric }
38166802da1Seric 
38266802da1Seric int
38366802da1Seric io_writev(struct io *io, const struct iovec *iov, int iovcount)
38466802da1Seric {
385*c57f8f28Seric 	int r;
386*c57f8f28Seric 
387*c57f8f28Seric 	r = iobuf_queuev(io->iobuf, iov, iovcount);
388*c57f8f28Seric 
389*c57f8f28Seric 	io_reload(io);
390*c57f8f28Seric 
391*c57f8f28Seric 	return r;
39266802da1Seric }
39366802da1Seric 
39466802da1Seric int
39566802da1Seric io_print(struct io *io, const char *s)
39666802da1Seric {
39766802da1Seric 	return io_write(io, s, strlen(s));
39866802da1Seric }
39966802da1Seric 
40066802da1Seric int
40166802da1Seric io_printf(struct io *io, const char *fmt, ...)
40266802da1Seric {
40366802da1Seric 	va_list ap;
40466802da1Seric 	int r;
40566802da1Seric 
40666802da1Seric 	va_start(ap, fmt);
40766802da1Seric 	r = io_vprintf(io, fmt, ap);
40866802da1Seric 	va_end(ap);
40966802da1Seric 
41066802da1Seric 	return r;
41166802da1Seric }
41266802da1Seric 
41366802da1Seric int
41466802da1Seric io_vprintf(struct io *io, const char *fmt, va_list ap)
41566802da1Seric {
41666802da1Seric 
41766802da1Seric 	char *buf;
41866802da1Seric 	int len;
41966802da1Seric 
42066802da1Seric 	len = vasprintf(&buf, fmt, ap);
42166802da1Seric 	if (len == -1)
42266802da1Seric 		return -1;
42366802da1Seric 	len = io_write(io, buf, len);
42466802da1Seric 	free(buf);
42566802da1Seric 
42666802da1Seric 	return len;
42766802da1Seric }
42866802da1Seric 
42966802da1Seric size_t
43066802da1Seric io_queued(struct io *io)
43166802da1Seric {
43266802da1Seric 	return iobuf_queued(io->iobuf);
43366802da1Seric }
43466802da1Seric 
43566802da1Seric /*
43666802da1Seric  * Buffered input functions
43766802da1Seric  */
43866802da1Seric 
43966802da1Seric void *
44066802da1Seric io_data(struct io *io)
44166802da1Seric {
44266802da1Seric 	return iobuf_data(io->iobuf);
44366802da1Seric }
44466802da1Seric 
44566802da1Seric size_t
44666802da1Seric io_datalen(struct io *io)
44766802da1Seric {
44866802da1Seric 	return iobuf_len(io->iobuf);
44966802da1Seric }
45066802da1Seric 
45166802da1Seric char *
45266802da1Seric io_getline(struct io *io, size_t *sz)
45366802da1Seric {
45466802da1Seric 	return iobuf_getline(io->iobuf, sz);
45566802da1Seric }
45666802da1Seric 
45766802da1Seric void
45866802da1Seric io_drop(struct io *io, size_t sz)
45966802da1Seric {
46066802da1Seric 	return iobuf_drop(io->iobuf, sz);
46166802da1Seric }
46266802da1Seric 
46366802da1Seric 
464d1ece852Seric #define IO_READING(io) (((io)->flags & IO_RW) != IO_WRITE)
465d1ece852Seric #define IO_WRITING(io) (((io)->flags & IO_RW) != IO_READ)
466d1ece852Seric 
467d1ece852Seric /*
468d1ece852Seric  * Setup the necessary events as required by the current io state,
469d1ece852Seric  * honouring duplex mode and i/o pauses.
470d1ece852Seric  */
471d1ece852Seric void
472d1ece852Seric io_reload(struct io *io)
473d1ece852Seric {
474d1ece852Seric 	short	events;
475d1ece852Seric 
476d1ece852Seric 	/* io will be reloaded at release time */
477d1ece852Seric 	if (io->flags & IO_HELD)
478d1ece852Seric 		return;
479d1ece852Seric 
4800e198904Seric 	if (io->iobuf)
4810e198904Seric 		iobuf_normalize(io->iobuf);
4820e198904Seric 
483d1ece852Seric #ifdef IO_SSL
484d1ece852Seric 	if (io->ssl) {
485d1ece852Seric 		io_reload_ssl(io);
486d1ece852Seric 		return;
487d1ece852Seric 	}
488d1ece852Seric #endif
489d1ece852Seric 
490d1ece852Seric 	io_debug("io_reload(%p)\n", io);
491d1ece852Seric 
492d1ece852Seric 	events = 0;
493d1ece852Seric 	if (IO_READING(io) && !(io->flags & IO_PAUSE_IN))
494d1ece852Seric 		events = EV_READ;
495d1ece852Seric 	if (IO_WRITING(io) && !(io->flags & IO_PAUSE_OUT) && io_queued(io))
496d1ece852Seric 		events |= EV_WRITE;
497d1ece852Seric 
498d1ece852Seric 	io_reset(io, events, io_dispatch);
499d1ece852Seric }
500d1ece852Seric 
501d1ece852Seric /* Set the requested event. */
502d1ece852Seric void
503d1ece852Seric io_reset(struct io *io, short events, void (*dispatch)(int, short, void*))
504d1ece852Seric {
505d1ece852Seric 	struct timeval	tv, *ptv;
506d1ece852Seric 
507d1ece852Seric 	io_debug("io_reset(%p, %s, %p) -> %s\n",
508d1ece852Seric 	    io, io_evstr(events), dispatch, io_strio(io));
509d1ece852Seric 
510d1ece852Seric 	/*
511d1ece852Seric 	 * Indicate that the event has already been reset so that reload
512d1ece852Seric 	 * is not called on frame_leave.
513d1ece852Seric 	 */
514d1ece852Seric 	io->flags |= IO_RESET;
515d1ece852Seric 
5169ad25316Seric 	if (event_initialized(&io->ev))
517d1ece852Seric 		event_del(&io->ev);
518d1ece852Seric 
519d1ece852Seric 	/*
520d1ece852Seric 	 * The io is paused by the user, so we don't want the timeout to be
521d1ece852Seric 	 * effective.
522d1ece852Seric 	 */
523d1ece852Seric 	if (events == 0)
524d1ece852Seric 		return;
525d1ece852Seric 
526d1ece852Seric 	event_set(&io->ev, io->sock, events, dispatch, io);
527d1ece852Seric 	if (io->timeout >= 0) {
528d1ece852Seric 		tv.tv_sec = io->timeout / 1000;
529d1ece852Seric 		tv.tv_usec = (io->timeout % 1000) * 1000;
530d1ece852Seric 		ptv = &tv;
531d1ece852Seric 	} else
532d1ece852Seric 		ptv = NULL;
533d1ece852Seric 
534d1ece852Seric 	event_add(&io->ev, ptv);
535d1ece852Seric }
536d1ece852Seric 
537d1ece852Seric size_t
538d1ece852Seric io_pending(struct io *io)
539d1ece852Seric {
540d1ece852Seric 	return iobuf_len(io->iobuf);
541d1ece852Seric }
542d1ece852Seric 
543d1ece852Seric const char*
544d1ece852Seric io_strflags(int flags)
545d1ece852Seric {
546d1ece852Seric 	static char	buf[64];
547d1ece852Seric 
548d1ece852Seric 	buf[0] = '\0';
549d1ece852Seric 
550d1ece852Seric 	switch (flags & IO_RW) {
551d1ece852Seric 	case 0:
552eb54aa8aSgilles 		(void)strlcat(buf, "rw", sizeof buf);
553d1ece852Seric 		break;
554d1ece852Seric 	case IO_READ:
555eb54aa8aSgilles 		(void)strlcat(buf, "R", sizeof buf);
556d1ece852Seric 		break;
557d1ece852Seric 	case IO_WRITE:
558eb54aa8aSgilles 		(void)strlcat(buf, "W", sizeof buf);
559d1ece852Seric 		break;
560d1ece852Seric 	case IO_RW:
561eb54aa8aSgilles 		(void)strlcat(buf, "RW", sizeof buf);
562d1ece852Seric 		break;
563d1ece852Seric 	}
564d1ece852Seric 
565d1ece852Seric 	if (flags & IO_PAUSE_IN)
566eb54aa8aSgilles 		(void)strlcat(buf, ",F_PI", sizeof buf);
567d1ece852Seric 	if (flags & IO_PAUSE_OUT)
568eb54aa8aSgilles 		(void)strlcat(buf, ",F_PO", sizeof buf);
569d1ece852Seric 
570d1ece852Seric 	return buf;
571d1ece852Seric }
572d1ece852Seric 
573d1ece852Seric const char*
574d1ece852Seric io_evstr(short ev)
575d1ece852Seric {
576d1ece852Seric 	static char	buf[64];
577d1ece852Seric 	char		buf2[16];
578d1ece852Seric 	int		n;
579d1ece852Seric 
580d1ece852Seric 	n = 0;
581d1ece852Seric 	buf[0] = '\0';
582d1ece852Seric 
583d1ece852Seric 	if (ev == 0) {
584eb54aa8aSgilles 		(void)strlcat(buf, "<NONE>", sizeof(buf));
585d1ece852Seric 		return buf;
586d1ece852Seric 	}
587d1ece852Seric 
588d1ece852Seric 	if (ev & EV_TIMEOUT) {
589eb54aa8aSgilles 		(void)strlcat(buf, "EV_TIMEOUT", sizeof(buf));
590d1ece852Seric 		ev &= ~EV_TIMEOUT;
591d1ece852Seric 		n++;
592d1ece852Seric 	}
593d1ece852Seric 
594d1ece852Seric 	if (ev & EV_READ) {
595d1ece852Seric 		if (n)
596eb54aa8aSgilles 			(void)strlcat(buf, "|", sizeof(buf));
597eb54aa8aSgilles 		(void)strlcat(buf, "EV_READ", sizeof(buf));
598d1ece852Seric 		ev &= ~EV_READ;
599d1ece852Seric 		n++;
600d1ece852Seric 	}
601d1ece852Seric 
602d1ece852Seric 	if (ev & EV_WRITE) {
603d1ece852Seric 		if (n)
604eb54aa8aSgilles 			(void)strlcat(buf, "|", sizeof(buf));
605eb54aa8aSgilles 		(void)strlcat(buf, "EV_WRITE", sizeof(buf));
606d1ece852Seric 		ev &= ~EV_WRITE;
607d1ece852Seric 		n++;
608d1ece852Seric 	}
609d1ece852Seric 
610d1ece852Seric 	if (ev & EV_SIGNAL) {
611d1ece852Seric 		if (n)
612eb54aa8aSgilles 			(void)strlcat(buf, "|", sizeof(buf));
613eb54aa8aSgilles 		(void)strlcat(buf, "EV_SIGNAL", sizeof(buf));
614d1ece852Seric 		ev &= ~EV_SIGNAL;
615d1ece852Seric 		n++;
616d1ece852Seric 	}
617d1ece852Seric 
618d1ece852Seric 	if (ev) {
619d1ece852Seric 		if (n)
620eb54aa8aSgilles 			(void)strlcat(buf, "|", sizeof(buf));
621eb54aa8aSgilles 		(void)strlcat(buf, "EV_?=0x", sizeof(buf));
622eb54aa8aSgilles 		(void)snprintf(buf2, sizeof(buf2), "%hx", ev);
623eb54aa8aSgilles 		(void)strlcat(buf, buf2, sizeof(buf));
624d1ece852Seric 	}
625d1ece852Seric 
626d1ece852Seric 	return buf;
627d1ece852Seric }
628d1ece852Seric 
629d1ece852Seric void
630d1ece852Seric io_dispatch(int fd, short ev, void *humppa)
631d1ece852Seric {
632d1ece852Seric 	struct io	*io = humppa;
633d1ece852Seric 	size_t		 w;
634d1ece852Seric 	ssize_t		 n;
63565c4fdfbSgilles 	int		 saved_errno;
636d1ece852Seric 
637d1ece852Seric 	io_frame_enter("io_dispatch", io, ev);
638d1ece852Seric 
639d1ece852Seric 	if (ev == EV_TIMEOUT) {
640d1ece852Seric 		io_callback(io, IO_TIMEOUT);
641d1ece852Seric 		goto leave;
642d1ece852Seric 	}
643d1ece852Seric 
644d1ece852Seric 	if (ev & EV_WRITE && (w = io_queued(io))) {
645d1ece852Seric 		if ((n = iobuf_write(io->iobuf, io->sock)) < 0) {
646a80802bcSeric 			if (n == IOBUF_WANT_WRITE) /* kqueue bug? */
647a80802bcSeric 				goto read;
64865c4fdfbSgilles 			if (n == IOBUF_CLOSED)
64965c4fdfbSgilles 				io_callback(io, IO_DISCONNECTED);
65065c4fdfbSgilles 			else {
65165c4fdfbSgilles 				saved_errno = errno;
65265c4fdfbSgilles 				io->error = strerror(errno);
65365c4fdfbSgilles 				errno = saved_errno;
65465c4fdfbSgilles 				io_callback(io, IO_ERROR);
65565c4fdfbSgilles 			}
656d1ece852Seric 			goto leave;
657d1ece852Seric 		}
658d1ece852Seric 		if (w > io->lowat && w - n <= io->lowat)
659d1ece852Seric 			io_callback(io, IO_LOWAT);
660d1ece852Seric 	}
661a80802bcSeric     read:
662d1ece852Seric 
663d1ece852Seric 	if (ev & EV_READ) {
664d1ece852Seric 		if ((n = iobuf_read(io->iobuf, io->sock)) < 0) {
66565c4fdfbSgilles 			if (n == IOBUF_CLOSED)
66665c4fdfbSgilles 				io_callback(io, IO_DISCONNECTED);
66765c4fdfbSgilles 			else {
66865c4fdfbSgilles 				saved_errno = errno;
66965c4fdfbSgilles 				io->error = strerror(errno);
67065c4fdfbSgilles 				errno = saved_errno;
67165c4fdfbSgilles 				io_callback(io, IO_ERROR);
67265c4fdfbSgilles 			}
673d1ece852Seric 			goto leave;
674d1ece852Seric 		}
675d1ece852Seric 		if (n)
676d1ece852Seric 			io_callback(io, IO_DATAIN);
677d1ece852Seric 	}
678d1ece852Seric 
679d1ece852Seric leave:
680d1ece852Seric 	io_frame_leave(io);
681d1ece852Seric }
682d1ece852Seric 
683d1ece852Seric void
684d1ece852Seric io_callback(struct io *io, int evt)
685d1ece852Seric {
686b556a8d3Seric 	io->cb(io, evt, io->arg);
687d1ece852Seric }
688d1ece852Seric 
689d1ece852Seric int
6902c1d98b8Seric io_connect(struct io *io, const struct sockaddr *sa, const struct sockaddr *bsa)
691d1ece852Seric {
692d1ece852Seric 	int	sock, errno_save;
693d1ece852Seric 
694d1ece852Seric 	if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) == -1)
695d1ece852Seric 		goto fail;
696d1ece852Seric 
697907c4b99Skrw 	io_set_nonblocking(sock);
698907c4b99Skrw 	io_set_nolinger(sock);
699d1ece852Seric 
7002c1d98b8Seric 	if (bsa && bind(sock, bsa, bsa->sa_len) == -1)
7012c1d98b8Seric 		goto fail;
7022c1d98b8Seric 
703d1ece852Seric 	if (connect(sock, sa, sa->sa_len) == -1)
704d1ece852Seric 		if (errno != EINPROGRESS)
705d1ece852Seric 			goto fail;
706d1ece852Seric 
707d1ece852Seric 	io->sock = sock;
708d1ece852Seric 	io_reset(io, EV_WRITE, io_dispatch_connect);
709d1ece852Seric 
710d1ece852Seric 	return (sock);
711d1ece852Seric 
712d1ece852Seric     fail:
713d1ece852Seric 	if (sock != -1) {
714d1ece852Seric 		errno_save = errno;
715d1ece852Seric 		close(sock);
716d1ece852Seric 		errno = errno_save;
71765c4fdfbSgilles 		io->error = strerror(errno);
718d1ece852Seric 	}
719d1ece852Seric 	return (-1);
720d1ece852Seric }
721d1ece852Seric 
722d1ece852Seric void
723d1ece852Seric io_dispatch_connect(int fd, short ev, void *humppa)
724d1ece852Seric {
725d1ece852Seric 	struct io	*io = humppa;
726299c4efeSeric 	int		 r, e;
727299c4efeSeric 	socklen_t	 sl;
728d1ece852Seric 
729d1ece852Seric 	io_frame_enter("io_dispatch_connect", io, ev);
730d1ece852Seric 
731d1ece852Seric 	if (ev == EV_TIMEOUT) {
732d1ece852Seric 		close(fd);
733d1ece852Seric 		io->sock = -1;
734d1ece852Seric 		io_callback(io, IO_TIMEOUT);
735d1ece852Seric 	} else {
736299c4efeSeric 		sl = sizeof(e);
737299c4efeSeric 		r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &e, &sl);
738299c4efeSeric 		if (r == -1)  {
739299c4efeSeric 			warn("io_dispatch_connect: getsockopt");
740299c4efeSeric 			e = errno;
741299c4efeSeric 		}
742299c4efeSeric 		if (e) {
743299c4efeSeric 			close(fd);
744299c4efeSeric 			io->sock = -1;
745299c4efeSeric 			io->error = strerror(e);
746299c4efeSeric 			io_callback(io, e == ETIMEDOUT ? IO_TIMEOUT : IO_ERROR);
747299c4efeSeric 		}
748299c4efeSeric 		else {
749d1ece852Seric 			io->state = IO_STATE_UP;
750d1ece852Seric 			io_callback(io, IO_CONNECTED);
751d1ece852Seric 		}
752299c4efeSeric 	}
753d1ece852Seric 
754d1ece852Seric 	io_frame_leave(io);
755d1ece852Seric }
756d1ece852Seric 
757d1ece852Seric #ifdef IO_SSL
758d1ece852Seric 
75965c4fdfbSgilles static const char*
76065c4fdfbSgilles io_ssl_error(void)
76165c4fdfbSgilles {
76265c4fdfbSgilles 	static char	buf[128];
76365c4fdfbSgilles 	unsigned long	e;
76465c4fdfbSgilles 
76565c4fdfbSgilles 	e = ERR_peek_last_error();
76665c4fdfbSgilles 	if (e) {
76765c4fdfbSgilles 		ERR_error_string(e, buf);
76865c4fdfbSgilles 		return (buf);
76965c4fdfbSgilles 	}
77065c4fdfbSgilles 
77165c4fdfbSgilles 	return ("No SSL error");
77265c4fdfbSgilles }
77365c4fdfbSgilles 
774d1ece852Seric int
775d1ece852Seric io_start_tls(struct io *io, void *ssl)
776d1ece852Seric {
777d1ece852Seric 	int	mode;
778d1ece852Seric 
779d1ece852Seric 	mode = io->flags & IO_RW;
780d1ece852Seric 	if (mode == 0 || mode == IO_RW)
781d1ece852Seric 		errx(1, "io_start_tls(): full-duplex or unset");
782d1ece852Seric 
783d1ece852Seric 	if (io->ssl)
784d1ece852Seric 		errx(1, "io_start_tls(): SSL already started");
785d1ece852Seric 	io->ssl = ssl;
786d1ece852Seric 
787d1ece852Seric 	if (SSL_set_fd(io->ssl, io->sock) == 0) {
788d1ece852Seric 		ssl_error("io_start_ssl:SSL_set_fd");
789d1ece852Seric 		return (-1);
790d1ece852Seric 	}
791d1ece852Seric 
792d1ece852Seric 	if (mode == IO_WRITE) {
793d1ece852Seric 		io->state = IO_STATE_CONNECT_SSL;
794d1ece852Seric 		SSL_set_connect_state(io->ssl);
795299c4efeSeric 		io_reset(io, EV_WRITE, io_dispatch_connect_ssl);
796d1ece852Seric 	} else {
797d1ece852Seric 		io->state = IO_STATE_ACCEPT_SSL;
798d1ece852Seric 		SSL_set_accept_state(io->ssl);
799299c4efeSeric 		io_reset(io, EV_READ, io_dispatch_accept_ssl);
800d1ece852Seric 	}
801d1ece852Seric 
802d1ece852Seric 	return (0);
803d1ece852Seric }
804d1ece852Seric 
805d1ece852Seric void
806d1ece852Seric io_dispatch_accept_ssl(int fd, short event, void *humppa)
807d1ece852Seric {
808d1ece852Seric 	struct io	*io = humppa;
809d1ece852Seric 	int		 e, ret;
810d1ece852Seric 
811d1ece852Seric 	io_frame_enter("io_dispatch_accept_ssl", io, event);
812d1ece852Seric 
813d1ece852Seric 	if (event == EV_TIMEOUT) {
814d1ece852Seric 		io_callback(io, IO_TIMEOUT);
815d1ece852Seric 		goto leave;
816d1ece852Seric 	}
817d1ece852Seric 
818d1ece852Seric 	if ((ret = SSL_accept(io->ssl)) > 0) {
819d1ece852Seric 		io->state = IO_STATE_UP;
820d1ece852Seric 		io_callback(io, IO_TLSREADY);
821d1ece852Seric 		goto leave;
822d1ece852Seric 	}
823d1ece852Seric 
824d1ece852Seric 	switch ((e = SSL_get_error(io->ssl, ret))) {
825d1ece852Seric 	case SSL_ERROR_WANT_READ:
826d1ece852Seric 		io_reset(io, EV_READ, io_dispatch_accept_ssl);
827d1ece852Seric 		break;
828d1ece852Seric 	case SSL_ERROR_WANT_WRITE:
829d1ece852Seric 		io_reset(io, EV_WRITE, io_dispatch_accept_ssl);
830d1ece852Seric 		break;
831d1ece852Seric 	default:
83265c4fdfbSgilles 		io->error = io_ssl_error();
833d1ece852Seric 		ssl_error("io_dispatch_accept_ssl:SSL_accept");
834d1ece852Seric 		io_callback(io, IO_ERROR);
835d1ece852Seric 		break;
836d1ece852Seric 	}
837d1ece852Seric 
838d1ece852Seric     leave:
839d1ece852Seric 	io_frame_leave(io);
840d1ece852Seric }
841d1ece852Seric 
842d1ece852Seric void
843d1ece852Seric io_dispatch_connect_ssl(int fd, short event, void *humppa)
844d1ece852Seric {
845d1ece852Seric 	struct io	*io = humppa;
846d1ece852Seric 	int		 e, ret;
847d1ece852Seric 
848d1ece852Seric 	io_frame_enter("io_dispatch_connect_ssl", io, event);
849d1ece852Seric 
850d1ece852Seric 	if (event == EV_TIMEOUT) {
851d1ece852Seric 		io_callback(io, IO_TIMEOUT);
852d1ece852Seric 		goto leave;
853d1ece852Seric 	}
854d1ece852Seric 
855d1ece852Seric 	if ((ret = SSL_connect(io->ssl)) > 0) {
856d1ece852Seric 		io->state = IO_STATE_UP;
857d1ece852Seric 		io_callback(io, IO_TLSREADY);
858d1ece852Seric 		goto leave;
859d1ece852Seric 	}
860d1ece852Seric 
861d1ece852Seric 	switch ((e = SSL_get_error(io->ssl, ret))) {
862d1ece852Seric 	case SSL_ERROR_WANT_READ:
863d1ece852Seric 		io_reset(io, EV_READ, io_dispatch_connect_ssl);
864d1ece852Seric 		break;
865d1ece852Seric 	case SSL_ERROR_WANT_WRITE:
866d1ece852Seric 		io_reset(io, EV_WRITE, io_dispatch_connect_ssl);
867d1ece852Seric 		break;
868d1ece852Seric 	default:
86965c4fdfbSgilles 		io->error = io_ssl_error();
8709013f127Seric 		ssl_error("io_dispatch_connect_ssl:SSL_connect");
87173f9c94dSeric 		io_callback(io, IO_TLSERROR);
872d1ece852Seric 		break;
873d1ece852Seric 	}
874d1ece852Seric 
875d1ece852Seric     leave:
876d1ece852Seric 	io_frame_leave(io);
877d1ece852Seric }
878d1ece852Seric 
879d1ece852Seric void
880d1ece852Seric io_dispatch_read_ssl(int fd, short event, void *humppa)
881d1ece852Seric {
882d1ece852Seric 	struct io	*io = humppa;
88365c4fdfbSgilles 	int		 n, saved_errno;
884d1ece852Seric 
885d1ece852Seric 	io_frame_enter("io_dispatch_read_ssl", io, event);
886d1ece852Seric 
887d1ece852Seric 	if (event == EV_TIMEOUT) {
888d1ece852Seric 		io_callback(io, IO_TIMEOUT);
889d1ece852Seric 		goto leave;
890d1ece852Seric 	}
891d1ece852Seric 
892b0e8ad58Seric again:
893d1ece852Seric 	switch ((n = iobuf_read_ssl(io->iobuf, (SSL*)io->ssl))) {
894d1ece852Seric 	case IOBUF_WANT_READ:
895d1ece852Seric 		io_reset(io, EV_READ, io_dispatch_read_ssl);
896d1ece852Seric 		break;
897d1ece852Seric 	case IOBUF_WANT_WRITE:
898d1ece852Seric 		io_reset(io, EV_WRITE, io_dispatch_read_ssl);
899d1ece852Seric 		break;
900d1ece852Seric 	case IOBUF_CLOSED:
901d1ece852Seric 		io_callback(io, IO_DISCONNECTED);
902d1ece852Seric 		break;
903d1ece852Seric 	case IOBUF_ERROR:
90465c4fdfbSgilles 		saved_errno = errno;
90565c4fdfbSgilles 		io->error = strerror(errno);
90665c4fdfbSgilles 		errno = saved_errno;
90765c4fdfbSgilles 		io_callback(io, IO_ERROR);
90865c4fdfbSgilles 		break;
90965c4fdfbSgilles 	case IOBUF_SSLERROR:
91065c4fdfbSgilles 		io->error = io_ssl_error();
9119013f127Seric 		ssl_error("io_dispatch_read_ssl:SSL_read");
912d1ece852Seric 		io_callback(io, IO_ERROR);
913d1ece852Seric 		break;
914d1ece852Seric 	default:
915d7bcae4dSeric 		io_debug("io_dispatch_read_ssl(...) -> r=%d\n", n);
916d1ece852Seric 		io_callback(io, IO_DATAIN);
917b0e8ad58Seric 		if (current == io && IO_READING(io) && SSL_pending(io->ssl))
918b0e8ad58Seric 			goto again;
919d1ece852Seric 	}
920d1ece852Seric 
921d1ece852Seric     leave:
922d1ece852Seric 	io_frame_leave(io);
923d1ece852Seric }
924d1ece852Seric 
925d1ece852Seric void
926d1ece852Seric io_dispatch_write_ssl(int fd, short event, void *humppa)
927d1ece852Seric {
928d1ece852Seric 	struct io	*io = humppa;
92965c4fdfbSgilles 	int		 n, saved_errno;
930d1ece852Seric 	size_t		 w2, w;
931d1ece852Seric 
932d1ece852Seric 	io_frame_enter("io_dispatch_write_ssl", io, event);
933d1ece852Seric 
934d1ece852Seric 	if (event == EV_TIMEOUT) {
935d1ece852Seric 		io_callback(io, IO_TIMEOUT);
936d1ece852Seric 		goto leave;
937d1ece852Seric 	}
938d1ece852Seric 
939d1ece852Seric 	w = io_queued(io);
940d1ece852Seric 	switch ((n = iobuf_write_ssl(io->iobuf, (SSL*)io->ssl))) {
941d1ece852Seric 	case IOBUF_WANT_READ:
942d1ece852Seric 		io_reset(io, EV_READ, io_dispatch_write_ssl);
943d1ece852Seric 		break;
944d1ece852Seric 	case IOBUF_WANT_WRITE:
945d1ece852Seric 		io_reset(io, EV_WRITE, io_dispatch_write_ssl);
946d1ece852Seric 		break;
947d1ece852Seric 	case IOBUF_CLOSED:
948d1ece852Seric 		io_callback(io, IO_DISCONNECTED);
949d1ece852Seric 		break;
950d1ece852Seric 	case IOBUF_ERROR:
95165c4fdfbSgilles 		saved_errno = errno;
95265c4fdfbSgilles 		io->error = strerror(errno);
95365c4fdfbSgilles 		errno = saved_errno;
95465c4fdfbSgilles 		io_callback(io, IO_ERROR);
95565c4fdfbSgilles 		break;
95665c4fdfbSgilles 	case IOBUF_SSLERROR:
95765c4fdfbSgilles 		io->error = io_ssl_error();
9589013f127Seric 		ssl_error("io_dispatch_write_ssl:SSL_write");
959d1ece852Seric 		io_callback(io, IO_ERROR);
960d1ece852Seric 		break;
961d1ece852Seric 	default:
962d7bcae4dSeric 		io_debug("io_dispatch_write_ssl(...) -> w=%d\n", n);
963d1ece852Seric 		w2 = io_queued(io);
964d1ece852Seric 		if (w > io->lowat && w2 <= io->lowat)
965d1ece852Seric 			io_callback(io, IO_LOWAT);
966d1ece852Seric 		break;
967d1ece852Seric 	}
968d1ece852Seric 
969d1ece852Seric     leave:
970d1ece852Seric 	io_frame_leave(io);
971d1ece852Seric }
972d1ece852Seric 
973d1ece852Seric void
974d1ece852Seric io_reload_ssl(struct io *io)
975d1ece852Seric {
976299c4efeSeric 	short	ev = 0;
977d1ece852Seric 	void	(*dispatch)(int, short, void*) = NULL;
978d1ece852Seric 
979d1ece852Seric 	switch (io->state) {
980d1ece852Seric 	case IO_STATE_CONNECT_SSL:
981299c4efeSeric 		ev = EV_WRITE;
982d1ece852Seric 		dispatch = io_dispatch_connect_ssl;
983d1ece852Seric 		break;
984d1ece852Seric 	case IO_STATE_ACCEPT_SSL:
985299c4efeSeric 		ev = EV_READ;
986d1ece852Seric 		dispatch = io_dispatch_accept_ssl;
987d1ece852Seric 		break;
988d1ece852Seric 	case IO_STATE_UP:
989299c4efeSeric 		ev = 0;
990299c4efeSeric 		if (IO_READING(io) && !(io->flags & IO_PAUSE_IN)) {
991299c4efeSeric 			ev = EV_READ;
992d1ece852Seric 			dispatch = io_dispatch_read_ssl;
993299c4efeSeric 		}
994ad775936Ssunil 		else if (IO_WRITING(io) && !(io->flags & IO_PAUSE_OUT) &&
995ad775936Ssunil 		    io_queued(io)) {
996299c4efeSeric 			ev = EV_WRITE;
997d1ece852Seric 			dispatch = io_dispatch_write_ssl;
998d1ece852Seric 		}
999299c4efeSeric 		if (!ev)
1000299c4efeSeric 			return; /* paused */
1001d1ece852Seric 		break;
1002d1ece852Seric 	default:
1003d1ece852Seric 		errx(1, "io_reload_ssl(): bad state");
1004d1ece852Seric 	}
1005d1ece852Seric 
1006299c4efeSeric 	io_reset(io, ev, dispatch);
1007d1ece852Seric }
1008d1ece852Seric 
1009d1ece852Seric #endif /* IO_SSL */
1010