1*04fee684Stb /* $OpenBSD: ioev.c,v 1.49 2023/02/08 08:20:54 tb 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
18d1ece852Seric #include <sys/socket.h>
19d1ece852Seric
20d1ece852Seric #include <errno.h>
218d3f7f0dSeric #include <event.h>
22d1ece852Seric #include <fcntl.h>
230e63ed3bSchl #include <inttypes.h>
24d1ece852Seric #include <stdlib.h>
25d1ece852Seric #include <string.h>
26d1ece852Seric #include <stdio.h>
27eed85469Seric #ifdef IO_TLS
28eed85469Seric #include <tls.h>
29eed85469Seric #endif
30d1ece852Seric #include <unistd.h>
31d1ece852Seric
32d1ece852Seric #include "ioev.h"
33d1ece852Seric #include "iobuf.h"
34ff01b044Seric #include "log.h"
35d1ece852Seric
36d1ece852Seric enum {
37d1ece852Seric IO_STATE_NONE,
38d1ece852Seric IO_STATE_CONNECT,
399ac7cdfdSeric IO_STATE_CONNECT_TLS,
409ac7cdfdSeric IO_STATE_ACCEPT_TLS,
41d1ece852Seric IO_STATE_UP,
42d1ece852Seric
43d1ece852Seric IO_STATE_MAX,
44d1ece852Seric };
45d1ece852Seric
46f80a744fSeric #define IO_PAUSE_IN IO_IN
47f80a744fSeric #define IO_PAUSE_OUT IO_OUT
48f80a744fSeric #define IO_READ 0x04
49f80a744fSeric #define IO_WRITE 0x08
50f80a744fSeric #define IO_RW (IO_READ | IO_WRITE)
51f80a744fSeric #define IO_RESET 0x10 /* internal */
52f80a744fSeric #define IO_HELD 0x20 /* internal */
53f80a744fSeric
548d3f7f0dSeric struct io {
558d3f7f0dSeric int sock;
568d3f7f0dSeric void *arg;
578d3f7f0dSeric void (*cb)(struct io*, int, void *);
5805afcc4dSeric struct iobuf iobuf;
598d3f7f0dSeric size_t lowat;
608d3f7f0dSeric int timeout;
618d3f7f0dSeric int flags;
628d3f7f0dSeric int state;
638d3f7f0dSeric struct event ev;
64eed85469Seric struct tls *tls;
65eed85469Seric
668d3f7f0dSeric const char *error; /* only valid immediately on callback */
678d3f7f0dSeric };
688d3f7f0dSeric
69d1ece852Seric const char* io_strflags(int);
70d1ece852Seric const char* io_evstr(short);
71d1ece852Seric
72d1ece852Seric void _io_init(void);
73d1ece852Seric void io_hold(struct io *);
74d1ece852Seric void io_release(struct io *);
75d1ece852Seric void io_callback(struct io*, int);
76d1ece852Seric void io_dispatch(int, short, void *);
77d1ece852Seric void io_dispatch_connect(int, short, void *);
78d1ece852Seric size_t io_pending(struct io *);
79d1ece852Seric size_t io_queued(struct io*);
80d1ece852Seric void io_reset(struct io *, short, void (*)(int, short, void*));
81d1ece852Seric void io_frame_enter(const char *, struct io *, int);
82d1ece852Seric void io_frame_leave(struct io *);
83d1ece852Seric
849ac7cdfdSeric #ifdef IO_TLS
85eed85469Seric void io_dispatch_handshake_tls(int, short, void *);
869ac7cdfdSeric void io_dispatch_accept_tls(int, short, void *);
879ac7cdfdSeric void io_dispatch_connect_tls(int, short, void *);
889ac7cdfdSeric void io_dispatch_read_tls(int, short, void *);
899ac7cdfdSeric void io_dispatch_write_tls(int, short, void *);
909ac7cdfdSeric void io_reload_tls(struct io *io);
91d1ece852Seric #endif
92d1ece852Seric
93d1ece852Seric static struct io *current = NULL;
94d1ece852Seric static uint64_t frame = 0;
95d1ece852Seric static int _io_debug = 0;
96d1ece852Seric
97d1ece852Seric #define io_debug(args...) do { if (_io_debug) printf(args); } while(0)
98d1ece852Seric
99d1ece852Seric
100d1ece852Seric const char*
io_strio(struct io * io)101d1ece852Seric io_strio(struct io *io)
102d1ece852Seric {
103d1ece852Seric static char buf[128];
10405a218a6Seric char ssl[128];
105d1ece852Seric
10605a218a6Seric ssl[0] = '\0';
1079ac7cdfdSeric #ifdef IO_TLS
1089ac7cdfdSeric if (io->tls) {
109eed85469Seric (void)snprintf(ssl, sizeof ssl, " tls=%s:%s",
110eed85469Seric tls_conn_version(io->tls),
111eed85469Seric tls_conn_cipher(io->tls));
11205a218a6Seric }
11305a218a6Seric #endif
11405a218a6Seric
115fd77dd20Sgilles (void)snprintf(buf, sizeof buf,
116d7bcae4dSeric "<io:%p fd=%d to=%d fl=%s%s ib=%zu ob=%zu>",
11705a218a6Seric io, io->sock, io->timeout, io_strflags(io->flags), ssl,
118d1ece852Seric io_pending(io), io_queued(io));
11905a218a6Seric
120d1ece852Seric return (buf);
121d1ece852Seric }
122d1ece852Seric
123d1ece852Seric #define CASE(x) case x : return #x
124d1ece852Seric
125d1ece852Seric const char*
io_strevent(int evt)126d1ece852Seric io_strevent(int evt)
127d1ece852Seric {
128d1ece852Seric static char buf[32];
129d1ece852Seric
130d1ece852Seric switch (evt) {
131d1ece852Seric CASE(IO_CONNECTED);
132d1ece852Seric CASE(IO_TLSREADY);
133d1ece852Seric CASE(IO_DATAIN);
134d1ece852Seric CASE(IO_LOWAT);
135d1ece852Seric CASE(IO_DISCONNECTED);
136d1ece852Seric CASE(IO_TIMEOUT);
137d1ece852Seric CASE(IO_ERROR);
138d1ece852Seric default:
139fd77dd20Sgilles (void)snprintf(buf, sizeof(buf), "IO_? %d", evt);
140d1ece852Seric return buf;
141d1ece852Seric }
142d1ece852Seric }
143d1ece852Seric
144d1ece852Seric void
io_set_nonblocking(int fd)145907c4b99Skrw io_set_nonblocking(int fd)
146d1ece852Seric {
147d1ece852Seric int flags;
148d1ece852Seric
149907c4b99Skrw if ((flags = fcntl(fd, F_GETFL)) == -1)
150ff01b044Seric fatal("io_set_blocking:fcntl(F_GETFL)");
151d1ece852Seric
152d1ece852Seric flags |= O_NONBLOCK;
153d1ece852Seric
15432e1408cSmillert if (fcntl(fd, F_SETFL, flags) == -1)
155ff01b044Seric fatal("io_set_blocking:fcntl(F_SETFL)");
156d1ece852Seric }
157d1ece852Seric
158d1ece852Seric void
io_set_nolinger(int fd)159907c4b99Skrw io_set_nolinger(int fd)
160d1ece852Seric {
161d1ece852Seric struct linger l;
162d1ece852Seric
163c1392a69Seric memset(&l, 0, sizeof(l));
164d1ece852Seric if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) == -1)
165ff01b044Seric fatal("io_set_linger:setsockopt");
166d1ece852Seric }
167d1ece852Seric
168d1ece852Seric /*
169d1ece852Seric * Event framing must not rely on an io pointer to refer to the "same" io
170af0dba2aSsobrado * throughout the frame, because this is not always the case:
171d1ece852Seric *
172d1ece852Seric * 1) enter(addr0) -> free(addr0) -> leave(addr0) = SEGV
173d1ece852Seric * 2) enter(addr0) -> free(addr0) -> malloc == addr0 -> leave(addr0) = BAD!
174d1ece852Seric *
175d1ece852Seric * In both case, the problem is that the io is freed in the callback, so
176d1ece852Seric * the pointer becomes invalid. If that happens, the user is required to
177d1ece852Seric * call io_clear, so we can adapt the frame state there.
178d1ece852Seric */
179d1ece852Seric void
io_frame_enter(const char * where,struct io * io,int ev)180d1ece852Seric io_frame_enter(const char *where, struct io *io, int ev)
181d1ece852Seric {
182d1ece852Seric io_debug("\n=== %" PRIu64 " ===\n"
183d1ece852Seric "io_frame_enter(%s, %s, %s)\n",
184d1ece852Seric frame, where, io_evstr(ev), io_strio(io));
185d1ece852Seric
186d1ece852Seric if (current)
187ff01b044Seric fatalx("io_frame_enter: interleaved frames");
188d1ece852Seric
189d1ece852Seric current = io;
190d1ece852Seric
191d1ece852Seric io_hold(io);
192d1ece852Seric }
193d1ece852Seric
194d1ece852Seric void
io_frame_leave(struct io * io)195d1ece852Seric io_frame_leave(struct io *io)
196d1ece852Seric {
197d1ece852Seric io_debug("io_frame_leave(%" PRIu64 ")\n", frame);
198d1ece852Seric
199d1ece852Seric if (current && current != io)
200ff01b044Seric fatalx("io_frame_leave: io mismatch");
201d1ece852Seric
202d1ece852Seric /* io has been cleared */
203d1ece852Seric if (current == NULL)
204d1ece852Seric goto done;
205d1ece852Seric
206d1ece852Seric /* TODO: There is a possible optimization there:
207d1ece852Seric * In a typical half-duplex request/response scenario,
208d1ece852Seric * the io is waiting to read a request, and when done, it queues
209d1ece852Seric * the response in the output buffer and goes to write mode.
210d1ece852Seric * There, the write event is set and will be triggered in the next
211d1ece852Seric * event frame. In most case, the write call could be done
212af0dba2aSsobrado * immediately as part of the last read frame, thus avoiding to go
213d1ece852Seric * through the event loop machinery. So, as an optimisation, we
214d1ece852Seric * could detect that case here and force an event dispatching.
215d1ece852Seric */
216d1ece852Seric
217d1ece852Seric /* Reload the io if it has not been reset already. */
218d1ece852Seric io_release(io);
219d1ece852Seric current = NULL;
220d1ece852Seric done:
221d1ece852Seric io_debug("=== /%" PRIu64 "\n", frame);
222d1ece852Seric
223d1ece852Seric frame += 1;
224d1ece852Seric }
225d1ece852Seric
226d1ece852Seric void
_io_init(void)227*04fee684Stb _io_init(void)
228d1ece852Seric {
229d1ece852Seric static int init = 0;
230d1ece852Seric
231d1ece852Seric if (init)
232d1ece852Seric return;
233d1ece852Seric
234d1ece852Seric init = 1;
235d1ece852Seric _io_debug = getenv("IO_DEBUG") != NULL;
236d1ece852Seric }
237d1ece852Seric
2388d3f7f0dSeric struct io *
io_new(void)2398d3f7f0dSeric io_new(void)
240d1ece852Seric {
2418d3f7f0dSeric struct io *io;
2428d3f7f0dSeric
243d1ece852Seric _io_init();
244d1ece852Seric
2458d3f7f0dSeric if ((io = calloc(1, sizeof(*io))) == NULL)
2468d3f7f0dSeric return NULL;
247d1ece852Seric
248f81b996bSeric io->sock = -1;
249d1ece852Seric io->timeout = -1;
2508d3f7f0dSeric
25105afcc4dSeric if (iobuf_init(&io->iobuf, 0, 0) == -1) {
2528d3f7f0dSeric free(io);
2538d3f7f0dSeric return NULL;
2548d3f7f0dSeric }
2558d3f7f0dSeric
2568d3f7f0dSeric return io;
257d1ece852Seric }
258d1ece852Seric
259d1ece852Seric void
io_free(struct io * io)2608d3f7f0dSeric io_free(struct io *io)
261d1ece852Seric {
262d1ece852Seric io_debug("io_clear(%p)\n", io);
263d1ece852Seric
264d1ece852Seric /* the current io is virtually dead */
265d1ece852Seric if (io == current)
266d1ece852Seric current = NULL;
267d1ece852Seric
2689ac7cdfdSeric #ifdef IO_TLS
269eed85469Seric tls_free(io->tls);
2709ac7cdfdSeric io->tls = NULL;
271d1ece852Seric #endif
272d1ece852Seric
2739ad25316Seric if (event_initialized(&io->ev))
274d1ece852Seric event_del(&io->ev);
275d1ece852Seric if (io->sock != -1) {
276d1ece852Seric close(io->sock);
277d1ece852Seric io->sock = -1;
278d1ece852Seric }
2798d3f7f0dSeric
28005afcc4dSeric iobuf_clear(&io->iobuf);
2818d3f7f0dSeric free(io);
282d1ece852Seric }
283d1ece852Seric
284d1ece852Seric void
io_hold(struct io * io)285d1ece852Seric io_hold(struct io *io)
286d1ece852Seric {
287d1ece852Seric io_debug("io_enter(%p)\n", io);
288d1ece852Seric
289d1ece852Seric if (io->flags & IO_HELD)
290ff01b044Seric fatalx("io_hold: io is already held");
291d1ece852Seric
292d1ece852Seric io->flags &= ~IO_RESET;
293d1ece852Seric io->flags |= IO_HELD;
294d1ece852Seric }
295d1ece852Seric
296d1ece852Seric void
io_release(struct io * io)297d1ece852Seric io_release(struct io *io)
298d1ece852Seric {
299d1ece852Seric if (!(io->flags & IO_HELD))
300ff01b044Seric fatalx("io_release: io is not held");
301d1ece852Seric
302d1ece852Seric io->flags &= ~IO_HELD;
303d1ece852Seric if (!(io->flags & IO_RESET))
304d1ece852Seric io_reload(io);
305d1ece852Seric }
306d1ece852Seric
307d1ece852Seric void
io_set_fd(struct io * io,int fd)308f81b996bSeric io_set_fd(struct io *io, int fd)
309f81b996bSeric {
310f81b996bSeric io->sock = fd;
311f81b996bSeric if (fd != -1)
312f81b996bSeric io_reload(io);
313f81b996bSeric }
314f81b996bSeric
315f81b996bSeric void
io_set_callback(struct io * io,void (* cb)(struct io *,int,void *),void * arg)316f81b996bSeric io_set_callback(struct io *io, void(*cb)(struct io *, int, void *), void *arg)
317f81b996bSeric {
318f81b996bSeric io->cb = cb;
319f81b996bSeric io->arg = arg;
320f81b996bSeric }
321f81b996bSeric
322f81b996bSeric void
io_set_timeout(struct io * io,int msec)323d1ece852Seric io_set_timeout(struct io *io, int msec)
324d1ece852Seric {
325d7bcae4dSeric io_debug("io_set_timeout(%p, %d)\n", io, msec);
326d1ece852Seric
327d1ece852Seric io->timeout = msec;
328d1ece852Seric }
329d1ece852Seric
330d1ece852Seric void
io_set_lowat(struct io * io,size_t lowat)331d1ece852Seric io_set_lowat(struct io *io, size_t lowat)
332d1ece852Seric {
333d1ece852Seric io_debug("io_set_lowat(%p, %zu)\n", io, lowat);
334d1ece852Seric
335d1ece852Seric io->lowat = lowat;
336d1ece852Seric }
337d1ece852Seric
338d1ece852Seric void
io_pause(struct io * io,int dir)339d1ece852Seric io_pause(struct io *io, int dir)
340d1ece852Seric {
341d1ece852Seric io_debug("io_pause(%p, %x)\n", io, dir);
342d1ece852Seric
343d1ece852Seric io->flags |= dir & (IO_PAUSE_IN | IO_PAUSE_OUT);
344d1ece852Seric io_reload(io);
345d1ece852Seric }
346d1ece852Seric
347d1ece852Seric void
io_resume(struct io * io,int dir)348d1ece852Seric io_resume(struct io *io, int dir)
349d1ece852Seric {
350d1ece852Seric io_debug("io_resume(%p, %x)\n", io, dir);
351d1ece852Seric
352d1ece852Seric io->flags &= ~(dir & (IO_PAUSE_IN | IO_PAUSE_OUT));
353d1ece852Seric io_reload(io);
354d1ece852Seric }
355d1ece852Seric
356d1ece852Seric void
io_set_read(struct io * io)357d1ece852Seric io_set_read(struct io *io)
358d1ece852Seric {
359d1ece852Seric int mode;
360d1ece852Seric
361d1ece852Seric io_debug("io_set_read(%p)\n", io);
362d1ece852Seric
363d1ece852Seric mode = io->flags & IO_RW;
364d1ece852Seric if (!(mode == 0 || mode == IO_WRITE))
365ff01b044Seric fatalx("io_set_read: full-duplex or reading");
366d1ece852Seric
367d1ece852Seric io->flags &= ~IO_RW;
368d1ece852Seric io->flags |= IO_READ;
369d1ece852Seric io_reload(io);
370d1ece852Seric }
371d1ece852Seric
372d1ece852Seric void
io_set_write(struct io * io)373d1ece852Seric io_set_write(struct io *io)
374d1ece852Seric {
375d1ece852Seric int mode;
376d1ece852Seric
377d1ece852Seric io_debug("io_set_write(%p)\n", io);
378d1ece852Seric
379d1ece852Seric mode = io->flags & IO_RW;
380d1ece852Seric if (!(mode == 0 || mode == IO_READ))
381ff01b044Seric fatalx("io_set_write: full-duplex or writing");
382d1ece852Seric
383d1ece852Seric io->flags &= ~IO_RW;
384d1ece852Seric io->flags |= IO_WRITE;
385d1ece852Seric io_reload(io);
386d1ece852Seric }
387d1ece852Seric
388219e2fd6Seric const char *
io_error(struct io * io)389219e2fd6Seric io_error(struct io *io)
390219e2fd6Seric {
391219e2fd6Seric return io->error;
392219e2fd6Seric }
393219e2fd6Seric
394eed85469Seric struct tls *
io_tls(struct io * io)3959ac7cdfdSeric io_tls(struct io *io)
3960a90943cSeric {
3979ac7cdfdSeric return io->tls;
3980a90943cSeric }
3990a90943cSeric
40040f95b7eSeric int
io_fileno(struct io * io)40140f95b7eSeric io_fileno(struct io *io)
40240f95b7eSeric {
40340f95b7eSeric return io->sock;
40440f95b7eSeric }
40540f95b7eSeric
406c13965bbSeric int
io_paused(struct io * io,int what)407c13965bbSeric io_paused(struct io *io, int what)
408c13965bbSeric {
409c13965bbSeric return (io->flags & (IO_PAUSE_IN | IO_PAUSE_OUT)) == what;
410c13965bbSeric }
411c13965bbSeric
41266802da1Seric /*
41366802da1Seric * Buffered output functions
41466802da1Seric */
41566802da1Seric
41666802da1Seric int
io_write(struct io * io,const void * buf,size_t len)41766802da1Seric io_write(struct io *io, const void *buf, size_t len)
41866802da1Seric {
419c57f8f28Seric int r;
420c57f8f28Seric
42105afcc4dSeric r = iobuf_queue(&io->iobuf, buf, len);
422c57f8f28Seric
423c57f8f28Seric io_reload(io);
424c57f8f28Seric
425c57f8f28Seric return r;
42666802da1Seric }
42766802da1Seric
42866802da1Seric int
io_writev(struct io * io,const struct iovec * iov,int iovcount)42966802da1Seric io_writev(struct io *io, const struct iovec *iov, int iovcount)
43066802da1Seric {
431c57f8f28Seric int r;
432c57f8f28Seric
43305afcc4dSeric r = iobuf_queuev(&io->iobuf, iov, iovcount);
434c57f8f28Seric
435c57f8f28Seric io_reload(io);
436c57f8f28Seric
437c57f8f28Seric return r;
43866802da1Seric }
43966802da1Seric
44066802da1Seric int
io_print(struct io * io,const char * s)44166802da1Seric io_print(struct io *io, const char *s)
44266802da1Seric {
44366802da1Seric return io_write(io, s, strlen(s));
44466802da1Seric }
44566802da1Seric
44666802da1Seric int
io_printf(struct io * io,const char * fmt,...)44766802da1Seric io_printf(struct io *io, const char *fmt, ...)
44866802da1Seric {
44966802da1Seric va_list ap;
45066802da1Seric int r;
45166802da1Seric
45266802da1Seric va_start(ap, fmt);
45366802da1Seric r = io_vprintf(io, fmt, ap);
45466802da1Seric va_end(ap);
45566802da1Seric
45666802da1Seric return r;
45766802da1Seric }
45866802da1Seric
45966802da1Seric int
io_vprintf(struct io * io,const char * fmt,va_list ap)46066802da1Seric io_vprintf(struct io *io, const char *fmt, va_list ap)
46166802da1Seric {
46266802da1Seric
46366802da1Seric char *buf;
46466802da1Seric int len;
46566802da1Seric
46666802da1Seric len = vasprintf(&buf, fmt, ap);
46766802da1Seric if (len == -1)
46866802da1Seric return -1;
46966802da1Seric len = io_write(io, buf, len);
47066802da1Seric free(buf);
47166802da1Seric
47266802da1Seric return len;
47366802da1Seric }
47466802da1Seric
47566802da1Seric size_t
io_queued(struct io * io)47666802da1Seric io_queued(struct io *io)
47766802da1Seric {
47805afcc4dSeric return iobuf_queued(&io->iobuf);
47966802da1Seric }
48066802da1Seric
48166802da1Seric /*
48266802da1Seric * Buffered input functions
48366802da1Seric */
48466802da1Seric
48566802da1Seric void *
io_data(struct io * io)48666802da1Seric io_data(struct io *io)
48766802da1Seric {
48805afcc4dSeric return iobuf_data(&io->iobuf);
48966802da1Seric }
49066802da1Seric
49166802da1Seric size_t
io_datalen(struct io * io)49266802da1Seric io_datalen(struct io *io)
49366802da1Seric {
49405afcc4dSeric return iobuf_len(&io->iobuf);
49566802da1Seric }
49666802da1Seric
49766802da1Seric char *
io_getline(struct io * io,size_t * sz)49866802da1Seric io_getline(struct io *io, size_t *sz)
49966802da1Seric {
50005afcc4dSeric return iobuf_getline(&io->iobuf, sz);
50166802da1Seric }
50266802da1Seric
50366802da1Seric void
io_drop(struct io * io,size_t sz)50466802da1Seric io_drop(struct io *io, size_t sz)
50566802da1Seric {
50605afcc4dSeric return iobuf_drop(&io->iobuf, sz);
50766802da1Seric }
50866802da1Seric
50966802da1Seric
510d1ece852Seric #define IO_READING(io) (((io)->flags & IO_RW) != IO_WRITE)
511d1ece852Seric #define IO_WRITING(io) (((io)->flags & IO_RW) != IO_READ)
512d1ece852Seric
513d1ece852Seric /*
514d1ece852Seric * Setup the necessary events as required by the current io state,
515d1ece852Seric * honouring duplex mode and i/o pauses.
516d1ece852Seric */
517d1ece852Seric void
io_reload(struct io * io)518d1ece852Seric io_reload(struct io *io)
519d1ece852Seric {
520d1ece852Seric short events;
521d1ece852Seric
522d1ece852Seric /* io will be reloaded at release time */
523d1ece852Seric if (io->flags & IO_HELD)
524d1ece852Seric return;
525d1ece852Seric
52605afcc4dSeric iobuf_normalize(&io->iobuf);
5270e198904Seric
5289ac7cdfdSeric #ifdef IO_TLS
5299ac7cdfdSeric if (io->tls) {
5309ac7cdfdSeric io_reload_tls(io);
531d1ece852Seric return;
532d1ece852Seric }
533d1ece852Seric #endif
534d1ece852Seric
535d1ece852Seric io_debug("io_reload(%p)\n", io);
536d1ece852Seric
537d1ece852Seric events = 0;
538d1ece852Seric if (IO_READING(io) && !(io->flags & IO_PAUSE_IN))
539d1ece852Seric events = EV_READ;
540d1ece852Seric if (IO_WRITING(io) && !(io->flags & IO_PAUSE_OUT) && io_queued(io))
541d1ece852Seric events |= EV_WRITE;
542d1ece852Seric
543d1ece852Seric io_reset(io, events, io_dispatch);
544d1ece852Seric }
545d1ece852Seric
546d1ece852Seric /* Set the requested event. */
547d1ece852Seric void
io_reset(struct io * io,short events,void (* dispatch)(int,short,void *))548d1ece852Seric io_reset(struct io *io, short events, void (*dispatch)(int, short, void*))
549d1ece852Seric {
550d1ece852Seric struct timeval tv, *ptv;
551d1ece852Seric
552d1ece852Seric io_debug("io_reset(%p, %s, %p) -> %s\n",
553d1ece852Seric io, io_evstr(events), dispatch, io_strio(io));
554d1ece852Seric
555d1ece852Seric /*
556d1ece852Seric * Indicate that the event has already been reset so that reload
557d1ece852Seric * is not called on frame_leave.
558d1ece852Seric */
559d1ece852Seric io->flags |= IO_RESET;
560d1ece852Seric
5619ad25316Seric if (event_initialized(&io->ev))
562d1ece852Seric event_del(&io->ev);
563d1ece852Seric
564d1ece852Seric /*
565d1ece852Seric * The io is paused by the user, so we don't want the timeout to be
566d1ece852Seric * effective.
567d1ece852Seric */
568d1ece852Seric if (events == 0)
569d1ece852Seric return;
570d1ece852Seric
571d1ece852Seric event_set(&io->ev, io->sock, events, dispatch, io);
572d1ece852Seric if (io->timeout >= 0) {
573d1ece852Seric tv.tv_sec = io->timeout / 1000;
574d1ece852Seric tv.tv_usec = (io->timeout % 1000) * 1000;
575d1ece852Seric ptv = &tv;
576d1ece852Seric } else
577d1ece852Seric ptv = NULL;
578d1ece852Seric
579d1ece852Seric event_add(&io->ev, ptv);
580d1ece852Seric }
581d1ece852Seric
582d1ece852Seric size_t
io_pending(struct io * io)583d1ece852Seric io_pending(struct io *io)
584d1ece852Seric {
58505afcc4dSeric return iobuf_len(&io->iobuf);
586d1ece852Seric }
587d1ece852Seric
588d1ece852Seric const char*
io_strflags(int flags)589d1ece852Seric io_strflags(int flags)
590d1ece852Seric {
591d1ece852Seric static char buf[64];
592d1ece852Seric
593d1ece852Seric buf[0] = '\0';
594d1ece852Seric
595d1ece852Seric switch (flags & IO_RW) {
596d1ece852Seric case 0:
597eb54aa8aSgilles (void)strlcat(buf, "rw", sizeof buf);
598d1ece852Seric break;
599d1ece852Seric case IO_READ:
600eb54aa8aSgilles (void)strlcat(buf, "R", sizeof buf);
601d1ece852Seric break;
602d1ece852Seric case IO_WRITE:
603eb54aa8aSgilles (void)strlcat(buf, "W", sizeof buf);
604d1ece852Seric break;
605d1ece852Seric case IO_RW:
606eb54aa8aSgilles (void)strlcat(buf, "RW", sizeof buf);
607d1ece852Seric break;
608d1ece852Seric }
609d1ece852Seric
610d1ece852Seric if (flags & IO_PAUSE_IN)
611eb54aa8aSgilles (void)strlcat(buf, ",F_PI", sizeof buf);
612d1ece852Seric if (flags & IO_PAUSE_OUT)
613eb54aa8aSgilles (void)strlcat(buf, ",F_PO", sizeof buf);
614d1ece852Seric
615d1ece852Seric return buf;
616d1ece852Seric }
617d1ece852Seric
618d1ece852Seric const char*
io_evstr(short ev)619d1ece852Seric io_evstr(short ev)
620d1ece852Seric {
621d1ece852Seric static char buf[64];
622d1ece852Seric char buf2[16];
623d1ece852Seric int n;
624d1ece852Seric
625d1ece852Seric n = 0;
626d1ece852Seric buf[0] = '\0';
627d1ece852Seric
628d1ece852Seric if (ev == 0) {
629eb54aa8aSgilles (void)strlcat(buf, "<NONE>", sizeof(buf));
630d1ece852Seric return buf;
631d1ece852Seric }
632d1ece852Seric
633d1ece852Seric if (ev & EV_TIMEOUT) {
634eb54aa8aSgilles (void)strlcat(buf, "EV_TIMEOUT", sizeof(buf));
635d1ece852Seric ev &= ~EV_TIMEOUT;
636d1ece852Seric n++;
637d1ece852Seric }
638d1ece852Seric
639d1ece852Seric if (ev & EV_READ) {
640d1ece852Seric if (n)
641eb54aa8aSgilles (void)strlcat(buf, "|", sizeof(buf));
642eb54aa8aSgilles (void)strlcat(buf, "EV_READ", sizeof(buf));
643d1ece852Seric ev &= ~EV_READ;
644d1ece852Seric n++;
645d1ece852Seric }
646d1ece852Seric
647d1ece852Seric if (ev & EV_WRITE) {
648d1ece852Seric if (n)
649eb54aa8aSgilles (void)strlcat(buf, "|", sizeof(buf));
650eb54aa8aSgilles (void)strlcat(buf, "EV_WRITE", sizeof(buf));
651d1ece852Seric ev &= ~EV_WRITE;
652d1ece852Seric n++;
653d1ece852Seric }
654d1ece852Seric
655d1ece852Seric if (ev & EV_SIGNAL) {
656d1ece852Seric if (n)
657eb54aa8aSgilles (void)strlcat(buf, "|", sizeof(buf));
658eb54aa8aSgilles (void)strlcat(buf, "EV_SIGNAL", sizeof(buf));
659d1ece852Seric ev &= ~EV_SIGNAL;
660d1ece852Seric n++;
661d1ece852Seric }
662d1ece852Seric
663d1ece852Seric if (ev) {
664d1ece852Seric if (n)
665eb54aa8aSgilles (void)strlcat(buf, "|", sizeof(buf));
666eb54aa8aSgilles (void)strlcat(buf, "EV_?=0x", sizeof(buf));
667eb54aa8aSgilles (void)snprintf(buf2, sizeof(buf2), "%hx", ev);
668eb54aa8aSgilles (void)strlcat(buf, buf2, sizeof(buf));
669d1ece852Seric }
670d1ece852Seric
671d1ece852Seric return buf;
672d1ece852Seric }
673d1ece852Seric
674d1ece852Seric void
io_dispatch(int fd,short ev,void * humppa)675d1ece852Seric io_dispatch(int fd, short ev, void *humppa)
676d1ece852Seric {
677d1ece852Seric struct io *io = humppa;
678d1ece852Seric size_t w;
679d1ece852Seric ssize_t n;
68065c4fdfbSgilles int saved_errno;
681d1ece852Seric
682d1ece852Seric io_frame_enter("io_dispatch", io, ev);
683d1ece852Seric
684d1ece852Seric if (ev == EV_TIMEOUT) {
685d1ece852Seric io_callback(io, IO_TIMEOUT);
686d1ece852Seric goto leave;
687d1ece852Seric }
688d1ece852Seric
689d1ece852Seric if (ev & EV_WRITE && (w = io_queued(io))) {
69005afcc4dSeric if ((n = iobuf_write(&io->iobuf, io->sock)) < 0) {
691a80802bcSeric if (n == IOBUF_WANT_WRITE) /* kqueue bug? */
692a80802bcSeric goto read;
69365c4fdfbSgilles if (n == IOBUF_CLOSED)
69465c4fdfbSgilles io_callback(io, IO_DISCONNECTED);
69565c4fdfbSgilles else {
69665c4fdfbSgilles saved_errno = errno;
69765c4fdfbSgilles io->error = strerror(errno);
69865c4fdfbSgilles errno = saved_errno;
69965c4fdfbSgilles io_callback(io, IO_ERROR);
70065c4fdfbSgilles }
701d1ece852Seric goto leave;
702d1ece852Seric }
703d1ece852Seric if (w > io->lowat && w - n <= io->lowat)
704d1ece852Seric io_callback(io, IO_LOWAT);
705d1ece852Seric }
706a80802bcSeric read:
707d1ece852Seric
708d1ece852Seric if (ev & EV_READ) {
70905afcc4dSeric iobuf_normalize(&io->iobuf);
71005afcc4dSeric if ((n = iobuf_read(&io->iobuf, io->sock)) < 0) {
71165c4fdfbSgilles if (n == IOBUF_CLOSED)
71265c4fdfbSgilles io_callback(io, IO_DISCONNECTED);
71365c4fdfbSgilles else {
71465c4fdfbSgilles saved_errno = errno;
71565c4fdfbSgilles io->error = strerror(errno);
71665c4fdfbSgilles errno = saved_errno;
71765c4fdfbSgilles io_callback(io, IO_ERROR);
71865c4fdfbSgilles }
719d1ece852Seric goto leave;
720d1ece852Seric }
721d1ece852Seric if (n)
722d1ece852Seric io_callback(io, IO_DATAIN);
723d1ece852Seric }
724d1ece852Seric
725d1ece852Seric leave:
726d1ece852Seric io_frame_leave(io);
727d1ece852Seric }
728d1ece852Seric
729d1ece852Seric void
io_callback(struct io * io,int evt)730d1ece852Seric io_callback(struct io *io, int evt)
731d1ece852Seric {
732b556a8d3Seric io->cb(io, evt, io->arg);
733d1ece852Seric }
734d1ece852Seric
735d1ece852Seric int
io_connect(struct io * io,const struct sockaddr * sa,const struct sockaddr * bsa)7362c1d98b8Seric io_connect(struct io *io, const struct sockaddr *sa, const struct sockaddr *bsa)
737d1ece852Seric {
738d1ece852Seric int sock, errno_save;
739d1ece852Seric
740d1ece852Seric if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) == -1)
741d1ece852Seric goto fail;
742d1ece852Seric
743907c4b99Skrw io_set_nonblocking(sock);
744907c4b99Skrw io_set_nolinger(sock);
745d1ece852Seric
7462c1d98b8Seric if (bsa && bind(sock, bsa, bsa->sa_len) == -1)
7472c1d98b8Seric goto fail;
7482c1d98b8Seric
749d1ece852Seric if (connect(sock, sa, sa->sa_len) == -1)
750d1ece852Seric if (errno != EINPROGRESS)
751d1ece852Seric goto fail;
752d1ece852Seric
753d1ece852Seric io->sock = sock;
754d1ece852Seric io_reset(io, EV_WRITE, io_dispatch_connect);
755d1ece852Seric
756d1ece852Seric return (sock);
757d1ece852Seric
758d1ece852Seric fail:
759d1ece852Seric if (sock != -1) {
760d1ece852Seric errno_save = errno;
761d1ece852Seric close(sock);
762d1ece852Seric errno = errno_save;
76365c4fdfbSgilles io->error = strerror(errno);
764d1ece852Seric }
765d1ece852Seric return (-1);
766d1ece852Seric }
767d1ece852Seric
768d1ece852Seric void
io_dispatch_connect(int fd,short ev,void * humppa)769d1ece852Seric io_dispatch_connect(int fd, short ev, void *humppa)
770d1ece852Seric {
771d1ece852Seric struct io *io = humppa;
772299c4efeSeric int r, e;
773299c4efeSeric socklen_t sl;
774d1ece852Seric
775d1ece852Seric io_frame_enter("io_dispatch_connect", io, ev);
776d1ece852Seric
777d1ece852Seric if (ev == EV_TIMEOUT) {
778d1ece852Seric close(fd);
779d1ece852Seric io->sock = -1;
780d1ece852Seric io_callback(io, IO_TIMEOUT);
781d1ece852Seric } else {
782299c4efeSeric sl = sizeof(e);
783299c4efeSeric r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &e, &sl);
784299c4efeSeric if (r == -1) {
785ff01b044Seric log_warn("io_dispatch_connect: getsockopt");
786299c4efeSeric e = errno;
787299c4efeSeric }
788299c4efeSeric if (e) {
789299c4efeSeric close(fd);
790299c4efeSeric io->sock = -1;
791299c4efeSeric io->error = strerror(e);
792299c4efeSeric io_callback(io, e == ETIMEDOUT ? IO_TIMEOUT : IO_ERROR);
793299c4efeSeric }
794299c4efeSeric else {
795d1ece852Seric io->state = IO_STATE_UP;
796d1ece852Seric io_callback(io, IO_CONNECTED);
797d1ece852Seric }
798299c4efeSeric }
799d1ece852Seric
800d1ece852Seric io_frame_leave(io);
801d1ece852Seric }
802d1ece852Seric
8039ac7cdfdSeric #ifdef IO_TLS
804d1ece852Seric int
io_connect_tls(struct io * io,struct tls * tls,const char * hostname)805eed85469Seric io_connect_tls(struct io *io, struct tls *tls, const char *hostname)
806d1ece852Seric {
807d1ece852Seric int mode;
808d1ece852Seric
809d1ece852Seric mode = io->flags & IO_RW;
810eed85469Seric if (mode != IO_WRITE)
811ff01b044Seric fatalx("io_connect_tls: expect IO_WRITE mode");
812d1ece852Seric
8139ac7cdfdSeric if (io->tls)
814ff01b044Seric fatalx("io_connect_tls: TLS already started");
815eed85469Seric
816c11a901bSeric if (tls_connect_socket(tls, io->sock, hostname) == -1) {
817c11a901bSeric io->error = tls_error(tls);
818c11a901bSeric return (-1);
819eed85469Seric }
820eed85469Seric
8219ac7cdfdSeric io->tls = tls;
8229ac7cdfdSeric io->state = IO_STATE_CONNECT_TLS;
823c11a901bSeric io_reset(io, EV_READ|EV_WRITE, io_dispatch_handshake_tls);
824d1ece852Seric
825d1ece852Seric return (0);
826d1ece852Seric }
827d1ece852Seric
828eed85469Seric int
io_accept_tls(struct io * io,struct tls * tls)829eed85469Seric io_accept_tls(struct io *io, struct tls *tls)
830eed85469Seric {
831eed85469Seric int mode;
832eed85469Seric
833eed85469Seric mode = io->flags & IO_RW;
834eed85469Seric if (mode != IO_READ)
835ff01b044Seric fatalx("io_accept_tls: expect IO_READ mode");
836eed85469Seric
837eed85469Seric if (io->tls)
838ff01b044Seric fatalx("io_accept_tls: TLS already started");
839c11a901bSeric
840c11a901bSeric if (tls_accept_socket(tls, &io->tls, io->sock) == -1) {
841c11a901bSeric io->error = tls_error(tls);
842c11a901bSeric return (-1);
843c11a901bSeric }
844c11a901bSeric
845eed85469Seric io->state = IO_STATE_ACCEPT_TLS;
846c11a901bSeric io_reset(io, EV_READ|EV_WRITE, io_dispatch_handshake_tls);
847eed85469Seric
848eed85469Seric return (0);
849eed85469Seric }
850eed85469Seric
851eed85469Seric void
io_dispatch_handshake_tls(int fd,short event,void * humppa)852eed85469Seric io_dispatch_handshake_tls(int fd, short event, void *humppa)
853eed85469Seric {
854eed85469Seric struct io *io = humppa;
855eed85469Seric int ret;
856eed85469Seric
857eed85469Seric io_frame_enter("io_dispatch_handshake_tls", io, event);
858eed85469Seric
859eed85469Seric if (event == EV_TIMEOUT) {
860eed85469Seric io_callback(io, IO_TIMEOUT);
861eed85469Seric goto leave;
862eed85469Seric }
863eed85469Seric
864eed85469Seric if ((ret = tls_handshake(io->tls)) == 0) {
865eed85469Seric io->state = IO_STATE_UP;
866eed85469Seric io_callback(io, IO_TLSREADY);
867eed85469Seric goto leave;
868eed85469Seric }
869eed85469Seric if (ret == TLS_WANT_POLLIN)
870eed85469Seric io_reset(io, EV_READ, io_dispatch_handshake_tls);
871eed85469Seric else if (ret == TLS_WANT_POLLOUT)
872eed85469Seric io_reset(io, EV_WRITE, io_dispatch_handshake_tls);
873eed85469Seric else {
874eed85469Seric io->error = tls_error(io->tls);
875eed85469Seric io_callback(io, IO_ERROR);
876eed85469Seric }
877eed85469Seric
878eed85469Seric leave:
879eed85469Seric io_frame_leave(io);
880eed85469Seric return;
881eed85469Seric }
882eed85469Seric
883d1ece852Seric void
io_dispatch_read_tls(int fd,short event,void * humppa)8849ac7cdfdSeric io_dispatch_read_tls(int fd, short event, void *humppa)
885d1ece852Seric {
886d1ece852Seric struct io *io = humppa;
887eed85469Seric int n;
888d1ece852Seric
8899ac7cdfdSeric io_frame_enter("io_dispatch_read_tls", io, event);
890d1ece852Seric
891d1ece852Seric if (event == EV_TIMEOUT) {
892d1ece852Seric io_callback(io, IO_TIMEOUT);
893d1ece852Seric goto leave;
894d1ece852Seric }
895d1ece852Seric
896b0e8ad58Seric again:
89705afcc4dSeric iobuf_normalize(&io->iobuf);
898eed85469Seric switch ((n = iobuf_read_tls(&io->iobuf, io->tls))) {
899d1ece852Seric case IOBUF_WANT_READ:
9009ac7cdfdSeric io_reset(io, EV_READ, io_dispatch_read_tls);
901d1ece852Seric break;
902d1ece852Seric case IOBUF_WANT_WRITE:
9039ac7cdfdSeric io_reset(io, EV_WRITE, io_dispatch_read_tls);
904d1ece852Seric break;
905d1ece852Seric case IOBUF_CLOSED:
906d1ece852Seric io_callback(io, IO_DISCONNECTED);
907d1ece852Seric break;
908d1ece852Seric case IOBUF_ERROR:
909eed85469Seric io->error = tls_error(io->tls);
910d1ece852Seric io_callback(io, IO_ERROR);
911d1ece852Seric break;
912d1ece852Seric default:
9139ac7cdfdSeric io_debug("io_dispatch_read_tls(...) -> r=%d\n", n);
914d1ece852Seric io_callback(io, IO_DATAIN);
915eed85469Seric if (current == io && IO_READING(io))
916b0e8ad58Seric goto again;
917d1ece852Seric }
918d1ece852Seric
919d1ece852Seric leave:
920d1ece852Seric io_frame_leave(io);
921d1ece852Seric }
922d1ece852Seric
923d1ece852Seric void
io_dispatch_write_tls(int fd,short event,void * humppa)9249ac7cdfdSeric io_dispatch_write_tls(int fd, short event, void *humppa)
925d1ece852Seric {
926d1ece852Seric struct io *io = humppa;
927eed85469Seric int n;
928d1ece852Seric size_t w2, w;
929d1ece852Seric
9309ac7cdfdSeric io_frame_enter("io_dispatch_write_tls", io, event);
931d1ece852Seric
932d1ece852Seric if (event == EV_TIMEOUT) {
933d1ece852Seric io_callback(io, IO_TIMEOUT);
934d1ece852Seric goto leave;
935d1ece852Seric }
936d1ece852Seric
937d1ece852Seric w = io_queued(io);
938eed85469Seric switch ((n = iobuf_write_tls(&io->iobuf, io->tls))) {
939d1ece852Seric case IOBUF_WANT_READ:
9409ac7cdfdSeric io_reset(io, EV_READ, io_dispatch_write_tls);
941d1ece852Seric break;
942d1ece852Seric case IOBUF_WANT_WRITE:
9439ac7cdfdSeric io_reset(io, EV_WRITE, io_dispatch_write_tls);
944d1ece852Seric break;
945d1ece852Seric case IOBUF_CLOSED:
946d1ece852Seric io_callback(io, IO_DISCONNECTED);
947d1ece852Seric break;
948d1ece852Seric case IOBUF_ERROR:
949eed85469Seric io->error = tls_error(io->tls);
950d1ece852Seric io_callback(io, IO_ERROR);
951d1ece852Seric break;
952d1ece852Seric default:
9539ac7cdfdSeric io_debug("io_dispatch_write_tls(...) -> w=%d\n", n);
954d1ece852Seric w2 = io_queued(io);
955d1ece852Seric if (w > io->lowat && w2 <= io->lowat)
956d1ece852Seric io_callback(io, IO_LOWAT);
957d1ece852Seric break;
958d1ece852Seric }
959d1ece852Seric
960d1ece852Seric leave:
961d1ece852Seric io_frame_leave(io);
962d1ece852Seric }
963d1ece852Seric
964d1ece852Seric void
io_reload_tls(struct io * io)9659ac7cdfdSeric io_reload_tls(struct io *io)
966d1ece852Seric {
967c11a901bSeric if (io->state != IO_STATE_UP)
968ff01b044Seric fatalx("io_reload_tls: bad state");
969c11a901bSeric
970c11a901bSeric if (IO_READING(io) && !(io->flags & IO_PAUSE_IN)) {
971c11a901bSeric io_reset(io, EV_READ, io_dispatch_read_tls);
972c11a901bSeric return;
973d1ece852Seric }
974d1ece852Seric
975c11a901bSeric if (IO_WRITING(io) && !(io->flags & IO_PAUSE_OUT) && io_queued(io)) {
976c11a901bSeric io_reset(io, EV_WRITE, io_dispatch_write_tls);
977c11a901bSeric return;
978c11a901bSeric }
979c11a901bSeric
980c11a901bSeric /* paused */
981d1ece852Seric }
982d1ece852Seric
9839ac7cdfdSeric #endif /* IO_TLS */
984