commit - b19b8dbca985e2f567bb3f476b116ea18c1ca9a2
commit + 98d3e6c172747dc58042bde09a848d3e03572934
blob - 659ab9e8b4f977072e2cacadbf9af8244697ea4a
blob + 46ec1afce4bacfa28a5124980c8dcf89ff1c154c
--- Makefile.am
+++ Makefile.am
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 \
defaults.h \
downloads.c \
emoji-matcher.c \
+ ev.c \
+ ev.h \
fs.c \
fs.h \
gencmd.awk \
telescope_identity_SOURCES = \
certs.c \
certs.h \
+ ev.c \
+ ev.h \
fs.c \
fs.h \
hist.c \
identity.c \
parser.c \
parser.h \
- utils.c \
+ utils.c \
utils.h
noinst_PROGRAMS = pagebundler
blob - 8928556709972b28db62863d0b7aeb0dd403b236
blob + 99b46defa92628536ea7bd98665fe2b7cbd877e0
--- cmd.c
+++ cmd.c
#include "cmd.h"
#include "compl.h"
#include "defaults.h"
+#include "ev.h"
#include "hist.h"
#include "keymap.h"
#include "mcache.h"
{
if (r) {
save_session();
- event_loopbreak();
+ ev_break();
}
}
blob - de06e6b654820fabe2d2634479ec69a0d184441c
blob + e83e196c254ef03fb7eeec1c996028ee967634be
--- compat.h
+++ compat.h
# error no compatible endian.h header found
#endif
-#if HAVE_EVENT2
-# include <event2/event.h>
-# include <event2/event_compat.h>
-# include <event2/event_struct.h>
-# include <event2/buffer.h>
-# include <event2/buffer_compat.h>
-# include <event2/bufferevent.h>
-# include <event2/bufferevent_struct.h>
-# include <event2/bufferevent_compat.h>
-#else
-# include <event.h>
-#endif
-
#ifdef HAVE_QUEUE_H
# include <sys/queue.h>
#else
blob - 73930b982ee6b2c5b3dabf2fe2d223b2f959dd9f
blob + db4a22fe78ee5db9f37557e66e93c8729dd84519
--- control.c
+++ control.c
#include <unistd.h>
#include "control.h"
+#include "ev.h"
#include "minibuffer.h"
#include "telescope.h"
#include "utils.h"
#define CONTROL_BACKLOG 5
struct {
- struct event ev;
- struct event evt;
+ unsigned long timeout;
int fd;
} control_state = {.fd = -1};
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;
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));
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);
}
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
#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
#include "compat.h"
+#include <sys/time.h>
+
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
+#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;
}
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;
if (e->ts < treshold)
mcache_free_entry(e->url);
- evtimer_add(&timerev, &tv);
+ timeout = ev_timer(&tv, clean_old_entries, NULL);
}
void
};
ohash_init(&h, 5, &info);
-
- evtimer_set(&timerev, clean_old_entries, NULL);
}
int
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
#include "compat.h"
+#include <sys/time.h>
+
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include "certs.h"
#include "cmd.h"
#include "defaults.h"
+#include "ev.h"
#include "fs.h"
#include "hist.h"
#include "iri.h"
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;
}
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;
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)
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
#include "compat.h"
+/* XXX needs some work to run on top of ev */
+#undef HAVE_ASR_RUN
+
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/socket.h>
# include <asr.h>
#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;
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;
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*);
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)
{
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)
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
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);
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);
}
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
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
}
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;
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;
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:
break;
case IMSG_QUIT:
- event_loopbreak();
+ ev_break();
imsg_free(&imsg);
return;
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)
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
#include "compat.h"
+#include <sys/time.h>
+
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <unistd.h>
#include "defaults.h"
+#include "ev.h"
#include "fs.h"
#include "hist.h"
#include "minibuffer.h"
struct history history;
-static struct event autosaveev;
+static unsigned int autosavetimer;
void
switch_to_tab(struct tab *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();
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);
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();
}
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
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
#include "compat.h"
#include <sys/socket.h>
+#include <sys/time.h>
#include <sys/un.h>
#include <sys/wait.h>
#include "cmd.h"
#include "control.h"
#include "defaults.h"
+#include "ev.h"
#include "fs.h"
#include "hist.h"
#include "iri.h"
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 *);
}
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;
if (dohist) {
if (hist_push(tab->hist, url) == -1) {
- event_loopbreak();
+ ev_break();
return;
}
/* 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)
/* 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
struct imsgev {
struct imsgbuf ibuf;
- void (*handler)(int, short, void *);
- struct event ev;
+ void (*handler)(int, int, void *);
short events;
};
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
#include "compat.h"
+#include <sys/time.h>
+
#include <assert.h>
#include <curses.h>
#include <locale.h>
#include "cmd.h"
#include "defaults.h"
+#include "ev.h"
#include "hist.h"
#include "keymap.h"
#include "minibuffer.h"
#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*);
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;
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;
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];
}
static void
-dispatch_stdio(int fd, short ev, void *d)
+dispatch_stdio(int fd, int ev, void *d)
{
int lk;
const char *keyname;
}
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();
}
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();
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;
wrefresh(echoarea);
}
- evtimer_add(&tab->loadingev, &loadingev_timer);
+ tab->loading_timer = ev_timer(&loading_tv, update_loading_anim, tab);
}
static void
{
if (!tab->loading_anim)
return;
- evtimer_del(&tab->loadingev);
+
+ ev_timer_cancel(tab->loading_timer);
tab->loading_anim = 0;
tab->loading_anim_step = 0;
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
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
#include <string.h>
#include <unistd.h>
+#include "ev.h"
#include "telescope.h"
#include "utils.h"
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