Blame


1 ce062d50 2019-08-21 martijn /* $OpenBSD: ioev.c,v 1.42 2019/06/12 17:42:53 eric Exp $ */
2 ce062d50 2019-08-21 martijn /*
3 ce062d50 2019-08-21 martijn * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
4 ce062d50 2019-08-21 martijn *
5 ce062d50 2019-08-21 martijn * Permission to use, copy, modify, and distribute this software for any
6 ce062d50 2019-08-21 martijn * purpose with or without fee is hereby granted, provided that the above
7 ce062d50 2019-08-21 martijn * copyright notice and this permission notice appear in all copies.
8 ce062d50 2019-08-21 martijn *
9 ce062d50 2019-08-21 martijn * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 ce062d50 2019-08-21 martijn * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 ce062d50 2019-08-21 martijn * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 ce062d50 2019-08-21 martijn * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 ce062d50 2019-08-21 martijn * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 ce062d50 2019-08-21 martijn * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 ce062d50 2019-08-21 martijn * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 ce062d50 2019-08-21 martijn */
17 957c2372 2019-11-14 martijn #define _GNU_SOURCE 1
18 13f08f83 2019-11-14 martijn #define _BSD_SOURCE 1
19 ce062d50 2019-08-21 martijn
20 ce062d50 2019-08-21 martijn #include <sys/types.h>
21 ce062d50 2019-08-21 martijn #include <sys/queue.h>
22 ce062d50 2019-08-21 martijn #include <sys/socket.h>
23 ce062d50 2019-08-21 martijn
24 ce062d50 2019-08-21 martijn #include <err.h>
25 ce062d50 2019-08-21 martijn #include <errno.h>
26 ce062d50 2019-08-21 martijn #include <event.h>
27 ce062d50 2019-08-21 martijn #include <fcntl.h>
28 ce062d50 2019-08-21 martijn #include <inttypes.h>
29 ce062d50 2019-08-21 martijn #include <stdlib.h>
30 ce062d50 2019-08-21 martijn #include <string.h>
31 ce062d50 2019-08-21 martijn #include <stdio.h>
32 ce062d50 2019-08-21 martijn #include <unistd.h>
33 ce062d50 2019-08-21 martijn
34 957c2372 2019-11-14 martijn #include "openbsd-compat.h"
35 ce062d50 2019-08-21 martijn #include "ioev.h"
36 ce062d50 2019-08-21 martijn #include "iobuf.h"
37 ce062d50 2019-08-21 martijn
38 ce062d50 2019-08-21 martijn #ifdef IO_TLS
39 ce062d50 2019-08-21 martijn #include <openssl/err.h>
40 ce062d50 2019-08-21 martijn #include <openssl/ssl.h>
41 ce062d50 2019-08-21 martijn #endif
42 ce062d50 2019-08-21 martijn
43 ce062d50 2019-08-21 martijn enum {
44 ce062d50 2019-08-21 martijn IO_STATE_NONE,
45 ce062d50 2019-08-21 martijn IO_STATE_CONNECT,
46 ce062d50 2019-08-21 martijn IO_STATE_CONNECT_TLS,
47 ce062d50 2019-08-21 martijn IO_STATE_ACCEPT_TLS,
48 ce062d50 2019-08-21 martijn IO_STATE_UP,
49 ce062d50 2019-08-21 martijn
50 ce062d50 2019-08-21 martijn IO_STATE_MAX,
51 ce062d50 2019-08-21 martijn };
52 ce062d50 2019-08-21 martijn
53 ce062d50 2019-08-21 martijn #define IO_PAUSE_IN IO_IN
54 ce062d50 2019-08-21 martijn #define IO_PAUSE_OUT IO_OUT
55 ce062d50 2019-08-21 martijn #define IO_READ 0x04
56 ce062d50 2019-08-21 martijn #define IO_WRITE 0x08
57 ce062d50 2019-08-21 martijn #define IO_RW (IO_READ | IO_WRITE)
58 ce062d50 2019-08-21 martijn #define IO_RESET 0x10 /* internal */
59 ce062d50 2019-08-21 martijn #define IO_HELD 0x20 /* internal */
60 ce062d50 2019-08-21 martijn
61 ce062d50 2019-08-21 martijn struct io {
62 ce062d50 2019-08-21 martijn int sock;
63 ce062d50 2019-08-21 martijn void *arg;
64 ce062d50 2019-08-21 martijn void (*cb)(struct io*, int, void *);
65 ce062d50 2019-08-21 martijn struct iobuf iobuf;
66 ce062d50 2019-08-21 martijn size_t lowat;
67 ce062d50 2019-08-21 martijn int timeout;
68 ce062d50 2019-08-21 martijn int flags;
69 ce062d50 2019-08-21 martijn int state;
70 ce062d50 2019-08-21 martijn struct event ev;
71 ce062d50 2019-08-21 martijn void *tls;
72 ce062d50 2019-08-21 martijn const char *error; /* only valid immediately on callback */
73 ce062d50 2019-08-21 martijn };
74 ce062d50 2019-08-21 martijn
75 ce062d50 2019-08-21 martijn const char* io_strflags(int);
76 ce062d50 2019-08-21 martijn const char* io_evstr(short);
77 ce062d50 2019-08-21 martijn
78 ce062d50 2019-08-21 martijn void _io_init(void);
79 ce062d50 2019-08-21 martijn void io_hold(struct io *);
80 ce062d50 2019-08-21 martijn void io_release(struct io *);
81 ce062d50 2019-08-21 martijn void io_callback(struct io*, int);
82 ce062d50 2019-08-21 martijn void io_dispatch(int, short, void *);
83 ce062d50 2019-08-21 martijn void io_dispatch_connect(int, short, void *);
84 ce062d50 2019-08-21 martijn size_t io_pending(struct io *);
85 ce062d50 2019-08-21 martijn size_t io_queued(struct io*);
86 ce062d50 2019-08-21 martijn void io_reset(struct io *, short, void (*)(int, short, void*));
87 ce062d50 2019-08-21 martijn void io_frame_enter(const char *, struct io *, int);
88 ce062d50 2019-08-21 martijn void io_frame_leave(struct io *);
89 ce062d50 2019-08-21 martijn
90 ce062d50 2019-08-21 martijn #ifdef IO_TLS
91 ce062d50 2019-08-21 martijn void ssl_error(const char *); /* XXX external */
92 ce062d50 2019-08-21 martijn
93 ce062d50 2019-08-21 martijn static const char* io_tls_error(void);
94 ce062d50 2019-08-21 martijn void io_dispatch_accept_tls(int, short, void *);
95 ce062d50 2019-08-21 martijn void io_dispatch_connect_tls(int, short, void *);
96 ce062d50 2019-08-21 martijn void io_dispatch_read_tls(int, short, void *);
97 ce062d50 2019-08-21 martijn void io_dispatch_write_tls(int, short, void *);
98 ce062d50 2019-08-21 martijn void io_reload_tls(struct io *io);
99 ce062d50 2019-08-21 martijn #endif
100 ce062d50 2019-08-21 martijn
101 ce062d50 2019-08-21 martijn static struct io *current = NULL;
102 ce062d50 2019-08-21 martijn static uint64_t frame = 0;
103 ce062d50 2019-08-21 martijn static int _io_debug = 0;
104 ce062d50 2019-08-21 martijn
105 7bc4d7c9 2025-01-26 martijn #define io_debug(args...) do { if (_io_debug) printf(args); } while(0)
106 ce062d50 2019-08-21 martijn
107 ce062d50 2019-08-21 martijn
108 ce062d50 2019-08-21 martijn const char*
109 ce062d50 2019-08-21 martijn io_strio(struct io *io)
110 ce062d50 2019-08-21 martijn {
111 ce062d50 2019-08-21 martijn static char buf[128];
112 ce062d50 2019-08-21 martijn char ssl[128];
113 ce062d50 2019-08-21 martijn
114 ce062d50 2019-08-21 martijn ssl[0] = '\0';
115 ce062d50 2019-08-21 martijn #ifdef IO_TLS
116 ce062d50 2019-08-21 martijn if (io->tls) {
117 ce062d50 2019-08-21 martijn (void)snprintf(ssl, sizeof ssl, " tls=%s:%s:%d",
118 ce062d50 2019-08-21 martijn SSL_get_version(io->tls),
119 ce062d50 2019-08-21 martijn SSL_get_cipher_name(io->tls),
120 ce062d50 2019-08-21 martijn SSL_get_cipher_bits(io->tls, NULL));
121 ce062d50 2019-08-21 martijn }
122 ce062d50 2019-08-21 martijn #endif
123 ce062d50 2019-08-21 martijn
124 ce062d50 2019-08-21 martijn (void)snprintf(buf, sizeof buf,
125 ce062d50 2019-08-21 martijn "<io:%p fd=%d to=%d fl=%s%s ib=%zu ob=%zu>",
126 ce062d50 2019-08-21 martijn io, io->sock, io->timeout, io_strflags(io->flags), ssl,
127 ce062d50 2019-08-21 martijn io_pending(io), io_queued(io));
128 ce062d50 2019-08-21 martijn
129 ce062d50 2019-08-21 martijn return (buf);
130 ce062d50 2019-08-21 martijn }
131 ce062d50 2019-08-21 martijn
132 ce062d50 2019-08-21 martijn #define CASE(x) case x : return #x
133 ce062d50 2019-08-21 martijn
134 ce062d50 2019-08-21 martijn const char*
135 ce062d50 2019-08-21 martijn io_strevent(int evt)
136 ce062d50 2019-08-21 martijn {
137 ce062d50 2019-08-21 martijn static char buf[32];
138 ce062d50 2019-08-21 martijn
139 ce062d50 2019-08-21 martijn switch (evt) {
140 ce062d50 2019-08-21 martijn CASE(IO_CONNECTED);
141 ce062d50 2019-08-21 martijn CASE(IO_TLSREADY);
142 ce062d50 2019-08-21 martijn CASE(IO_DATAIN);
143 ce062d50 2019-08-21 martijn CASE(IO_LOWAT);
144 ce062d50 2019-08-21 martijn CASE(IO_DISCONNECTED);
145 ce062d50 2019-08-21 martijn CASE(IO_TIMEOUT);
146 ce062d50 2019-08-21 martijn CASE(IO_ERROR);
147 ce062d50 2019-08-21 martijn default:
148 ce062d50 2019-08-21 martijn (void)snprintf(buf, sizeof(buf), "IO_? %d", evt);
149 ce062d50 2019-08-21 martijn return buf;
150 ce062d50 2019-08-21 martijn }
151 ce062d50 2019-08-21 martijn }
152 ce062d50 2019-08-21 martijn
153 ce062d50 2019-08-21 martijn void
154 ce062d50 2019-08-21 martijn io_set_nonblocking(int fd)
155 ce062d50 2019-08-21 martijn {
156 ce062d50 2019-08-21 martijn int flags;
157 ce062d50 2019-08-21 martijn
158 ce062d50 2019-08-21 martijn if ((flags = fcntl(fd, F_GETFL)) == -1)
159 ce062d50 2019-08-21 martijn err(1, "io_set_blocking:fcntl(F_GETFL)");
160 ce062d50 2019-08-21 martijn
161 ce062d50 2019-08-21 martijn flags |= O_NONBLOCK;
162 ce062d50 2019-08-21 martijn
163 ce062d50 2019-08-21 martijn if (fcntl(fd, F_SETFL, flags) == -1)
164 ce062d50 2019-08-21 martijn err(1, "io_set_blocking:fcntl(F_SETFL)");
165 ce062d50 2019-08-21 martijn }
166 ce062d50 2019-08-21 martijn
167 ce062d50 2019-08-21 martijn void
168 ce062d50 2019-08-21 martijn io_set_nolinger(int fd)
169 ce062d50 2019-08-21 martijn {
170 ce062d50 2019-08-21 martijn struct linger l;
171 ce062d50 2019-08-21 martijn
172 ce062d50 2019-08-21 martijn memset(&l, 0, sizeof(l));
173 ce062d50 2019-08-21 martijn if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) == -1)
174 ce062d50 2019-08-21 martijn err(1, "io_set_linger:setsockopt()");
175 ce062d50 2019-08-21 martijn }
176 ce062d50 2019-08-21 martijn
177 ce062d50 2019-08-21 martijn /*
178 ce062d50 2019-08-21 martijn * Event framing must not rely on an io pointer to refer to the "same" io
179 ce062d50 2019-08-21 martijn * throughout the frame, because this is not always the case:
180 ce062d50 2019-08-21 martijn *
181 ce062d50 2019-08-21 martijn * 1) enter(addr0) -> free(addr0) -> leave(addr0) = SEGV
182 ce062d50 2019-08-21 martijn * 2) enter(addr0) -> free(addr0) -> malloc == addr0 -> leave(addr0) = BAD!
183 ce062d50 2019-08-21 martijn *
184 ce062d50 2019-08-21 martijn * In both case, the problem is that the io is freed in the callback, so
185 ce062d50 2019-08-21 martijn * the pointer becomes invalid. If that happens, the user is required to
186 ce062d50 2019-08-21 martijn * call io_clear, so we can adapt the frame state there.
187 ce062d50 2019-08-21 martijn */
188 ce062d50 2019-08-21 martijn void
189 ce062d50 2019-08-21 martijn io_frame_enter(const char *where, struct io *io, int ev)
190 ce062d50 2019-08-21 martijn {
191 ce062d50 2019-08-21 martijn io_debug("\n=== %" PRIu64 " ===\n"
192 ce062d50 2019-08-21 martijn "io_frame_enter(%s, %s, %s)\n",
193 ce062d50 2019-08-21 martijn frame, where, io_evstr(ev), io_strio(io));
194 ce062d50 2019-08-21 martijn
195 ce062d50 2019-08-21 martijn if (current)
196 ce062d50 2019-08-21 martijn errx(1, "io_frame_enter: interleaved frames");
197 ce062d50 2019-08-21 martijn
198 ce062d50 2019-08-21 martijn current = io;
199 ce062d50 2019-08-21 martijn
200 ce062d50 2019-08-21 martijn io_hold(io);
201 ce062d50 2019-08-21 martijn }
202 ce062d50 2019-08-21 martijn
203 ce062d50 2019-08-21 martijn void
204 ce062d50 2019-08-21 martijn io_frame_leave(struct io *io)
205 ce062d50 2019-08-21 martijn {
206 ce062d50 2019-08-21 martijn io_debug("io_frame_leave(%" PRIu64 ")\n", frame);
207 ce062d50 2019-08-21 martijn
208 ce062d50 2019-08-21 martijn if (current && current != io)
209 ce062d50 2019-08-21 martijn errx(1, "io_frame_leave: io mismatch");
210 ce062d50 2019-08-21 martijn
211 ce062d50 2019-08-21 martijn /* io has been cleared */
212 ce062d50 2019-08-21 martijn if (current == NULL)
213 ce062d50 2019-08-21 martijn goto done;
214 ce062d50 2019-08-21 martijn
215 ce062d50 2019-08-21 martijn /* TODO: There is a possible optimization there:
216 ce062d50 2019-08-21 martijn * In a typical half-duplex request/response scenario,
217 ce062d50 2019-08-21 martijn * the io is waiting to read a request, and when done, it queues
218 ce062d50 2019-08-21 martijn * the response in the output buffer and goes to write mode.
219 ce062d50 2019-08-21 martijn * There, the write event is set and will be triggered in the next
220 ce062d50 2019-08-21 martijn * event frame. In most case, the write call could be done
221 ce062d50 2019-08-21 martijn * immediately as part of the last read frame, thus avoiding to go
222 ce062d50 2019-08-21 martijn * through the event loop machinery. So, as an optimisation, we
223 ce062d50 2019-08-21 martijn * could detect that case here and force an event dispatching.
224 ce062d50 2019-08-21 martijn */
225 ce062d50 2019-08-21 martijn
226 ce062d50 2019-08-21 martijn /* Reload the io if it has not been reset already. */
227 ce062d50 2019-08-21 martijn io_release(io);
228 ce062d50 2019-08-21 martijn current = NULL;
229 ce062d50 2019-08-21 martijn done:
230 ce062d50 2019-08-21 martijn io_debug("=== /%" PRIu64 "\n", frame);
231 ce062d50 2019-08-21 martijn
232 ce062d50 2019-08-21 martijn frame += 1;
233 ce062d50 2019-08-21 martijn }
234 ce062d50 2019-08-21 martijn
235 ce062d50 2019-08-21 martijn void
236 5afa0465 2024-01-29 martijn _io_init(void)
237 ce062d50 2019-08-21 martijn {
238 ce062d50 2019-08-21 martijn static int init = 0;
239 ce062d50 2019-08-21 martijn
240 ce062d50 2019-08-21 martijn if (init)
241 ce062d50 2019-08-21 martijn return;
242 ce062d50 2019-08-21 martijn
243 ce062d50 2019-08-21 martijn init = 1;
244 ce062d50 2019-08-21 martijn _io_debug = getenv("IO_DEBUG") != NULL;
245 ce062d50 2019-08-21 martijn }
246 ce062d50 2019-08-21 martijn
247 ce062d50 2019-08-21 martijn struct io *
248 ce062d50 2019-08-21 martijn io_new(void)
249 ce062d50 2019-08-21 martijn {
250 ce062d50 2019-08-21 martijn struct io *io;
251 ce062d50 2019-08-21 martijn
252 ce062d50 2019-08-21 martijn _io_init();
253 ce062d50 2019-08-21 martijn
254 ce062d50 2019-08-21 martijn if ((io = calloc(1, sizeof(*io))) == NULL)
255 ce062d50 2019-08-21 martijn return NULL;
256 ce062d50 2019-08-21 martijn
257 ce062d50 2019-08-21 martijn io->sock = -1;
258 ce062d50 2019-08-21 martijn io->timeout = -1;
259 ce062d50 2019-08-21 martijn
260 ce062d50 2019-08-21 martijn if (iobuf_init(&io->iobuf, 0, 0) == -1) {
261 ce062d50 2019-08-21 martijn free(io);
262 ce062d50 2019-08-21 martijn return NULL;
263 ce062d50 2019-08-21 martijn }
264 ce062d50 2019-08-21 martijn
265 ce062d50 2019-08-21 martijn return io;
266 ce062d50 2019-08-21 martijn }
267 ce062d50 2019-08-21 martijn
268 ce062d50 2019-08-21 martijn void
269 ce062d50 2019-08-21 martijn io_free(struct io *io)
270 ce062d50 2019-08-21 martijn {
271 ce062d50 2019-08-21 martijn io_debug("io_clear(%p)\n", io);
272 ce062d50 2019-08-21 martijn
273 ce062d50 2019-08-21 martijn /* the current io is virtually dead */
274 ce062d50 2019-08-21 martijn if (io == current)
275 ce062d50 2019-08-21 martijn current = NULL;
276 ce062d50 2019-08-21 martijn
277 ce062d50 2019-08-21 martijn #ifdef IO_TLS
278 ce062d50 2019-08-21 martijn SSL_free(io->tls);
279 ce062d50 2019-08-21 martijn io->tls = NULL;
280 ce062d50 2019-08-21 martijn #endif
281 ce062d50 2019-08-21 martijn
282 ce062d50 2019-08-21 martijn if (event_initialized(&io->ev))
283 ce062d50 2019-08-21 martijn event_del(&io->ev);
284 ce062d50 2019-08-21 martijn if (io->sock != -1) {
285 ce062d50 2019-08-21 martijn close(io->sock);
286 ce062d50 2019-08-21 martijn io->sock = -1;
287 ce062d50 2019-08-21 martijn }
288 ce062d50 2019-08-21 martijn
289 ce062d50 2019-08-21 martijn iobuf_clear(&io->iobuf);
290 ce062d50 2019-08-21 martijn free(io);
291 ce062d50 2019-08-21 martijn }
292 ce062d50 2019-08-21 martijn
293 ce062d50 2019-08-21 martijn void
294 ce062d50 2019-08-21 martijn io_hold(struct io *io)
295 ce062d50 2019-08-21 martijn {
296 ce062d50 2019-08-21 martijn io_debug("io_enter(%p)\n", io);
297 ce062d50 2019-08-21 martijn
298 ce062d50 2019-08-21 martijn if (io->flags & IO_HELD)
299 ce062d50 2019-08-21 martijn errx(1, "io_hold: io is already held");
300 ce062d50 2019-08-21 martijn
301 ce062d50 2019-08-21 martijn io->flags &= ~IO_RESET;
302 ce062d50 2019-08-21 martijn io->flags |= IO_HELD;
303 ce062d50 2019-08-21 martijn }
304 ce062d50 2019-08-21 martijn
305 ce062d50 2019-08-21 martijn void
306 ce062d50 2019-08-21 martijn io_release(struct io *io)
307 ce062d50 2019-08-21 martijn {
308 ce062d50 2019-08-21 martijn if (!(io->flags & IO_HELD))
309 ce062d50 2019-08-21 martijn errx(1, "io_release: io is not held");
310 ce062d50 2019-08-21 martijn
311 ce062d50 2019-08-21 martijn io->flags &= ~IO_HELD;
312 ce062d50 2019-08-21 martijn if (!(io->flags & IO_RESET))
313 ce062d50 2019-08-21 martijn io_reload(io);
314 ce062d50 2019-08-21 martijn }
315 ce062d50 2019-08-21 martijn
316 ce062d50 2019-08-21 martijn void
317 ce062d50 2019-08-21 martijn io_set_fd(struct io *io, int fd)
318 ce062d50 2019-08-21 martijn {
319 ce062d50 2019-08-21 martijn io->sock = fd;
320 ce062d50 2019-08-21 martijn if (fd != -1)
321 ce062d50 2019-08-21 martijn io_reload(io);
322 ce062d50 2019-08-21 martijn }
323 ce062d50 2019-08-21 martijn
324 ce062d50 2019-08-21 martijn void
325 ce062d50 2019-08-21 martijn io_set_callback(struct io *io, void(*cb)(struct io *, int, void *), void *arg)
326 ce062d50 2019-08-21 martijn {
327 ce062d50 2019-08-21 martijn io->cb = cb;
328 ce062d50 2019-08-21 martijn io->arg = arg;
329 ce062d50 2019-08-21 martijn }
330 ce062d50 2019-08-21 martijn
331 ce062d50 2019-08-21 martijn void
332 ce062d50 2019-08-21 martijn io_set_timeout(struct io *io, int msec)
333 ce062d50 2019-08-21 martijn {
334 ce062d50 2019-08-21 martijn io_debug("io_set_timeout(%p, %d)\n", io, msec);
335 ce062d50 2019-08-21 martijn
336 ce062d50 2019-08-21 martijn io->timeout = msec;
337 ce062d50 2019-08-21 martijn }
338 ce062d50 2019-08-21 martijn
339 ce062d50 2019-08-21 martijn void
340 ce062d50 2019-08-21 martijn io_set_lowat(struct io *io, size_t lowat)
341 ce062d50 2019-08-21 martijn {
342 ce062d50 2019-08-21 martijn io_debug("io_set_lowat(%p, %zu)\n", io, lowat);
343 ce062d50 2019-08-21 martijn
344 ce062d50 2019-08-21 martijn io->lowat = lowat;
345 ce062d50 2019-08-21 martijn }
346 ce062d50 2019-08-21 martijn
347 ce062d50 2019-08-21 martijn void
348 ce062d50 2019-08-21 martijn io_pause(struct io *io, int dir)
349 ce062d50 2019-08-21 martijn {
350 ce062d50 2019-08-21 martijn io_debug("io_pause(%p, %x)\n", io, dir);
351 ce062d50 2019-08-21 martijn
352 ce062d50 2019-08-21 martijn io->flags |= dir & (IO_PAUSE_IN | IO_PAUSE_OUT);
353 ce062d50 2019-08-21 martijn io_reload(io);
354 ce062d50 2019-08-21 martijn }
355 ce062d50 2019-08-21 martijn
356 ce062d50 2019-08-21 martijn void
357 ce062d50 2019-08-21 martijn io_resume(struct io *io, int dir)
358 ce062d50 2019-08-21 martijn {
359 ce062d50 2019-08-21 martijn io_debug("io_resume(%p, %x)\n", io, dir);
360 ce062d50 2019-08-21 martijn
361 ce062d50 2019-08-21 martijn io->flags &= ~(dir & (IO_PAUSE_IN | IO_PAUSE_OUT));
362 ce062d50 2019-08-21 martijn io_reload(io);
363 ce062d50 2019-08-21 martijn }
364 ce062d50 2019-08-21 martijn
365 ce062d50 2019-08-21 martijn void
366 ce062d50 2019-08-21 martijn io_set_read(struct io *io)
367 ce062d50 2019-08-21 martijn {
368 ce062d50 2019-08-21 martijn int mode;
369 ce062d50 2019-08-21 martijn
370 ce062d50 2019-08-21 martijn io_debug("io_set_read(%p)\n", io);
371 ce062d50 2019-08-21 martijn
372 ce062d50 2019-08-21 martijn mode = io->flags & IO_RW;
373 ce062d50 2019-08-21 martijn if (!(mode == 0 || mode == IO_WRITE))
374 ce062d50 2019-08-21 martijn errx(1, "io_set_read(): full-duplex or reading");
375 ce062d50 2019-08-21 martijn
376 ce062d50 2019-08-21 martijn io->flags &= ~IO_RW;
377 ce062d50 2019-08-21 martijn io->flags |= IO_READ;
378 ce062d50 2019-08-21 martijn io_reload(io);
379 ce062d50 2019-08-21 martijn }
380 ce062d50 2019-08-21 martijn
381 ce062d50 2019-08-21 martijn void
382 ce062d50 2019-08-21 martijn io_set_write(struct io *io)
383 ce062d50 2019-08-21 martijn {
384 ce062d50 2019-08-21 martijn int mode;
385 ce062d50 2019-08-21 martijn
386 ce062d50 2019-08-21 martijn io_debug("io_set_write(%p)\n", io);
387 ce062d50 2019-08-21 martijn
388 ce062d50 2019-08-21 martijn mode = io->flags & IO_RW;
389 ce062d50 2019-08-21 martijn if (!(mode == 0 || mode == IO_READ))
390 ce062d50 2019-08-21 martijn errx(1, "io_set_write(): full-duplex or writing");
391 ce062d50 2019-08-21 martijn
392 ce062d50 2019-08-21 martijn io->flags &= ~IO_RW;
393 ce062d50 2019-08-21 martijn io->flags |= IO_WRITE;
394 ce062d50 2019-08-21 martijn io_reload(io);
395 ce062d50 2019-08-21 martijn }
396 ce062d50 2019-08-21 martijn
397 ce062d50 2019-08-21 martijn const char *
398 ce062d50 2019-08-21 martijn io_error(struct io *io)
399 ce062d50 2019-08-21 martijn {
400 ce062d50 2019-08-21 martijn return io->error;
401 ce062d50 2019-08-21 martijn }
402 ce062d50 2019-08-21 martijn
403 ce062d50 2019-08-21 martijn void *
404 ce062d50 2019-08-21 martijn io_tls(struct io *io)
405 ce062d50 2019-08-21 martijn {
406 ce062d50 2019-08-21 martijn return io->tls;
407 ce062d50 2019-08-21 martijn }
408 ce062d50 2019-08-21 martijn
409 ce062d50 2019-08-21 martijn int
410 ce062d50 2019-08-21 martijn io_fileno(struct io *io)
411 ce062d50 2019-08-21 martijn {
412 ce062d50 2019-08-21 martijn return io->sock;
413 ce062d50 2019-08-21 martijn }
414 ce062d50 2019-08-21 martijn
415 ce062d50 2019-08-21 martijn int
416 ce062d50 2019-08-21 martijn io_paused(struct io *io, int what)
417 ce062d50 2019-08-21 martijn {
418 ce062d50 2019-08-21 martijn return (io->flags & (IO_PAUSE_IN | IO_PAUSE_OUT)) == what;
419 ce062d50 2019-08-21 martijn }
420 ce062d50 2019-08-21 martijn
421 ce062d50 2019-08-21 martijn /*
422 ce062d50 2019-08-21 martijn * Buffered output functions
423 ce062d50 2019-08-21 martijn */
424 ce062d50 2019-08-21 martijn
425 ce062d50 2019-08-21 martijn int
426 ce062d50 2019-08-21 martijn io_write(struct io *io, const void *buf, size_t len)
427 ce062d50 2019-08-21 martijn {
428 ce062d50 2019-08-21 martijn int r;
429 ce062d50 2019-08-21 martijn
430 ce062d50 2019-08-21 martijn r = iobuf_queue(&io->iobuf, buf, len);
431 ce062d50 2019-08-21 martijn
432 ce062d50 2019-08-21 martijn io_reload(io);
433 ce062d50 2019-08-21 martijn
434 ce062d50 2019-08-21 martijn return r;
435 ce062d50 2019-08-21 martijn }
436 ce062d50 2019-08-21 martijn
437 ce062d50 2019-08-21 martijn int
438 ce062d50 2019-08-21 martijn io_writev(struct io *io, const struct iovec *iov, int iovcount)
439 ce062d50 2019-08-21 martijn {
440 ce062d50 2019-08-21 martijn int r;
441 ce062d50 2019-08-21 martijn
442 ce062d50 2019-08-21 martijn r = iobuf_queuev(&io->iobuf, iov, iovcount);
443 ce062d50 2019-08-21 martijn
444 ce062d50 2019-08-21 martijn io_reload(io);
445 ce062d50 2019-08-21 martijn
446 ce062d50 2019-08-21 martijn return r;
447 ce062d50 2019-08-21 martijn }
448 ce062d50 2019-08-21 martijn
449 ce062d50 2019-08-21 martijn int
450 ce062d50 2019-08-21 martijn io_print(struct io *io, const char *s)
451 ce062d50 2019-08-21 martijn {
452 ce062d50 2019-08-21 martijn return io_write(io, s, strlen(s));
453 ce062d50 2019-08-21 martijn }
454 ce062d50 2019-08-21 martijn
455 ce062d50 2019-08-21 martijn int
456 ce062d50 2019-08-21 martijn io_printf(struct io *io, const char *fmt, ...)
457 ce062d50 2019-08-21 martijn {
458 ce062d50 2019-08-21 martijn va_list ap;
459 ce062d50 2019-08-21 martijn int r;
460 ce062d50 2019-08-21 martijn
461 ce062d50 2019-08-21 martijn va_start(ap, fmt);
462 ce062d50 2019-08-21 martijn r = io_vprintf(io, fmt, ap);
463 ce062d50 2019-08-21 martijn va_end(ap);
464 ce062d50 2019-08-21 martijn
465 ce062d50 2019-08-21 martijn return r;
466 ce062d50 2019-08-21 martijn }
467 ce062d50 2019-08-21 martijn
468 ce062d50 2019-08-21 martijn int
469 ce062d50 2019-08-21 martijn io_vprintf(struct io *io, const char *fmt, va_list ap)
470 ce062d50 2019-08-21 martijn {
471 ce062d50 2019-08-21 martijn
472 ce062d50 2019-08-21 martijn char *buf;
473 ce062d50 2019-08-21 martijn int len;
474 ce062d50 2019-08-21 martijn
475 ce062d50 2019-08-21 martijn len = vasprintf(&buf, fmt, ap);
476 ce062d50 2019-08-21 martijn if (len == -1)
477 ce062d50 2019-08-21 martijn return -1;
478 ce062d50 2019-08-21 martijn len = io_write(io, buf, len);
479 ce062d50 2019-08-21 martijn free(buf);
480 ce062d50 2019-08-21 martijn
481 ce062d50 2019-08-21 martijn return len;
482 ce062d50 2019-08-21 martijn }
483 ce062d50 2019-08-21 martijn
484 ce062d50 2019-08-21 martijn size_t
485 ce062d50 2019-08-21 martijn io_queued(struct io *io)
486 ce062d50 2019-08-21 martijn {
487 ce062d50 2019-08-21 martijn return iobuf_queued(&io->iobuf);
488 ce062d50 2019-08-21 martijn }
489 ce062d50 2019-08-21 martijn
490 ce062d50 2019-08-21 martijn /*
491 ce062d50 2019-08-21 martijn * Buffered input functions
492 ce062d50 2019-08-21 martijn */
493 ce062d50 2019-08-21 martijn
494 ce062d50 2019-08-21 martijn void *
495 ce062d50 2019-08-21 martijn io_data(struct io *io)
496 ce062d50 2019-08-21 martijn {
497 ce062d50 2019-08-21 martijn return iobuf_data(&io->iobuf);
498 ce062d50 2019-08-21 martijn }
499 ce062d50 2019-08-21 martijn
500 ce062d50 2019-08-21 martijn size_t
501 ce062d50 2019-08-21 martijn io_datalen(struct io *io)
502 ce062d50 2019-08-21 martijn {
503 ce062d50 2019-08-21 martijn return iobuf_len(&io->iobuf);
504 ce062d50 2019-08-21 martijn }
505 ce062d50 2019-08-21 martijn
506 ce062d50 2019-08-21 martijn char *
507 ce062d50 2019-08-21 martijn io_getline(struct io *io, size_t *sz)
508 ce062d50 2019-08-21 martijn {
509 ce062d50 2019-08-21 martijn return iobuf_getline(&io->iobuf, sz);
510 ce062d50 2019-08-21 martijn }
511 ce062d50 2019-08-21 martijn
512 ce062d50 2019-08-21 martijn void
513 ce062d50 2019-08-21 martijn io_drop(struct io *io, size_t sz)
514 ce062d50 2019-08-21 martijn {
515 ce062d50 2019-08-21 martijn return iobuf_drop(&io->iobuf, sz);
516 ce062d50 2019-08-21 martijn }
517 ce062d50 2019-08-21 martijn
518 ce062d50 2019-08-21 martijn
519 ce062d50 2019-08-21 martijn #define IO_READING(io) (((io)->flags & IO_RW) != IO_WRITE)
520 ce062d50 2019-08-21 martijn #define IO_WRITING(io) (((io)->flags & IO_RW) != IO_READ)
521 ce062d50 2019-08-21 martijn
522 ce062d50 2019-08-21 martijn /*
523 ce062d50 2019-08-21 martijn * Setup the necessary events as required by the current io state,
524 ce062d50 2019-08-21 martijn * honouring duplex mode and i/o pauses.
525 ce062d50 2019-08-21 martijn */
526 ce062d50 2019-08-21 martijn void
527 ce062d50 2019-08-21 martijn io_reload(struct io *io)
528 ce062d50 2019-08-21 martijn {
529 ce062d50 2019-08-21 martijn short events;
530 ce062d50 2019-08-21 martijn
531 ce062d50 2019-08-21 martijn /* io will be reloaded at release time */
532 ce062d50 2019-08-21 martijn if (io->flags & IO_HELD)
533 ce062d50 2019-08-21 martijn return;
534 ce062d50 2019-08-21 martijn
535 ce062d50 2019-08-21 martijn iobuf_normalize(&io->iobuf);
536 ce062d50 2019-08-21 martijn
537 ce062d50 2019-08-21 martijn #ifdef IO_TLS
538 ce062d50 2019-08-21 martijn if (io->tls) {
539 ce062d50 2019-08-21 martijn io_reload_tls(io);
540 ce062d50 2019-08-21 martijn return;
541 ce062d50 2019-08-21 martijn }
542 ce062d50 2019-08-21 martijn #endif
543 ce062d50 2019-08-21 martijn
544 ce062d50 2019-08-21 martijn io_debug("io_reload(%p)\n", io);
545 ce062d50 2019-08-21 martijn
546 ce062d50 2019-08-21 martijn events = 0;
547 ce062d50 2019-08-21 martijn if (IO_READING(io) && !(io->flags & IO_PAUSE_IN))
548 ce062d50 2019-08-21 martijn events = EV_READ;
549 ce062d50 2019-08-21 martijn if (IO_WRITING(io) && !(io->flags & IO_PAUSE_OUT) && io_queued(io))
550 ce062d50 2019-08-21 martijn events |= EV_WRITE;
551 ce062d50 2019-08-21 martijn
552 ce062d50 2019-08-21 martijn io_reset(io, events, io_dispatch);
553 ce062d50 2019-08-21 martijn }
554 ce062d50 2019-08-21 martijn
555 ce062d50 2019-08-21 martijn /* Set the requested event. */
556 ce062d50 2019-08-21 martijn void
557 ce062d50 2019-08-21 martijn io_reset(struct io *io, short events, void (*dispatch)(int, short, void*))
558 ce062d50 2019-08-21 martijn {
559 ce062d50 2019-08-21 martijn struct timeval tv, *ptv;
560 ce062d50 2019-08-21 martijn
561 ce062d50 2019-08-21 martijn io_debug("io_reset(%p, %s, %p) -> %s\n",
562 ce062d50 2019-08-21 martijn io, io_evstr(events), dispatch, io_strio(io));
563 ce062d50 2019-08-21 martijn
564 ce062d50 2019-08-21 martijn /*
565 ce062d50 2019-08-21 martijn * Indicate that the event has already been reset so that reload
566 ce062d50 2019-08-21 martijn * is not called on frame_leave.
567 ce062d50 2019-08-21 martijn */
568 ce062d50 2019-08-21 martijn io->flags |= IO_RESET;
569 ce062d50 2019-08-21 martijn
570 681d8d49 2022-03-28 martijn if (event_initialized(&io->ev) &&
571 681d8d49 2022-03-28 martijn event_pending(&io->ev, EV_READ|EV_WRITE, NULL))
572 ce062d50 2019-08-21 martijn event_del(&io->ev);
573 ce062d50 2019-08-21 martijn
574 ce062d50 2019-08-21 martijn /*
575 ce062d50 2019-08-21 martijn * The io is paused by the user, so we don't want the timeout to be
576 ce062d50 2019-08-21 martijn * effective.
577 ce062d50 2019-08-21 martijn */
578 ce062d50 2019-08-21 martijn if (events == 0)
579 ce062d50 2019-08-21 martijn return;
580 ce062d50 2019-08-21 martijn
581 ce062d50 2019-08-21 martijn event_set(&io->ev, io->sock, events, dispatch, io);
582 ce062d50 2019-08-21 martijn if (io->timeout >= 0) {
583 ce062d50 2019-08-21 martijn tv.tv_sec = io->timeout / 1000;
584 ce062d50 2019-08-21 martijn tv.tv_usec = (io->timeout % 1000) * 1000;
585 ce062d50 2019-08-21 martijn ptv = &tv;
586 ce062d50 2019-08-21 martijn } else
587 ce062d50 2019-08-21 martijn ptv = NULL;
588 ce062d50 2019-08-21 martijn
589 ce062d50 2019-08-21 martijn event_add(&io->ev, ptv);
590 ce062d50 2019-08-21 martijn }
591 ce062d50 2019-08-21 martijn
592 ce062d50 2019-08-21 martijn size_t
593 ce062d50 2019-08-21 martijn io_pending(struct io *io)
594 ce062d50 2019-08-21 martijn {
595 ce062d50 2019-08-21 martijn return iobuf_len(&io->iobuf);
596 ce062d50 2019-08-21 martijn }
597 ce062d50 2019-08-21 martijn
598 ce062d50 2019-08-21 martijn const char*
599 ce062d50 2019-08-21 martijn io_strflags(int flags)
600 ce062d50 2019-08-21 martijn {
601 ce062d50 2019-08-21 martijn static char buf[64];
602 ce062d50 2019-08-21 martijn
603 ce062d50 2019-08-21 martijn buf[0] = '\0';
604 ce062d50 2019-08-21 martijn
605 ce062d50 2019-08-21 martijn switch (flags & IO_RW) {
606 ce062d50 2019-08-21 martijn case 0:
607 ce062d50 2019-08-21 martijn (void)strlcat(buf, "rw", sizeof buf);
608 ce062d50 2019-08-21 martijn break;
609 ce062d50 2019-08-21 martijn case IO_READ:
610 ce062d50 2019-08-21 martijn (void)strlcat(buf, "R", sizeof buf);
611 ce062d50 2019-08-21 martijn break;
612 ce062d50 2019-08-21 martijn case IO_WRITE:
613 ce062d50 2019-08-21 martijn (void)strlcat(buf, "W", sizeof buf);
614 ce062d50 2019-08-21 martijn break;
615 ce062d50 2019-08-21 martijn case IO_RW:
616 ce062d50 2019-08-21 martijn (void)strlcat(buf, "RW", sizeof buf);
617 ce062d50 2019-08-21 martijn break;
618 ce062d50 2019-08-21 martijn }
619 ce062d50 2019-08-21 martijn
620 ce062d50 2019-08-21 martijn if (flags & IO_PAUSE_IN)
621 ce062d50 2019-08-21 martijn (void)strlcat(buf, ",F_PI", sizeof buf);
622 ce062d50 2019-08-21 martijn if (flags & IO_PAUSE_OUT)
623 ce062d50 2019-08-21 martijn (void)strlcat(buf, ",F_PO", sizeof buf);
624 ce062d50 2019-08-21 martijn
625 ce062d50 2019-08-21 martijn return buf;
626 ce062d50 2019-08-21 martijn }
627 ce062d50 2019-08-21 martijn
628 ce062d50 2019-08-21 martijn const char*
629 ce062d50 2019-08-21 martijn io_evstr(short ev)
630 ce062d50 2019-08-21 martijn {
631 ce062d50 2019-08-21 martijn static char buf[64];
632 ce062d50 2019-08-21 martijn char buf2[16];
633 ce062d50 2019-08-21 martijn int n;
634 ce062d50 2019-08-21 martijn
635 ce062d50 2019-08-21 martijn n = 0;
636 ce062d50 2019-08-21 martijn buf[0] = '\0';
637 ce062d50 2019-08-21 martijn
638 ce062d50 2019-08-21 martijn if (ev == 0) {
639 ce062d50 2019-08-21 martijn (void)strlcat(buf, "<NONE>", sizeof(buf));
640 ce062d50 2019-08-21 martijn return buf;
641 ce062d50 2019-08-21 martijn }
642 ce062d50 2019-08-21 martijn
643 ce062d50 2019-08-21 martijn if (ev & EV_TIMEOUT) {
644 ce062d50 2019-08-21 martijn (void)strlcat(buf, "EV_TIMEOUT", sizeof(buf));
645 ce062d50 2019-08-21 martijn ev &= ~EV_TIMEOUT;
646 ce062d50 2019-08-21 martijn n++;
647 ce062d50 2019-08-21 martijn }
648 ce062d50 2019-08-21 martijn
649 ce062d50 2019-08-21 martijn if (ev & EV_READ) {
650 ce062d50 2019-08-21 martijn if (n)
651 ce062d50 2019-08-21 martijn (void)strlcat(buf, "|", sizeof(buf));
652 ce062d50 2019-08-21 martijn (void)strlcat(buf, "EV_READ", sizeof(buf));
653 ce062d50 2019-08-21 martijn ev &= ~EV_READ;
654 ce062d50 2019-08-21 martijn n++;
655 ce062d50 2019-08-21 martijn }
656 ce062d50 2019-08-21 martijn
657 ce062d50 2019-08-21 martijn if (ev & EV_WRITE) {
658 ce062d50 2019-08-21 martijn if (n)
659 ce062d50 2019-08-21 martijn (void)strlcat(buf, "|", sizeof(buf));
660 ce062d50 2019-08-21 martijn (void)strlcat(buf, "EV_WRITE", sizeof(buf));
661 ce062d50 2019-08-21 martijn ev &= ~EV_WRITE;
662 ce062d50 2019-08-21 martijn n++;
663 ce062d50 2019-08-21 martijn }
664 ce062d50 2019-08-21 martijn
665 ce062d50 2019-08-21 martijn if (ev & EV_SIGNAL) {
666 ce062d50 2019-08-21 martijn if (n)
667 ce062d50 2019-08-21 martijn (void)strlcat(buf, "|", sizeof(buf));
668 ce062d50 2019-08-21 martijn (void)strlcat(buf, "EV_SIGNAL", sizeof(buf));
669 ce062d50 2019-08-21 martijn ev &= ~EV_SIGNAL;
670 ce062d50 2019-08-21 martijn n++;
671 ce062d50 2019-08-21 martijn }
672 ce062d50 2019-08-21 martijn
673 ce062d50 2019-08-21 martijn if (ev) {
674 ce062d50 2019-08-21 martijn if (n)
675 ce062d50 2019-08-21 martijn (void)strlcat(buf, "|", sizeof(buf));
676 ce062d50 2019-08-21 martijn (void)strlcat(buf, "EV_?=0x", sizeof(buf));
677 ce062d50 2019-08-21 martijn (void)snprintf(buf2, sizeof(buf2), "%hx", ev);
678 ce062d50 2019-08-21 martijn (void)strlcat(buf, buf2, sizeof(buf));
679 ce062d50 2019-08-21 martijn }
680 ce062d50 2019-08-21 martijn
681 ce062d50 2019-08-21 martijn return buf;
682 ce062d50 2019-08-21 martijn }
683 ce062d50 2019-08-21 martijn
684 ce062d50 2019-08-21 martijn void
685 957c2372 2019-11-14 martijn io_dispatch(__unused int fd, short ev, void *humppa)
686 ce062d50 2019-08-21 martijn {
687 ce062d50 2019-08-21 martijn struct io *io = humppa;
688 ce062d50 2019-08-21 martijn size_t w;
689 ce062d50 2019-08-21 martijn ssize_t n;
690 ce062d50 2019-08-21 martijn int saved_errno;
691 ce062d50 2019-08-21 martijn
692 ce062d50 2019-08-21 martijn io_frame_enter("io_dispatch", io, ev);
693 ce062d50 2019-08-21 martijn
694 ce062d50 2019-08-21 martijn if (ev == EV_TIMEOUT) {
695 ce062d50 2019-08-21 martijn io_callback(io, IO_TIMEOUT);
696 ce062d50 2019-08-21 martijn goto leave;
697 ce062d50 2019-08-21 martijn }
698 ce062d50 2019-08-21 martijn
699 ce062d50 2019-08-21 martijn if (ev & EV_WRITE && (w = io_queued(io))) {
700 ce062d50 2019-08-21 martijn if ((n = iobuf_write(&io->iobuf, io->sock)) < 0) {
701 ce062d50 2019-08-21 martijn if (n == IOBUF_WANT_WRITE) /* kqueue bug? */
702 ce062d50 2019-08-21 martijn goto read;
703 ce062d50 2019-08-21 martijn if (n == IOBUF_CLOSED)
704 ce062d50 2019-08-21 martijn io_callback(io, IO_DISCONNECTED);
705 ce062d50 2019-08-21 martijn else {
706 ce062d50 2019-08-21 martijn saved_errno = errno;
707 ce062d50 2019-08-21 martijn io->error = strerror(errno);
708 ce062d50 2019-08-21 martijn errno = saved_errno;
709 ce062d50 2019-08-21 martijn io_callback(io, IO_ERROR);
710 ce062d50 2019-08-21 martijn }
711 ce062d50 2019-08-21 martijn goto leave;
712 ce062d50 2019-08-21 martijn }
713 ce062d50 2019-08-21 martijn if (w > io->lowat && w - n <= io->lowat)
714 ce062d50 2019-08-21 martijn io_callback(io, IO_LOWAT);
715 ce062d50 2019-08-21 martijn }
716 ce062d50 2019-08-21 martijn read:
717 ce062d50 2019-08-21 martijn
718 ce062d50 2019-08-21 martijn if (ev & EV_READ) {
719 ce062d50 2019-08-21 martijn iobuf_normalize(&io->iobuf);
720 ce062d50 2019-08-21 martijn if ((n = iobuf_read(&io->iobuf, io->sock)) < 0) {
721 ce062d50 2019-08-21 martijn if (n == IOBUF_CLOSED)
722 ce062d50 2019-08-21 martijn io_callback(io, IO_DISCONNECTED);
723 ce062d50 2019-08-21 martijn else {
724 ce062d50 2019-08-21 martijn saved_errno = errno;
725 ce062d50 2019-08-21 martijn io->error = strerror(errno);
726 ce062d50 2019-08-21 martijn errno = saved_errno;
727 ce062d50 2019-08-21 martijn io_callback(io, IO_ERROR);
728 ce062d50 2019-08-21 martijn }
729 ce062d50 2019-08-21 martijn goto leave;
730 ce062d50 2019-08-21 martijn }
731 ce062d50 2019-08-21 martijn if (n)
732 ce062d50 2019-08-21 martijn io_callback(io, IO_DATAIN);
733 ce062d50 2019-08-21 martijn }
734 ce062d50 2019-08-21 martijn
735 ce062d50 2019-08-21 martijn leave:
736 ce062d50 2019-08-21 martijn io_frame_leave(io);
737 ce062d50 2019-08-21 martijn }
738 ce062d50 2019-08-21 martijn
739 ce062d50 2019-08-21 martijn void
740 ce062d50 2019-08-21 martijn io_callback(struct io *io, int evt)
741 ce062d50 2019-08-21 martijn {
742 ce062d50 2019-08-21 martijn io->cb(io, evt, io->arg);
743 ce062d50 2019-08-21 martijn }
744 ce062d50 2019-08-21 martijn
745 ce062d50 2019-08-21 martijn int
746 ce062d50 2019-08-21 martijn io_connect(struct io *io, const struct sockaddr *sa, const struct sockaddr *bsa)
747 ce062d50 2019-08-21 martijn {
748 ce062d50 2019-08-21 martijn int sock, errno_save;
749 ce062d50 2019-08-21 martijn
750 ce062d50 2019-08-21 martijn if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) == -1)
751 ce062d50 2019-08-21 martijn goto fail;
752 ce062d50 2019-08-21 martijn
753 ce062d50 2019-08-21 martijn io_set_nonblocking(sock);
754 ce062d50 2019-08-21 martijn io_set_nolinger(sock);
755 ce062d50 2019-08-21 martijn
756 957c2372 2019-11-14 martijn if (bsa && bind(sock, bsa, SA_LEN(bsa)) == -1)
757 ce062d50 2019-08-21 martijn goto fail;
758 ce062d50 2019-08-21 martijn
759 957c2372 2019-11-14 martijn if (connect(sock, sa, SA_LEN(sa)) == -1)
760 ce062d50 2019-08-21 martijn if (errno != EINPROGRESS)
761 ce062d50 2019-08-21 martijn goto fail;
762 ce062d50 2019-08-21 martijn
763 ce062d50 2019-08-21 martijn io->sock = sock;
764 ce062d50 2019-08-21 martijn io_reset(io, EV_WRITE, io_dispatch_connect);
765 ce062d50 2019-08-21 martijn
766 ce062d50 2019-08-21 martijn return (sock);
767 ce062d50 2019-08-21 martijn
768 ce062d50 2019-08-21 martijn fail:
769 ce062d50 2019-08-21 martijn if (sock != -1) {
770 ce062d50 2019-08-21 martijn errno_save = errno;
771 ce062d50 2019-08-21 martijn close(sock);
772 ce062d50 2019-08-21 martijn errno = errno_save;
773 ce062d50 2019-08-21 martijn io->error = strerror(errno);
774 ce062d50 2019-08-21 martijn }
775 ce062d50 2019-08-21 martijn return (-1);
776 ce062d50 2019-08-21 martijn }
777 ce062d50 2019-08-21 martijn
778 ce062d50 2019-08-21 martijn void
779 ce062d50 2019-08-21 martijn io_dispatch_connect(int fd, short ev, void *humppa)
780 ce062d50 2019-08-21 martijn {
781 ce062d50 2019-08-21 martijn struct io *io = humppa;
782 ce062d50 2019-08-21 martijn int r, e;
783 ce062d50 2019-08-21 martijn socklen_t sl;
784 ce062d50 2019-08-21 martijn
785 ce062d50 2019-08-21 martijn io_frame_enter("io_dispatch_connect", io, ev);
786 ce062d50 2019-08-21 martijn
787 ce062d50 2019-08-21 martijn if (ev == EV_TIMEOUT) {
788 ce062d50 2019-08-21 martijn close(fd);
789 ce062d50 2019-08-21 martijn io->sock = -1;
790 ce062d50 2019-08-21 martijn io_callback(io, IO_TIMEOUT);
791 ce062d50 2019-08-21 martijn } else {
792 ce062d50 2019-08-21 martijn sl = sizeof(e);
793 ce062d50 2019-08-21 martijn r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &e, &sl);
794 ce062d50 2019-08-21 martijn if (r == -1) {
795 ce062d50 2019-08-21 martijn warn("io_dispatch_connect: getsockopt");
796 ce062d50 2019-08-21 martijn e = errno;
797 ce062d50 2019-08-21 martijn }
798 ce062d50 2019-08-21 martijn if (e) {
799 ce062d50 2019-08-21 martijn close(fd);
800 ce062d50 2019-08-21 martijn io->sock = -1;
801 ce062d50 2019-08-21 martijn io->error = strerror(e);
802 ce062d50 2019-08-21 martijn io_callback(io, e == ETIMEDOUT ? IO_TIMEOUT : IO_ERROR);
803 ce062d50 2019-08-21 martijn }
804 ce062d50 2019-08-21 martijn else {
805 ce062d50 2019-08-21 martijn io->state = IO_STATE_UP;
806 ce062d50 2019-08-21 martijn io_callback(io, IO_CONNECTED);
807 ce062d50 2019-08-21 martijn }
808 ce062d50 2019-08-21 martijn }
809 ce062d50 2019-08-21 martijn
810 ce062d50 2019-08-21 martijn io_frame_leave(io);
811 ce062d50 2019-08-21 martijn }
812 ce062d50 2019-08-21 martijn
813 ce062d50 2019-08-21 martijn #ifdef IO_TLS
814 ce062d50 2019-08-21 martijn
815 ce062d50 2019-08-21 martijn static const char*
816 ce062d50 2019-08-21 martijn io_tls_error(void)
817 ce062d50 2019-08-21 martijn {
818 ce062d50 2019-08-21 martijn static char buf[128];
819 ce062d50 2019-08-21 martijn unsigned long e;
820 ce062d50 2019-08-21 martijn
821 ce062d50 2019-08-21 martijn e = ERR_peek_last_error();
822 ce062d50 2019-08-21 martijn if (e) {
823 ce062d50 2019-08-21 martijn ERR_error_string(e, buf);
824 ce062d50 2019-08-21 martijn return (buf);
825 ce062d50 2019-08-21 martijn }
826 ce062d50 2019-08-21 martijn
827 ce062d50 2019-08-21 martijn return ("No TLS error");
828 ce062d50 2019-08-21 martijn }
829 ce062d50 2019-08-21 martijn
830 ce062d50 2019-08-21 martijn int
831 ce062d50 2019-08-21 martijn io_start_tls(struct io *io, void *tls)
832 ce062d50 2019-08-21 martijn {
833 ce062d50 2019-08-21 martijn int mode;
834 ce062d50 2019-08-21 martijn
835 ce062d50 2019-08-21 martijn mode = io->flags & IO_RW;
836 ce062d50 2019-08-21 martijn if (mode == 0 || mode == IO_RW)
837 ce062d50 2019-08-21 martijn errx(1, "io_start_tls(): full-duplex or unset");
838 ce062d50 2019-08-21 martijn
839 ce062d50 2019-08-21 martijn if (io->tls)
840 ce062d50 2019-08-21 martijn errx(1, "io_start_tls(): TLS already started");
841 ce062d50 2019-08-21 martijn io->tls = tls;
842 ce062d50 2019-08-21 martijn
843 ce062d50 2019-08-21 martijn if (SSL_set_fd(io->tls, io->sock) == 0) {
844 ce062d50 2019-08-21 martijn ssl_error("io_start_tls:SSL_set_fd");
845 ce062d50 2019-08-21 martijn return (-1);
846 ce062d50 2019-08-21 martijn }
847 ce062d50 2019-08-21 martijn
848 ce062d50 2019-08-21 martijn if (mode == IO_WRITE) {
849 ce062d50 2019-08-21 martijn io->state = IO_STATE_CONNECT_TLS;
850 ce062d50 2019-08-21 martijn SSL_set_connect_state(io->tls);
851 ce062d50 2019-08-21 martijn io_reset(io, EV_WRITE, io_dispatch_connect_tls);
852 ce062d50 2019-08-21 martijn } else {
853 ce062d50 2019-08-21 martijn io->state = IO_STATE_ACCEPT_TLS;
854 ce062d50 2019-08-21 martijn SSL_set_accept_state(io->tls);
855 ce062d50 2019-08-21 martijn io_reset(io, EV_READ, io_dispatch_accept_tls);
856 ce062d50 2019-08-21 martijn }
857 ce062d50 2019-08-21 martijn
858 ce062d50 2019-08-21 martijn return (0);
859 ce062d50 2019-08-21 martijn }
860 ce062d50 2019-08-21 martijn
861 ce062d50 2019-08-21 martijn void
862 ce062d50 2019-08-21 martijn io_dispatch_accept_tls(int fd, short event, void *humppa)
863 ce062d50 2019-08-21 martijn {
864 ce062d50 2019-08-21 martijn struct io *io = humppa;
865 ce062d50 2019-08-21 martijn int e, ret;
866 ce062d50 2019-08-21 martijn
867 ce062d50 2019-08-21 martijn io_frame_enter("io_dispatch_accept_tls", io, event);
868 ce062d50 2019-08-21 martijn
869 ce062d50 2019-08-21 martijn if (event == EV_TIMEOUT) {
870 ce062d50 2019-08-21 martijn io_callback(io, IO_TIMEOUT);
871 ce062d50 2019-08-21 martijn goto leave;
872 ce062d50 2019-08-21 martijn }
873 ce062d50 2019-08-21 martijn
874 ce062d50 2019-08-21 martijn if ((ret = SSL_accept(io->tls)) > 0) {
875 ce062d50 2019-08-21 martijn io->state = IO_STATE_UP;
876 ce062d50 2019-08-21 martijn io_callback(io, IO_TLSREADY);
877 ce062d50 2019-08-21 martijn goto leave;
878 ce062d50 2019-08-21 martijn }
879 ce062d50 2019-08-21 martijn
880 ce062d50 2019-08-21 martijn switch ((e = SSL_get_error(io->tls, ret))) {
881 ce062d50 2019-08-21 martijn case SSL_ERROR_WANT_READ:
882 ce062d50 2019-08-21 martijn io_reset(io, EV_READ, io_dispatch_accept_tls);
883 ce062d50 2019-08-21 martijn break;
884 ce062d50 2019-08-21 martijn case SSL_ERROR_WANT_WRITE:
885 ce062d50 2019-08-21 martijn io_reset(io, EV_WRITE, io_dispatch_accept_tls);
886 ce062d50 2019-08-21 martijn break;
887 ce062d50 2019-08-21 martijn default:
888 ce062d50 2019-08-21 martijn io->error = io_tls_error();
889 ce062d50 2019-08-21 martijn ssl_error("io_dispatch_accept_tls:SSL_accept");
890 ce062d50 2019-08-21 martijn io_callback(io, IO_ERROR);
891 ce062d50 2019-08-21 martijn break;
892 ce062d50 2019-08-21 martijn }
893 ce062d50 2019-08-21 martijn
894 ce062d50 2019-08-21 martijn leave:
895 ce062d50 2019-08-21 martijn io_frame_leave(io);
896 ce062d50 2019-08-21 martijn }
897 ce062d50 2019-08-21 martijn
898 ce062d50 2019-08-21 martijn void
899 ce062d50 2019-08-21 martijn io_dispatch_connect_tls(int fd, short event, void *humppa)
900 ce062d50 2019-08-21 martijn {
901 ce062d50 2019-08-21 martijn struct io *io = humppa;
902 ce062d50 2019-08-21 martijn int e, ret;
903 ce062d50 2019-08-21 martijn
904 ce062d50 2019-08-21 martijn io_frame_enter("io_dispatch_connect_tls", io, event);
905 ce062d50 2019-08-21 martijn
906 ce062d50 2019-08-21 martijn if (event == EV_TIMEOUT) {
907 ce062d50 2019-08-21 martijn io_callback(io, IO_TIMEOUT);
908 ce062d50 2019-08-21 martijn goto leave;
909 ce062d50 2019-08-21 martijn }
910 ce062d50 2019-08-21 martijn
911 ce062d50 2019-08-21 martijn if ((ret = SSL_connect(io->tls)) > 0) {
912 ce062d50 2019-08-21 martijn io->state = IO_STATE_UP;
913 ce062d50 2019-08-21 martijn io_callback(io, IO_TLSREADY);
914 ce062d50 2019-08-21 martijn goto leave;
915 ce062d50 2019-08-21 martijn }
916 ce062d50 2019-08-21 martijn
917 ce062d50 2019-08-21 martijn switch ((e = SSL_get_error(io->tls, ret))) {
918 ce062d50 2019-08-21 martijn case SSL_ERROR_WANT_READ:
919 ce062d50 2019-08-21 martijn io_reset(io, EV_READ, io_dispatch_connect_tls);
920 ce062d50 2019-08-21 martijn break;
921 ce062d50 2019-08-21 martijn case SSL_ERROR_WANT_WRITE:
922 ce062d50 2019-08-21 martijn io_reset(io, EV_WRITE, io_dispatch_connect_tls);
923 ce062d50 2019-08-21 martijn break;
924 ce062d50 2019-08-21 martijn default:
925 ce062d50 2019-08-21 martijn io->error = io_tls_error();
926 ce062d50 2019-08-21 martijn ssl_error("io_dispatch_connect_ssl:SSL_connect");
927 ce062d50 2019-08-21 martijn io_callback(io, IO_TLSERROR);
928 ce062d50 2019-08-21 martijn break;
929 ce062d50 2019-08-21 martijn }
930 ce062d50 2019-08-21 martijn
931 ce062d50 2019-08-21 martijn leave:
932 ce062d50 2019-08-21 martijn io_frame_leave(io);
933 ce062d50 2019-08-21 martijn }
934 ce062d50 2019-08-21 martijn
935 ce062d50 2019-08-21 martijn void
936 ce062d50 2019-08-21 martijn io_dispatch_read_tls(int fd, short event, void *humppa)
937 ce062d50 2019-08-21 martijn {
938 ce062d50 2019-08-21 martijn struct io *io = humppa;
939 ce062d50 2019-08-21 martijn int n, saved_errno;
940 ce062d50 2019-08-21 martijn
941 ce062d50 2019-08-21 martijn io_frame_enter("io_dispatch_read_tls", io, event);
942 ce062d50 2019-08-21 martijn
943 ce062d50 2019-08-21 martijn if (event == EV_TIMEOUT) {
944 ce062d50 2019-08-21 martijn io_callback(io, IO_TIMEOUT);
945 ce062d50 2019-08-21 martijn goto leave;
946 ce062d50 2019-08-21 martijn }
947 ce062d50 2019-08-21 martijn
948 ce062d50 2019-08-21 martijn again:
949 ce062d50 2019-08-21 martijn iobuf_normalize(&io->iobuf);
950 ce062d50 2019-08-21 martijn switch ((n = iobuf_read_tls(&io->iobuf, (SSL*)io->tls))) {
951 ce062d50 2019-08-21 martijn case IOBUF_WANT_READ:
952 ce062d50 2019-08-21 martijn io_reset(io, EV_READ, io_dispatch_read_tls);
953 ce062d50 2019-08-21 martijn break;
954 ce062d50 2019-08-21 martijn case IOBUF_WANT_WRITE:
955 ce062d50 2019-08-21 martijn io_reset(io, EV_WRITE, io_dispatch_read_tls);
956 ce062d50 2019-08-21 martijn break;
957 ce062d50 2019-08-21 martijn case IOBUF_CLOSED:
958 ce062d50 2019-08-21 martijn io_callback(io, IO_DISCONNECTED);
959 ce062d50 2019-08-21 martijn break;
960 ce062d50 2019-08-21 martijn case IOBUF_ERROR:
961 ce062d50 2019-08-21 martijn saved_errno = errno;
962 ce062d50 2019-08-21 martijn io->error = strerror(errno);
963 ce062d50 2019-08-21 martijn errno = saved_errno;
964 ce062d50 2019-08-21 martijn io_callback(io, IO_ERROR);
965 ce062d50 2019-08-21 martijn break;
966 ce062d50 2019-08-21 martijn case IOBUF_TLSERROR:
967 ce062d50 2019-08-21 martijn io->error = io_tls_error();
968 ce062d50 2019-08-21 martijn ssl_error("io_dispatch_read_tls:SSL_read");
969 ce062d50 2019-08-21 martijn io_callback(io, IO_ERROR);
970 ce062d50 2019-08-21 martijn break;
971 ce062d50 2019-08-21 martijn default:
972 ce062d50 2019-08-21 martijn io_debug("io_dispatch_read_tls(...) -> r=%d\n", n);
973 ce062d50 2019-08-21 martijn io_callback(io, IO_DATAIN);
974 ce062d50 2019-08-21 martijn if (current == io && IO_READING(io) && SSL_pending(io->tls))
975 ce062d50 2019-08-21 martijn goto again;
976 ce062d50 2019-08-21 martijn }
977 ce062d50 2019-08-21 martijn
978 ce062d50 2019-08-21 martijn leave:
979 ce062d50 2019-08-21 martijn io_frame_leave(io);
980 ce062d50 2019-08-21 martijn }
981 ce062d50 2019-08-21 martijn
982 ce062d50 2019-08-21 martijn void
983 ce062d50 2019-08-21 martijn io_dispatch_write_tls(int fd, short event, void *humppa)
984 ce062d50 2019-08-21 martijn {
985 ce062d50 2019-08-21 martijn struct io *io = humppa;
986 ce062d50 2019-08-21 martijn int n, saved_errno;
987 ce062d50 2019-08-21 martijn size_t w2, w;
988 ce062d50 2019-08-21 martijn
989 ce062d50 2019-08-21 martijn io_frame_enter("io_dispatch_write_tls", io, event);
990 ce062d50 2019-08-21 martijn
991 ce062d50 2019-08-21 martijn if (event == EV_TIMEOUT) {
992 ce062d50 2019-08-21 martijn io_callback(io, IO_TIMEOUT);
993 ce062d50 2019-08-21 martijn goto leave;
994 ce062d50 2019-08-21 martijn }
995 ce062d50 2019-08-21 martijn
996 ce062d50 2019-08-21 martijn w = io_queued(io);
997 ce062d50 2019-08-21 martijn switch ((n = iobuf_write_tls(&io->iobuf, (SSL*)io->tls))) {
998 ce062d50 2019-08-21 martijn case IOBUF_WANT_READ:
999 ce062d50 2019-08-21 martijn io_reset(io, EV_READ, io_dispatch_write_tls);
1000 ce062d50 2019-08-21 martijn break;
1001 ce062d50 2019-08-21 martijn case IOBUF_WANT_WRITE:
1002 ce062d50 2019-08-21 martijn io_reset(io, EV_WRITE, io_dispatch_write_tls);
1003 ce062d50 2019-08-21 martijn break;
1004 ce062d50 2019-08-21 martijn case IOBUF_CLOSED:
1005 ce062d50 2019-08-21 martijn io_callback(io, IO_DISCONNECTED);
1006 ce062d50 2019-08-21 martijn break;
1007 ce062d50 2019-08-21 martijn case IOBUF_ERROR:
1008 ce062d50 2019-08-21 martijn saved_errno = errno;
1009 ce062d50 2019-08-21 martijn io->error = strerror(errno);
1010 ce062d50 2019-08-21 martijn errno = saved_errno;
1011 ce062d50 2019-08-21 martijn io_callback(io, IO_ERROR);
1012 ce062d50 2019-08-21 martijn break;
1013 ce062d50 2019-08-21 martijn case IOBUF_TLSERROR:
1014 ce062d50 2019-08-21 martijn io->error = io_tls_error();
1015 ce062d50 2019-08-21 martijn ssl_error("io_dispatch_write_tls:SSL_write");
1016 ce062d50 2019-08-21 martijn io_callback(io, IO_ERROR);
1017 ce062d50 2019-08-21 martijn break;
1018 ce062d50 2019-08-21 martijn default:
1019 ce062d50 2019-08-21 martijn io_debug("io_dispatch_write_tls(...) -> w=%d\n", n);
1020 ce062d50 2019-08-21 martijn w2 = io_queued(io);
1021 ce062d50 2019-08-21 martijn if (w > io->lowat && w2 <= io->lowat)
1022 ce062d50 2019-08-21 martijn io_callback(io, IO_LOWAT);
1023 ce062d50 2019-08-21 martijn break;
1024 ce062d50 2019-08-21 martijn }
1025 ce062d50 2019-08-21 martijn
1026 ce062d50 2019-08-21 martijn leave:
1027 ce062d50 2019-08-21 martijn io_frame_leave(io);
1028 ce062d50 2019-08-21 martijn }
1029 ce062d50 2019-08-21 martijn
1030 ce062d50 2019-08-21 martijn void
1031 ce062d50 2019-08-21 martijn io_reload_tls(struct io *io)
1032 ce062d50 2019-08-21 martijn {
1033 ce062d50 2019-08-21 martijn short ev = 0;
1034 ce062d50 2019-08-21 martijn void (*dispatch)(int, short, void*) = NULL;
1035 ce062d50 2019-08-21 martijn
1036 ce062d50 2019-08-21 martijn switch (io->state) {
1037 ce062d50 2019-08-21 martijn case IO_STATE_CONNECT_TLS:
1038 ce062d50 2019-08-21 martijn ev = EV_WRITE;
1039 ce062d50 2019-08-21 martijn dispatch = io_dispatch_connect_tls;
1040 ce062d50 2019-08-21 martijn break;
1041 ce062d50 2019-08-21 martijn case IO_STATE_ACCEPT_TLS:
1042 ce062d50 2019-08-21 martijn ev = EV_READ;
1043 ce062d50 2019-08-21 martijn dispatch = io_dispatch_accept_tls;
1044 ce062d50 2019-08-21 martijn break;
1045 ce062d50 2019-08-21 martijn case IO_STATE_UP:
1046 ce062d50 2019-08-21 martijn ev = 0;
1047 ce062d50 2019-08-21 martijn if (IO_READING(io) && !(io->flags & IO_PAUSE_IN)) {
1048 ce062d50 2019-08-21 martijn ev = EV_READ;
1049 ce062d50 2019-08-21 martijn dispatch = io_dispatch_read_tls;
1050 ce062d50 2019-08-21 martijn }
1051 ce062d50 2019-08-21 martijn else if (IO_WRITING(io) && !(io->flags & IO_PAUSE_OUT) &&
1052 ce062d50 2019-08-21 martijn io_queued(io)) {
1053 ce062d50 2019-08-21 martijn ev = EV_WRITE;
1054 ce062d50 2019-08-21 martijn dispatch = io_dispatch_write_tls;
1055 ce062d50 2019-08-21 martijn }
1056 ce062d50 2019-08-21 martijn if (!ev)
1057 ce062d50 2019-08-21 martijn return; /* paused */
1058 ce062d50 2019-08-21 martijn break;
1059 ce062d50 2019-08-21 martijn default:
1060 ce062d50 2019-08-21 martijn errx(1, "io_reload_tls(): bad state");
1061 ce062d50 2019-08-21 martijn }
1062 ce062d50 2019-08-21 martijn
1063 ce062d50 2019-08-21 martijn io_reset(io, ev, dispatch);
1064 ce062d50 2019-08-21 martijn }
1065 ce062d50 2019-08-21 martijn
1066 ce062d50 2019-08-21 martijn #endif /* IO_TLS */