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