#include #include #include #if INTERFACE #include #include typedef void (*ConnectionCallback)(EV_P_ Connection *); struct Connection { ev_io watcher; struct tls *ctx; ConnectionCallback success_cb; ConnectionCallback failure_cb; Buffer read_buf; Buffer write_buf; }; #define connection_set_failure_cb(connection, callback) \ do { \ (connection)->failure_cb = callback; \ } while (0) #define connection_set_cb(connection, callback) \ do { \ (connection)->success_cb = callback; \ } while (0) #define connection_read_buf(connection) &((connection)->read_buf) #define connection_write_buf(connection) &((connection)->write_buf) #endif void connection_init(EV_P_ Connection *connection, struct tls_config *config) { (void)(EV_A_ 0); ev_io_init(&connection->watcher, NULL, STDIN_FILENO, 0); connection->ctx = tls_client(); tls_configure(connection->ctx, config); } void connection_read_some(EV_P_ Connection *connection) { assert(connection->success_cb && connection->failure_cb); ev_set_cb(&connection->watcher, connection_read_some_cb); ev_invoke(EV_A_ & connection->watcher, 0); } static void connection_read_some_cb(EV_P_ ev_io *watcher, int revents) { Connection *connection = (Connection *)watcher; ssize_t n; (void)revents; ev_io_stop(EV_A_ watcher); n = tls_read(connection->ctx, buffer_data_remaining(&connection->read_buf), buffer_size_remaining(&connection->read_buf)); if (n == TLS_WANT_POLLIN) { ev_io_modify(watcher, EV_READ); ev_io_start(EV_A_ watcher); } else if (n == TLS_WANT_POLLOUT) { ev_io_modify(watcher, EV_WRITE); ev_io_start(EV_A_ watcher); } else if (n == -1) { connection->failure_cb(EV_A_ connection); } else { buffer_provide(&connection->read_buf, n); connection->success_cb(EV_A_ connection); } } void connection_write_some(EV_P_ Connection *connection) { assert(connection->success_cb && connection->failure_cb); ev_set_cb(&connection->watcher, connection_write_some_cb); ev_invoke(EV_A_ & connection->watcher, 0); } static void connection_write_some_cb(EV_P_ ev_io *watcher, int revents) { Connection *connection = (Connection *)watcher; ssize_t n; (void)revents; ev_io_stop(EV_A_ watcher); n = tls_write(connection->ctx, buffer_data(&connection->write_buf), buffer_size(&connection->write_buf)); if (n == TLS_WANT_POLLIN) { ev_io_modify(watcher, EV_READ); ev_io_start(EV_A_ watcher); } else if (n == TLS_WANT_POLLOUT) { ev_io_modify(watcher, EV_WRITE); ev_io_start(EV_A_ watcher); } else if (n == -1) { connection->failure_cb(EV_A_ connection); } else { buffer_consume(&connection->write_buf, n); connection->success_cb(EV_A_ connection); } } void connection_stop(EV_P_ Connection *connection) { ev_io_stop(EV_A_ & connection->watcher); close(connection->watcher.fd); tls_free(connection->ctx); }