commit 98d3e6c172747dc58042bde09a848d3e03572934 from: Omar Polo date: Sun Feb 18 23:09:32 2024 UTC convert telescope to use ev instead of libevent libevent is a very cool library, I like the APIs and enjoy using it. However, telescope is not as large and doesn't have as many file descriptor, so libevent is quite ``too big'' for our needs. ev started as a small event loop on top of poll(2) for amused, and can be used here too, it just needed to grow the ability to handle several timers, as we need quite some on telescope (in fact, we use more timers than fds!) commit - b19b8dbca985e2f567bb3f476b116ea18c1ca9a2 commit + 98d3e6c172747dc58042bde09a848d3e03572934 blob - 659ab9e8b4f977072e2cacadbf9af8244697ea4a blob + 46ec1afce4bacfa28a5124980c8dcf89ff1c154c --- Makefile.am +++ Makefile.am @@ -4,7 +4,9 @@ bin_PROGRAMS = telescope telescope-identity EXTRA_telescope_SOURCES = compat/ohash.h compat/queue.h compat/imsg.h contrib -telescope_SOURCES = certs.c \ +telescope_SOURCES = bufio.c \ + bufio.h \ + certs.c \ certs.h \ cmd.c \ cmd.gen.c \ @@ -18,6 +20,8 @@ telescope_SOURCES = certs.c \ defaults.h \ downloads.c \ emoji-matcher.c \ + ev.c \ + ev.h \ fs.c \ fs.h \ gencmd.awk \ @@ -61,6 +65,8 @@ telescope_SOURCES = certs.c \ telescope_identity_SOURCES = \ certs.c \ certs.h \ + ev.c \ + ev.h \ fs.c \ fs.h \ hist.c \ @@ -68,7 +74,7 @@ telescope_identity_SOURCES = \ identity.c \ parser.c \ parser.h \ - utils.c \ + utils.c \ utils.h noinst_PROGRAMS = pagebundler blob - 8928556709972b28db62863d0b7aeb0dd403b236 blob + 99b46defa92628536ea7bd98665fe2b7cbd877e0 --- cmd.c +++ cmd.c @@ -24,6 +24,7 @@ #include "cmd.h" #include "compl.h" #include "defaults.h" +#include "ev.h" #include "hist.h" #include "keymap.h" #include "mcache.h" @@ -278,7 +279,7 @@ kill_telescope_cb(int r, struct tab *tab) { if (r) { save_session(); - event_loopbreak(); + ev_break(); } } blob - de06e6b654820fabe2d2634479ec69a0d184441c blob + e83e196c254ef03fb7eeec1c996028ee967634be --- compat.h +++ compat.h @@ -52,19 +52,6 @@ # error no compatible endian.h header found #endif -#if HAVE_EVENT2 -# include -# include -# include -# include -# include -# include -# include -# include -#else -# include -#endif - #ifdef HAVE_QUEUE_H # include #else blob - 73930b982ee6b2c5b3dabf2fe2d223b2f959dd9f blob + db4a22fe78ee5db9f37557e66e93c8729dd84519 --- control.c +++ control.c @@ -30,6 +30,7 @@ #include #include "control.h" +#include "ev.h" #include "minibuffer.h" #include "telescope.h" #include "utils.h" @@ -38,8 +39,7 @@ #define CONTROL_BACKLOG 5 struct { - struct event ev; - struct event evt; + unsigned long timeout; int fd; } control_state = {.fd = -1}; @@ -110,23 +110,19 @@ control_listen(int fd) return (-1); } - event_set(&control_state.ev, control_state.fd, EV_READ, - control_accept, NULL); - event_add(&control_state.ev, NULL); - evtimer_set(&control_state.evt, control_accept, NULL); - + ev_add(control_state.fd, EV_READ, control_accept, NULL); return (0); } void -control_accept(int listenfd, short event, void *bula) +control_accept(int listenfd, int event, void *bula) { int connfd; socklen_t len; struct sockaddr_un sun; struct ctl_conn *c; - event_add(&control_state.ev, NULL); + ev_add(control_state.fd, EV_READ, control_accept, NULL); if ((event & EV_TIMEOUT)) return; @@ -134,13 +130,14 @@ control_accept(int listenfd, short event, void *bula) if ((connfd = accept(listenfd, (struct sockaddr *)&sun, &len)) == -1) { /* * Pause accept if we are out of file descriptors, or - * libevent will haunt us here too. + * ev will haunt us here too. */ if (errno == ENFILE || errno == EMFILE) { struct timeval evtpause = { 1, 0 }; - event_del(&control_state.ev); - evtimer_add(&control_state.evt, &evtpause); + ev_del(control_state.fd); + control_state.timeout = ev_timer(&evtpause, + control_accept, NULL); } else if (errno != EWOULDBLOCK && errno != EINTR && errno != ECONNABORTED) message("%s: accept4: %s", __func__, strerror(errno)); @@ -163,9 +160,12 @@ control_accept(int listenfd, short event, void *bula) imsg_init(&c->iev.ibuf, connfd); c->iev.handler = control_dispatch_imsg; c->iev.events = EV_READ; - event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, - c->iev.handler, &c->iev); - event_add(&c->iev.ev, NULL); + if (ev_add(connfd, c->iev.events, c->iev.handler, &c->iev) == -1) { + message("%s: ev_add: %s", __func__, strerror(errno)); + close(connfd); + free(c); + return; + } TAILQ_INSERT_TAIL(&ctl_conns, c, entry); } @@ -209,20 +209,21 @@ control_close(int fd) msgbuf_clear(&c->iev.ibuf.w); TAILQ_REMOVE(&ctl_conns, c, entry); - event_del(&c->iev.ev); + ev_del(c->iev.ibuf.fd); close(c->iev.ibuf.fd); /* Some file descriptors are available again. */ - if (evtimer_pending(&control_state.evt, NULL)) { - evtimer_del(&control_state.evt); - event_add(&control_state.ev, NULL); + if (ev_timer_pending(control_state.timeout)) { + ev_timer_cancel(control_state.timeout); + control_state.timeout = 0; + ev_add(control_state.fd, EV_READ, control_accept, NULL); } free(c); } void -control_dispatch_imsg(int fd, short event, void *bula) +control_dispatch_imsg(int fd, int event, void *bula) { struct ctl_conn *c; struct imsg imsg; blob - c779aaeb95cf5546bf933fe861acf75b7474d386 blob + 83562a8d7d6323eb000e8daf7bff0c57faf64700 --- control.h +++ control.h @@ -19,6 +19,6 @@ #ifndef SMALL int control_init(char *); int control_listen(int); -void control_accept(int, short, void *); -void control_dispatch_imsg(int, short, void *); +void control_accept(int, int, void *); +void control_dispatch_imsg(int, int, void *); #endif /* SMALL */ blob - 3e60428279ef2a543079d6aae59d4faa4249cabd blob + ccb1c1f16740952e7d570287251025d2eadd9a74 --- mcache.c +++ mcache.c @@ -16,17 +16,20 @@ #include "compat.h" +#include + #include #include #include +#include "ev.h" #include "hist.h" #include "mcache.h" #include "parser.h" #include "utils.h" static struct timeval tv = { 5 * 60, 0 }; -static struct event timerev; +static unsigned int timeout; static struct ohash h; static size_t npages; @@ -59,7 +62,7 @@ mcache_free_entry(const char *url) } static void -clean_old_entries(int fd, short ev, void *data) +clean_old_entries(int fd, int ev, void *data) { struct mcache_entry *e; unsigned int i; @@ -72,7 +75,7 @@ clean_old_entries(int fd, short ev, void *data) if (e->ts < treshold) mcache_free_entry(e->url); - evtimer_add(&timerev, &tv); + timeout = ev_timer(&tv, clean_old_entries, NULL); } void @@ -86,8 +89,6 @@ mcache_init(void) }; ohash_init(&h, 5, &info); - - evtimer_set(&timerev, clean_old_entries, NULL); } int @@ -127,8 +128,8 @@ mcache_tab(struct tab *tab) npages++; tot += e->buflen; - if (!evtimer_pending(&timerev, NULL)) - evtimer_add(&timerev, &tv); + if (!ev_timer_pending(timeout)) + timeout = ev_timer(&tv, clean_old_entries, NULL); return 0; blob - 8b73b7a720677518f8c1cbf84d5024ba473567fa blob + b3c3efce84a1314766b58c3874096490c548edf7 --- minibuffer.c +++ minibuffer.c @@ -16,6 +16,8 @@ #include "compat.h" +#include + #include #include #include @@ -25,6 +27,7 @@ #include "certs.h" #include "cmd.h" #include "defaults.h" +#include "ev.h" #include "fs.h" #include "hist.h" #include "iri.h" @@ -45,10 +48,10 @@ static void yornp_abort(void); static void read_self_insert(void); static void read_abort(void); static void read_select(void); -static void handle_clear_echoarea(int, short, void *); +static void handle_clear_echoarea(int, int, void *); -static struct event clechoev; -static struct timeval clechoev_timer = { 5, 0 }; +static unsigned long clechotimer; +static struct timeval clechotv = { 5, 0 }; static void (*yornp_cb)(int, struct tab *); static struct tab *yornp_data; @@ -642,7 +645,7 @@ minibuffer_read(const char *prompt, void (*fn)(const c } static void -handle_clear_echoarea(int fd, short ev, void *d) +handle_clear_echoarea(int fd, int ev, void *d) { free(ministate.curmesg); ministate.curmesg = NULL; @@ -653,15 +656,14 @@ handle_clear_echoarea(int fd, short ev, void *d) void vmessage(const char *fmt, va_list ap) { - if (evtimer_pending(&clechoev, NULL)) - evtimer_del(&clechoev); + ev_timer_cancel(clechotimer); free(ministate.curmesg); ministate.curmesg = NULL; if (fmt != NULL) { - evtimer_set(&clechoev, handle_clear_echoarea, NULL); - evtimer_add(&clechoev, &clechoev_timer); + clechotimer = ev_timer(&clechotv, handle_clear_echoarea, + NULL); /* TODO: what to do if the allocation fails here? */ if (vasprintf(&ministate.curmesg, fmt, ap) == -1) @@ -697,6 +699,4 @@ minibuffer_init(void) ministate.vline.parent = &ministate.line; ministate.buffer.page.name = "*minibuffer*"; ministate.buffer.current_line = &ministate.vline; - - evtimer_set(&clechoev, handle_clear_echoarea, NULL); } blob - f9f6b98d8a2c8649026269776fb9304e788086ca blob + d0bf32c05c2e6a792754779e460ce76a4c17b200 --- net.c +++ net.c @@ -16,6 +16,9 @@ #include "compat.h" +/* XXX needs some work to run on top of ev */ +#undef HAVE_ASR_RUN + #include #include #include @@ -38,17 +41,28 @@ # include #endif +#include "bufio.h" +#include "ev.h" #include "telescope.h" #include "utils.h" static struct imsgev *iev_ui; +enum conn_state { + CONN_CONNECTING, + CONN_HANDSHAKE, + CONN_HEADER, + CONN_BODY, + CONN_CLOSE, + CONN_ERROR, +}; + /* a pending request */ struct req { uint32_t id; + enum conn_state state; int proto; int fd; - struct tls *ctx; char *host; char *port; char *req; @@ -56,9 +70,11 @@ struct req { void *ccert; size_t ccert_len; int ccert_fd; - int done_header; - struct bufferevent *bev; + int eof; + unsigned int handshake_tout; + struct bufio bio; + int conn_error; const char *cause; @@ -75,7 +91,6 @@ static struct req *req_by_id(uint32_t); static void die(void) __attribute__((__noreturn__)); -static void try_to_connect(int, short, void*); #if HAVE_ASR_RUN static void query_done(struct asr_result*, void*); @@ -86,40 +101,18 @@ static void close_with_err(struct req*, const char*); static void close_with_errf(struct req*, const char*, ...) __attribute__((format(printf, 2, 3))); -static void net_tls_handshake(int, short, void *); -static void net_tls_readcb(int, short, void *); -static void net_tls_writecb(int, short, void *); - +static int try_to_connect(struct req *); static int gemini_parse_reply(struct req *, const char *, size_t); +static void net_ev(int, int, void *); +static void handle_dispatch_imsg(int, int, void*); -static void net_ready(struct req *req); -static void net_read(struct bufferevent *, void *); -static void net_write(struct bufferevent *, void *); -static void net_error(struct bufferevent *, short, void *); - -static void handle_dispatch_imsg(int, short, void*); - static int net_send_ui(int, uint32_t, const void *, uint16_t); /* TODO: making this customizable */ struct timeval timeout_for_handshake = { 5, 0 }; -typedef void (*statefn)(int, short, void*); - TAILQ_HEAD(, req) reqhead; -static inline void -yield_r(struct req *req, statefn fn, struct timeval *tv) -{ - event_once(req->fd, EV_READ, fn, req, tv); -} - -static inline void -yield_w(struct req *req, statefn fn, struct timeval *tv) -{ - event_once(req->fd, EV_WRITE, fn, req, tv); -} - static struct req * req_by_id(uint32_t id) { @@ -139,117 +132,6 @@ die(void) abort(); /* TODO */ } -static void -try_to_connect(int fd, short ev, void *d) -{ - struct req *req = d; - int error = 0; - socklen_t len = sizeof(error); - -again: - if (req->p == NULL) - goto err; - - if (req->fd != -1) { - if (getsockopt(req->fd, SOL_SOCKET, SO_ERROR, &error, - &len) == -1) - goto err; - if (error != 0) { - req->conn_error = error; - req->cause = "connect"; - close(req->fd); - req->fd = -1; - req->p = req->p->ai_next; - goto again; - } - goto done; - } - - req->fd = socket(req->p->ai_family, req->p->ai_socktype, - req->p->ai_protocol); - if (req->fd == -1) { - req->conn_error = errno; - req->cause = "socket"; - req->p = req->p->ai_next; - goto again; - } - - if (!mark_nonblock_cloexec(req->fd)) { - req->conn_error = errno; - req->cause = "setsockopt"; - goto err; - } - if (connect(req->fd, req->p->ai_addr, req->p->ai_addrlen) == 0) - goto done; - yield_w(req, try_to_connect, NULL); - return; - -err: - freeaddrinfo(req->servinfo); - close_with_errf(req, "failed to connect to %s (%s: %s.)", req->host, - req->cause, strerror(req->conn_error)); - return; - -done: - freeaddrinfo(req->servinfo); - - switch (req->proto) { - case PROTO_FINGER: - case PROTO_GOPHER: - /* finger and gopher don't have a header nor TLS */ - req->done_header = 1; - net_ready(req); - break; - - case PROTO_GEMINI: { - struct tls_config *conf; - - if ((conf = tls_config_new()) == NULL) - die(); - - tls_config_insecure_noverifycert(conf); - tls_config_insecure_noverifyname(conf); - - if (req->ccert && tls_config_set_keypair_mem(conf, - req->ccert, req->ccert_len, req->ccert, req->ccert_len) - == -1) { - close_with_errf(req, "failed to load keypair: %s", - tls_config_error(conf)); - tls_config_free(conf); - return; - } - - /* prepare tls */ - if ((req->ctx = tls_client()) == NULL) { - close_with_errf(req, "tls_client: %s", - strerror(errno)); - tls_config_free(conf); - return; - } - - if (tls_configure(req->ctx, conf) == -1) { - close_with_errf(req, "tls_configure: %s", - tls_error(req->ctx)); - tls_config_free(conf); - return; - } - tls_config_free(conf); - - if (tls_connect_socket(req->ctx, req->fd, req->host) - == -1) { - close_with_errf(req, "tls_connect_socket: %s", - tls_error(req->ctx)); - return; - } - yield_w(req, net_tls_handshake, &timeout_for_handshake); - break; - } - - default: - die(); - } -} - #if HAVE_ASR_RUN static void query_done(struct asr_result *res, void *d) @@ -266,7 +148,8 @@ query_done(struct asr_result *res, void *d) req->fd = -1; req->servinfo = res->ar_addrinfo; req->p = res->ar_addrinfo; - try_to_connect(0, 0, req); + req->state = CONN_CONNECTING; + net_ev(-1, EV_READ, req); } static void @@ -300,39 +183,41 @@ conn_towards(struct req *req) req->fd = -1; req->p = req->servinfo; - try_to_connect(0, 0, req); + req->state = CONN_CONNECTING; + net_ev(-1, EV_READ, req); } #endif static void -close_conn(int fd, short ev, void *d) +close_conn(int fd, int ev, void *d) { struct req *req = d; + if (req->state != CONN_ERROR) + req->state = CONN_CLOSE; + #if HAVE_ASR_RUN if (req->asrev != NULL) event_asr_abort(req->asrev); #endif - if (req->bev != NULL) { - bufferevent_free(req->bev); - req->bev = NULL; + if (req->handshake_tout != 0) { + ev_timer_cancel(req->handshake_tout); + req->handshake_tout = 0; } - if (req->ctx != NULL) { - switch (tls_close(req->ctx)) { - case TLS_WANT_POLLIN: - yield_r(req, close_conn, NULL); - return; - case TLS_WANT_POLLOUT: - yield_w(req, close_conn, NULL); - return; - } - - tls_free(req->ctx); - req->ctx = NULL; + if (req->state == CONN_CLOSE && + bufio_close(&req->bio) == -1 && + errno == EAGAIN) { + ev_add(req->fd, bufio_ev(&req->bio), close_conn, req); + return; } + if (req->servinfo) + freeaddrinfo(req->servinfo); + + bufio_free(&req->bio); + if (req->ccert != NULL) { munmap(req->ccert, req->ccert_len); close(req->ccert_fd); @@ -343,14 +228,17 @@ close_conn(int fd, short ev, void *d) free(req->req); TAILQ_REMOVE(&reqhead, req, reqs); - if (req->fd != -1) + if (req->fd != -1) { + ev_del(req->fd); close(req->fd); + } free(req); } static void close_with_err(struct req *req, const char *err) { + req->state = CONN_ERROR; net_send_ui(IMSG_ERR, req->id, err, strlen(err)+1); close_conn(0, 0, req); } @@ -370,138 +258,54 @@ close_with_errf(struct req *req, const char *fmt, ...) free(s); } -static void -net_tls_handshake(int fd, short event, void *d) +static int +try_to_connect(struct req *req) { - struct req *req = d; - const char *hash; + int error; + socklen_t len = sizeof(error); - if (event == EV_TIMEOUT) { - close_with_err(req, "Timeout loading page"); - return; - } + again: + if (req->p == NULL) + return (-1); - switch (tls_handshake(req->ctx)) { - case TLS_WANT_POLLIN: - yield_r(req, net_tls_handshake, NULL); - return; - case TLS_WANT_POLLOUT: - yield_w(req, net_tls_handshake, NULL); - return; - } + if (req->fd != -1) { + if (getsockopt(req->fd, SOL_SOCKET, SO_ERROR, &error, + &len) == -1) { + req->conn_error = errno; + req->cause = "getsockopt"; + return (-1); + } - hash = tls_peer_cert_hash(req->ctx); - if (hash == NULL) { - close_with_errf(req, "handshake failed: %s", - tls_error(req->ctx)); - return; - } - net_send_ui(IMSG_CHECK_CERT, req->id, hash, strlen(hash)+1); -} + if (error == 0) /* connected */ + return (0); -static void -net_tls_readcb(int fd, short event, void *d) -{ - struct bufferevent *bufev = d; - struct req *req = bufev->cbarg; - char buf[IBUF_READ_SIZE]; - int what = EVBUFFER_READ; - int howmuch = IBUF_READ_SIZE; - int res; - ssize_t ret; - size_t len; - - if (event == EV_TIMEOUT) { - what |= EVBUFFER_TIMEOUT; - goto err; + req->conn_error = error; + req->cause = "connect"; + close(req->fd); + req->fd = -1; + req->p = req->p->ai_next; + goto again; } - if (bufev->wm_read.high != 0) - howmuch = MIN(sizeof(buf), bufev->wm_read.high); - - switch (ret = tls_read(req->ctx, buf, howmuch)) { - case TLS_WANT_POLLIN: - case TLS_WANT_POLLOUT: - goto retry; - case -1: - what |= EVBUFFER_ERROR; - goto err; - } - len = ret; - - if (len == 0) { - what |= EVBUFFER_EOF; - goto err; - } - - res = evbuffer_add(bufev->input, buf, len); - if (res == -1) { - what |= EVBUFFER_ERROR; - goto err; - } - - event_add(&bufev->ev_read, NULL); - - len = EVBUFFER_LENGTH(bufev->input); - if (bufev->wm_read.low != 0 && len < bufev->wm_read.low) - return; - - if (bufev->readcb != NULL) - (*bufev->readcb)(bufev, bufev->cbarg); - return; - -retry: - event_add(&bufev->ev_read, NULL); - return; - -err: - (*bufev->errorcb)(bufev, what, bufev->cbarg); -} - -static void -net_tls_writecb(int fd, short event, void *d) -{ - struct bufferevent *bufev = d; - struct req *req = bufev->cbarg; - ssize_t ret; - size_t len; - short what = EVBUFFER_WRITE; - - if (event & EV_TIMEOUT) { - what |= EVBUFFER_TIMEOUT; - goto err; + req->fd = socket(req->p->ai_family, req->p->ai_socktype, + req->p->ai_protocol); + if (req->fd == -1) { + req->conn_error = errno; + req->cause = "socket"; + req->p = req->p->ai_next; + goto again; } - if (EVBUFFER_LENGTH(bufev->output) != 0) { - ret = tls_write(req->ctx, EVBUFFER_DATA(bufev->output), - EVBUFFER_LENGTH(bufev->output)); - switch (ret) { - case TLS_WANT_POLLIN: - case TLS_WANT_POLLOUT: - goto retry; - case -1: - what |= EVBUFFER_ERROR; - goto err; - } - len = ret; - - evbuffer_drain(bufev->output, len); + if (!mark_nonblock_cloexec(req->fd)) { + req->conn_error = errno; + req->cause = "setsockopt"; + return (-1); } - if (EVBUFFER_LENGTH(bufev->output) != 0) - event_add(&bufev->ev_write, NULL); - - if (bufev->writecb != NULL && - EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low) - (*bufev->writecb)(bufev, bufev->cbarg); - return; - -retry: - event_add(&bufev->ev_write, NULL); - return; - -err: - (*bufev->errorcb)(bufev, what, bufev->cbarg); + if (connect(req->fd, req->p->ai_addr, req->p->ai_addrlen) == 0) + return (0); + errno = EAGAIN; + return (-1); } static int @@ -533,140 +337,164 @@ gemini_parse_reply(struct req *req, const char *header imsg_close(&iev_ui->ibuf, ibuf); imsg_event_add(iev_ui); - bufferevent_disable(req->bev, EV_READ|EV_WRITE); + /* pause until we've told go go ahead */ + ev_del(req->fd); return code; } -/* called when we're ready to read/write */ -static void -net_ready(struct req *req) +static inline int +net_send_req(struct req *req) { - req->bev = bufferevent_new(req->fd, net_read, net_write, net_error, - req); - if (req->bev == NULL) - die(); - -#if HAVE_EVENT2 - evbuffer_unfreeze(req->bev->input, 0); - evbuffer_unfreeze(req->bev->output, 1); -#endif - - /* setup tls i/o layer */ - if (req->ctx != NULL) { - event_set(&req->bev->ev_read, req->fd, EV_READ, - net_tls_readcb, req->bev); - event_set(&req->bev->ev_write, req->fd, EV_WRITE, - net_tls_writecb, req->bev); - } - - /* TODO: adjust watermarks */ - bufferevent_setwatermark(req->bev, EV_WRITE, 1, 0); - bufferevent_setwatermark(req->bev, EV_READ, 1, 0); - - bufferevent_enable(req->bev, EV_READ|EV_WRITE); - - bufferevent_write(req->bev, req->req, req->len); + return (bufio_compose(&req->bio, req->req, req->len)); } -/* called after a read has been done */ static void -net_read(struct bufferevent *bev, void *d) +net_ev(int fd, int ev, void *d) { static char buf[4096]; struct req *req = d; - struct evbuffer *src = EVBUFFER_INPUT(bev); + const char *hash; + ssize_t read; size_t len; + char *header, *endl; int r; - char *header; - if (!req->done_header) { - header = evbuffer_readln(src, &len, EVBUFFER_EOL_CRLF_STRICT); - if (header == NULL && EVBUFFER_LENGTH(src) >= 1024) { - (*bev->errorcb)(bev, EVBUFFER_READ, bev->cbarg); + if (ev == EV_TIMEOUT) { + close_with_err(req, "Timeout loading page"); + return; + } + + if (req->state == CONN_CONNECTING) { + ev_del(req->fd); + if (try_to_connect(req) == -1) { + if (req->fd != -1 && errno == EAGAIN) { + ev_add(req->fd, EV_WRITE, net_ev, req); + return; + } + close_with_errf(req, "failed to connect to %s" + " (%s: %s)", req->host, req->cause, + strerror(req->conn_error)); return; } - if (header == NULL) + + bufio_set_fd(&req->bio, req->fd); + + switch (req->proto) { + case PROTO_FINGER: + case PROTO_GOPHER: + /* finger and gopher don't have a header nor TLS */ + req->state = CONN_BODY; + if (net_send_req(req) == -1) { + close_with_err(req, "failed to send request"); + return; + } + break; + case PROTO_GEMINI: + req->state = CONN_HANDSHAKE; + if (bufio_starttls(&req->bio, req->host, 1, + req->ccert, req->ccert_len, + req->ccert, req->ccert_len) == -1) { + close_with_err(req, "failed to setup TLS"); + return; + } + req->handshake_tout = ev_timer(&timeout_for_handshake, + net_ev, req); + if (req->handshake_tout == 0) { + close_with_err(req, "failed to setup" + " handshake timer"); + return; + } + break; + } + } + + if (req->state == CONN_HANDSHAKE) { + if (bufio_handshake(&req->bio) == -1 && errno == EAGAIN) { + ev_add(req->fd, bufio_ev(&req->bio), + net_ev, req); return; - r = gemini_parse_reply(req, header, len); - free(header); - req->done_header = 1; - if (r == 0) { - (*bev->errorcb)(bev, EVBUFFER_READ, bev->cbarg); - return; } - if (r < 20 || r >= 30) { - close_conn(0, 0, req); + + ev_timer_cancel(req->handshake_tout); + req->handshake_tout = 0; + + req->state = CONN_HEADER; + + /* pause until we've told the certificate is OK */ + ev_del(req->fd); + + hash = tls_peer_cert_hash(req->bio.ctx); + if (hash == NULL) { + close_with_errf(req, "handshake failed: %s", + tls_error(req->bio.ctx)); return; } - } - /* - * Split data into chunks before sending. imsg can't handle - * message that are "too big". - */ - for (;;) { - if ((len = bufferevent_read(bev, buf, sizeof(buf))) == 0) - break; - net_send_ui(IMSG_BUF, req->id, buf, len); + net_send_ui(IMSG_CHECK_CERT, req->id, hash, strlen(hash)+1); + return; } -} -/* called after a write has been done */ -static void -net_write(struct bufferevent *bev, void *d) -{ - struct evbuffer *dst = EVBUFFER_OUTPUT(bev); - - if (EVBUFFER_LENGTH(dst) == 0) - (*bev->errorcb)(bev, EVBUFFER_WRITE, bev->cbarg); -} - -static void -net_error(struct bufferevent *bev, short error, void *d) -{ - struct req *req = d; - struct evbuffer *src; - - if (error & EVBUFFER_TIMEOUT) { - close_with_err(req, "Timeout loading page"); - return; + if (ev & EV_READ) { + read = bufio_read(&req->bio); + if (read == -1 && errno != EAGAIN) { + close_with_errf(req, "Read error"); + return; + } + if (read == 0) + req->eof = 1; } - if (error & EVBUFFER_ERROR) { - close_with_errf(req, "%s error (0x%x)", - (error & EVBUFFER_READ) ? "read" : "write", error); + if ((ev & EV_WRITE) && bufio_write(&req->bio) == -1 && + errno != EAGAIN) { + close_with_errf(req, "bufio_write: %s", strerror(errno)); return; } - if (error & EVBUFFER_EOF) { - /* EOF and no header */ - if (!req->done_header) { - close_with_err(req, "protocol error"); + if (req->state == CONN_HEADER) { + header = req->bio.rbuf.buf; + endl = memmem(header, req->bio.rbuf.len, "\r\n", 2); + if (endl == NULL && req->bio.rbuf.len >= 1024) { + close_with_err(req, "Invalid gemini reply (too long)"); return; } - - src = EVBUFFER_INPUT(req->bev); - if (EVBUFFER_LENGTH(src) != 0) - net_send_ui(IMSG_BUF, req->id, EVBUFFER_DATA(src), - EVBUFFER_LENGTH(src)); - net_send_ui(IMSG_EOF, req->id, NULL, 0); - close_conn(0, 0, req); + if (endl == NULL && req->eof) { + close_with_err(req, "Invalid gemini reply."); + return; + } + if (endl == NULL) { + ev_add(req->fd, bufio_ev(&req->bio), net_ev, req); + return; + } + *endl = '\0'; + req->state = CONN_BODY; + r = gemini_parse_reply(req, header, strlen(header)); + buf_drain(&req->bio.rbuf, endl - header + 2); + if (r == 0) { + close_with_err(req, "Malformed gemini reply"); + return; + } + if (r < 20 || r >= 30) + close_conn(0, 0, req); return; } - - if (error & EVBUFFER_WRITE) { - /* finished sending request */ - bufferevent_disable(bev, EV_WRITE); - return; + + /* + * Split data into chunks before sending. imsg can't handle + * message that are "too big". + */ + for (;;) { + if ((len = bufio_drain(&req->bio, buf, sizeof(buf))) == 0) + break; + net_send_ui(IMSG_BUF, req->id, buf, len); } - if (error & EVBUFFER_READ) { - close_with_err(req, "protocol error"); - return; + if (req->eof) { + net_send_ui(IMSG_EOF, req->id, NULL, 0); + close_conn(0, 0, req); } - close_with_errf(req, "unknown event error %x", error); + ev_add(req->fd, bufio_ev(&req->bio), net_ev, req); } static int @@ -702,7 +530,7 @@ load_cert(struct imsg *imsg, struct req *req) } static void -handle_dispatch_imsg(int fd, short event, void *d) +handle_dispatch_imsg(int fd, int event, void *d) { struct imsgev *iev = d; struct imsgbuf *ibuf = &iev->ibuf; @@ -757,9 +585,10 @@ handle_dispatch_imsg(int fd, short event, void *d) die(); if (load_cert(&imsg, req) == -1) die(); + if (bufio_init(&req->bio) == -1) + die(); req->len = strlen(req->req); - req->proto = r.proto; conn_towards(req); break; @@ -771,16 +600,28 @@ handle_dispatch_imsg(int fd, short event, void *d) if (imsg_get_data(&imsg, &certok, sizeof(certok)) == -1) die(); - if (certok) - net_ready(req); - else + if (!certok) { close_conn(0, 0, req); + break; + } + + if (net_send_req(req) == -1) { + close_with_err(req, "failed to send request"); + break; + } + + if (ev_add(req->fd, EV_WRITE, net_ev, req) == -1) { + close_with_err(req, + "failed to register event."); + break; + } break; case IMSG_PROCEED: if ((req = req_by_id(imsg_get_id(&imsg))) == NULL) break; - bufferevent_enable(req->bev, EV_READ); + ev_add(req->fd, EV_READ, net_ev, req); + net_ev(req->fd, 0, req); break; case IMSG_STOP: @@ -790,7 +631,7 @@ handle_dispatch_imsg(int fd, short event, void *d) break; case IMSG_QUIT: - event_loopbreak(); + ev_break(); imsg_free(&imsg); return; @@ -819,7 +660,8 @@ net_main(void) TAILQ_INIT(&reqhead); - event_init(); + if (ev_init() == -1) + exit(1); /* Setup pipe and event handler to the main process */ if ((iev_ui = malloc(sizeof(*iev_ui))) == NULL) @@ -827,13 +669,11 @@ net_main(void) imsg_init(&iev_ui->ibuf, 3); iev_ui->handler = handle_dispatch_imsg; iev_ui->events = EV_READ; - event_set(&iev_ui->ev, iev_ui->ibuf.fd, iev_ui->events, - iev_ui->handler, iev_ui); - event_add(&iev_ui->ev, NULL); + ev_add(iev_ui->ibuf.fd, iev_ui->events, iev_ui->handler, iev_ui); sandbox_net_process(); - event_dispatch(); + ev_loop(); msgbuf_clear(&iev_ui->ibuf.w); close(iev_ui->ibuf.fd); blob - 00ec289712d0468169ede9e25727384fb46c6299 blob + ea916a32f1698678ee10b0001f14d2568abd59e2 --- session.c +++ session.c @@ -16,6 +16,8 @@ #include "compat.h" +#include + #include #include #include @@ -26,6 +28,7 @@ #include #include "defaults.h" +#include "ev.h" #include "fs.h" #include "hist.h" #include "minibuffer.h" @@ -35,7 +38,7 @@ struct history history; -static struct event autosaveev; +static unsigned int autosavetimer; void switch_to_tab(struct tab *tab) @@ -65,19 +68,18 @@ new_tab(const char *url, const char *base, struct tab autosave_hook(); if ((tab = calloc(1, sizeof(*tab))) == NULL) { - event_loopbreak(); + ev_break(); return NULL; } if ((tab->hist = hist_new(HIST_LINEAR)) == NULL) { free(tab); - event_loopbreak(); + ev_break(); return NULL; } TAILQ_INIT(&tab->buffer.head); TAILQ_INIT(&tab->buffer.page.head); - evtimer_set(&tab->loadingev, NULL, NULL); tab->id = tab_new_id(); @@ -111,8 +113,7 @@ kill_tab(struct tab *tab, int append) ui_schedule_redraw(); autosave_hook(); - if (evtimer_pending(&tab->loadingev, NULL)) - evtimer_del(&tab->loadingev); + ev_timer_cancel(tab->loading_timer); if (append) TAILQ_INSERT_TAIL(&ktabshead, tab, tabs); @@ -406,11 +407,11 @@ history_add(const char *uri) void autosave_init(void) { - evtimer_set(&autosaveev, autosave_timer, NULL); + return; } void -autosave_timer(int fd, short event, void *data) +autosave_timer(int fd, int event, void *data) { save_session(); } @@ -427,11 +428,11 @@ autosave_hook(void) if (autosave <= 0) return; - if (!evtimer_pending(&autosaveev, NULL)) { + if (!ev_timer_pending(autosavetimer)) { tv.tv_sec = autosave; tv.tv_usec = 0; - evtimer_add(&autosaveev, &tv); + autosavetimer = ev_timer(&tv, autosave_timer, NULL); } } blob - bf1ec4d751e38ebc8a2188849d6202fd717c1a79 blob + 52ea5baad8d6c7c51f1126311fa7267a8137b001 --- session.h +++ session.h @@ -67,7 +67,7 @@ void history_sort(void); void history_add(const char *); void autosave_init(void); -void autosave_timer(int, short, void *); +void autosave_timer(int, int, void *); void autosave_hook(void); int load_session(struct ohash *); blob - ef2f9c40c819f99968ab181beedb609c3e3a7a84 blob + 4e71ecbaff97f7964d344324aed229fd8d1cf793 --- telescope.c +++ telescope.c @@ -17,6 +17,7 @@ #include "compat.h" #include +#include #include #include @@ -34,6 +35,7 @@ #include "cmd.h" #include "control.h" #include "defaults.h" +#include "ev.h" #include "fs.h" #include "hist.h" #include "iri.h" @@ -119,7 +121,7 @@ static void handle_check_cert_user_choice(int, struc static void handle_maybe_save_new_cert(int, struct tab *); static void handle_maybe_save_page(int, struct tab *); static void handle_save_page_path(const char *, struct tab *); -static void handle_dispatch_imsg(int, short, void *); +static void handle_dispatch_imsg(int, int, void *); static void load_about_url(struct tab *, const char *); static void load_file_url(struct tab *, const char *); static void load_finger_url(struct tab *, const char *); @@ -435,7 +437,7 @@ handle_save_page_path(const char *path, struct tab *ta } static void -handle_dispatch_imsg(int fd, short event, void *data) +handle_dispatch_imsg(int fd, int event, void *data) { struct imsgev *iev = data; struct imsgbuf *imsgbuf = &iev->ibuf; @@ -844,7 +846,7 @@ load_url(struct tab *tab, const char *url, const char if (dohist) { if (hist_push(tab->hist, url) == -1) { - event_loopbreak(); + ev_break(); return; } @@ -1165,7 +1167,8 @@ main(int argc, char * const *argv) /* initialize tofu store */ tofu_init(&certs, 5, offsetof(struct tofu_entry, domain)); - event_init(); + if (ev_init() == -1) + err(1, "ev_init"); if (!safe_mode) { if ((control_fd = control_init(ctlsock_path)) == -1) @@ -1181,9 +1184,7 @@ main(int argc, char * const *argv) /* Setup event handlers for pipes to net */ iev_net->events = EV_READ; - event_set(&iev_net->ev, iev_net->ibuf.fd, iev_net->events, - iev_net->handler, iev_net); - event_add(&iev_net->ev, NULL); + ev_add(iev_net->ibuf.fd, iev_net->events, iev_net->handler, iev_net); if (ui_init()) { sandbox_ui_process(); blob - cf1297fdfadd033ea352e0e23b27b1d18d0c8292 blob + 80534e7a35a0ef841f9140001c72bf13ca683226 --- telescope.h +++ telescope.h @@ -33,8 +33,7 @@ struct imsgev { struct imsgbuf ibuf; - void (*handler)(int, short, void *); - struct event ev; + void (*handler)(int, int, void *); short events; }; @@ -206,7 +205,7 @@ struct tab { short loading_anim; short loading_anim_step; - struct event loadingev; + unsigned long loading_timer; }; extern TAILQ_HEAD(proxylist, proxy) proxies; blob - c80797e2f3b87797fb9e8964e4826553f82d7192 blob + 67514fe337cc20f21f8eb58d02e1c55d9912bdbf --- ui.c +++ ui.c @@ -32,6 +32,8 @@ #include "compat.h" +#include + #include #include #include @@ -43,6 +45,7 @@ #include "cmd.h" #include "defaults.h" +#include "ev.h" #include "hist.h" #include "keymap.h" #include "minibuffer.h" @@ -51,17 +54,15 @@ #include "ui.h" #include "utf8.h" -static struct event stdioev, winchev; - static void set_scroll_position(struct tab *, size_t, size_t); static void restore_curs_x(struct buffer *); static int readkey(void); -static void dispatch_stdio(int, short, void*); -static void handle_resize(int, short, void*); -static void handle_resize_nodelay(int, short, void*); -static void handle_download_refresh(int, short, void *); +static void dispatch_stdio(int, int, void*); +static void handle_resize(int, int, void*); +static void handle_resize_nodelay(int, int, void*); +static void handle_download_refresh(int, int, void *); static void rearrange_windows(void); static void line_prefix_and_text(struct vline *, char *, size_t, const char **, const char **, int *); static void print_vline(int, int, WINDOW*, struct vline*); @@ -77,7 +78,7 @@ static void do_redraw_minibuffer(void); static void do_redraw_minibuffer_compl(void); static void place_cursor(int); static void redraw_tab(struct tab*); -static void update_loading_anim(int, short, void*); +static void update_loading_anim(int, int, void*); static void stop_loading_anim(struct tab*); static int should_rearrange_windows; @@ -88,10 +89,10 @@ static int x_offset; struct thiskey thiskey; struct tab *current_tab; -static struct event resizeev; -static struct timeval resize_timer = { 0, 250000 }; +static unsigned int resize_timer; +static struct timeval resize_tv = { 0, 250000 }; -static struct event download_refreshev; +static unsigned int download_timer; static struct timeval download_refresh_timer = { 0, 250000 }; static WINDOW *tabline, *body, *modeline, *echoarea, *minibuffer; @@ -112,7 +113,7 @@ int download_cols; static int side_window; static int in_side_window; -static struct timeval loadingev_timer = { 0, 250000 }; +static struct timeval loading_tv = { 0, 250000 }; static char keybuf[64]; @@ -296,7 +297,7 @@ readkey(void) } static void -dispatch_stdio(int fd, short ev, void *d) +dispatch_stdio(int fd, int ev, void *d) { int lk; const char *keyname; @@ -344,17 +345,14 @@ dispatch_stdio(int fd, short ev, void *d) } static void -handle_resize(int sig, short ev, void *d) +handle_resize(int sig, int ev, void *d) { - if (event_pending(&resizeev, EV_TIMEOUT, NULL)) { - event_del(&resizeev); - } - evtimer_set(&resizeev, handle_resize_nodelay, NULL); - evtimer_add(&resizeev, &resize_timer); + ev_timer_cancel(resize_timer); + resize_timer = ev_timer(&resize_tv, handle_resize_nodelay, NULL); } static void -handle_resize_nodelay(int s, short ev, void *d) +handle_resize_nodelay(int s, int ev, void *d) { endwin(); refresh(); @@ -364,7 +362,7 @@ handle_resize_nodelay(int s, short ev, void *d) } static void -handle_download_refresh(int s, short v, void *d) +handle_download_refresh(int s, int v, void *d) { if (side_window & SIDE_WINDOW_BOTTOM) { recompute_downloads(); @@ -1055,12 +1053,13 @@ start_loading_anim(struct tab *tab) if (tab->loading_anim) return; tab->loading_anim = 1; - evtimer_set(&tab->loadingev, update_loading_anim, tab); - evtimer_add(&tab->loadingev, &loadingev_timer); + + ev_timer_cancel(tab->loading_timer); + tab->loading_timer = ev_timer(&loading_tv, update_loading_anim, tab); } static void -update_loading_anim(int fd, short ev, void *d) +update_loading_anim(int fd, int ev, void *d) { struct tab *tab = d; @@ -1074,7 +1073,7 @@ update_loading_anim(int fd, short ev, void *d) wrefresh(echoarea); } - evtimer_add(&tab->loadingev, &loadingev_timer); + tab->loading_timer = ev_timer(&loading_tv, update_loading_anim, tab); } static void @@ -1082,7 +1081,8 @@ stop_loading_anim(struct tab *tab) { if (!tab->loading_anim) return; - evtimer_del(&tab->loadingev); + + ev_timer_cancel(tab->loading_timer); tab->loading_anim = 0; tab->loading_anim_step = 0; @@ -1173,19 +1173,14 @@ ui_init(void) void ui_main_loop(void) { - evtimer_set(&resizeev, handle_resize, NULL); - evtimer_set(&download_refreshev, handle_download_refresh, NULL); + if (ev_signal(SIGWINCH, handle_resize, NULL) == -1 || + ev_add(0, EV_READ, dispatch_stdio, NULL) == -1) + err(1, "ev_signal or ev_add failed"); - event_set(&stdioev, 0, EV_READ | EV_PERSIST, dispatch_stdio, NULL); - event_add(&stdioev, NULL); - - signal_set(&winchev, SIGWINCH, handle_resize, NULL); - signal_add(&winchev, NULL); - switch_to_tab(current_tab); rearrange_windows(); - event_dispatch(); + ev_loop(); } void @@ -1224,11 +1219,11 @@ ui_on_tab_refresh(struct tab *tab) void ui_on_download_refresh(void) { - if (event_pending(&download_refreshev, EV_TIMEOUT, NULL)) + if (ev_timer_pending(download_timer)) return; - evtimer_set(&download_refreshev, handle_download_refresh, NULL); - evtimer_add(&download_refreshev, &download_refresh_timer); + download_timer = ev_timer(&download_refresh_timer, + handle_download_refresh, NULL); } void blob - fc40369b423e13aa044a9089bfec117e2354b22c blob + 43ca40e36f48cabe9b52c27e38cf142dff07ccd9 --- utils.c +++ utils.c @@ -23,6 +23,7 @@ #include #include +#include "ev.h" #include "telescope.h" #include "utils.h" @@ -77,9 +78,7 @@ imsg_event_add(struct imsgev *iev) if (iev->ibuf.w.queued) iev->events |= EV_WRITE; - event_del(&iev->ev); - event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); - event_add(&iev->ev, NULL); + ev_add(iev->ibuf.fd, iev->events, iev->handler, iev); } int