cmatrix/src/connection.c

104 lines
3 KiB
C

#include <assert.h>
#include <connection.h>
#include <unistd.h>
#if INTERFACE
#include <ev.h>
#include <tls.h>
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);
}