buffer_clear(&c->inbuf);
buffer_clear(&c->outbuf);
- io_del(&c->io);
+ io_del(&mesh->loop, &c->io);
if(c->socket > 0)
closesocket(c->socket);
#include "dropin.h"
#include "event.h"
#include "net.h"
+#include "splay_tree.h"
#include "utils.h"
+#include "xalloc.h"
+event_loop_t *loop;
struct timeval now;
-static fd_set readfds;
-static fd_set writefds;
-static volatile bool running;
-
static int io_compare(const io_t *a, const io_t *b) {
return a->fd - b->fd;
}
return 0;
}
-static splay_tree_t io_tree = {.compare = (splay_compare_t)io_compare};
-static splay_tree_t timeout_tree = {.compare = (splay_compare_t)timeout_compare};
-
-void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags) {
+void io_add(event_loop_t *loop, io_t *io, io_cb_t cb, void *data, int fd, int flags) {
if(io->cb)
return;
io->data = data;
io->node.data = io;
- io_set(io, flags);
+ io_set(loop, io, flags);
- if(!splay_insert_node(&io_tree, &io->node))
+ if(!splay_insert_node(&loop->ios, &io->node))
abort();
}
-void io_set(io_t *io, int flags) {
+void io_set(event_loop_t *loop, io_t *io, int flags) {
io->flags = flags;
if(flags & IO_READ)
- FD_SET(io->fd, &readfds);
+ FD_SET(io->fd, &loop->readfds);
else
- FD_CLR(io->fd, &readfds);
+ FD_CLR(io->fd, &loop->readfds);
if(flags & IO_WRITE)
- FD_SET(io->fd, &writefds);
+ FD_SET(io->fd, &loop->writefds);
else
- FD_CLR(io->fd, &writefds);
+ FD_CLR(io->fd, &loop->writefds);
}
-void io_del(io_t *io) {
+void io_del(event_loop_t *loop, io_t *io) {
if(!io->cb)
return;
- io_set(io, 0);
+ io_set(loop, io, 0);
- splay_unlink_node(&io_tree, &io->node);
+ splay_unlink_node(&loop->ios, &io->node);
io->cb = NULL;
}
-void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv) {
+void timeout_add(event_loop_t *loop, timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv) {
timeout->cb = cb;
timeout->data = data;
timeout->node.data = timeout;
- timeout_set(timeout, tv);
+ timeout_set(loop, timeout, tv);
}
-void timeout_set(timeout_t *timeout, struct timeval *tv) {
+void timeout_set(event_loop_t *loop, timeout_t *timeout, struct timeval *tv) {
if(timerisset(&timeout->tv))
- splay_unlink_node(&timeout_tree, &timeout->node);
+ splay_unlink_node(&loop->timeouts, &timeout->node);
- if(!now.tv_sec)
- gettimeofday(&now, NULL);
+ if(!loop->now.tv_sec)
+ gettimeofday(&loop->now, NULL);
- timeradd(&now, tv, &timeout->tv);
+ timeradd(&loop->now, tv, &timeout->tv);
- if(!splay_insert_node(&timeout_tree, &timeout->node))
+ if(!splay_insert_node(&loop->timeouts, &timeout->node))
abort();
}
-void timeout_del(timeout_t *timeout) {
+void timeout_del(event_loop_t *loop, timeout_t *timeout) {
if(!timeout->cb)
return;
- splay_unlink_node(&timeout_tree, &timeout->node);
+ splay_unlink_node(&loop->timeouts, &timeout->node);
timeout->cb = 0;
timeout->tv = (struct timeval){0, 0};
}
-#ifndef HAVE_MINGW
static int signal_compare(const signal_t *a, const signal_t *b) {
- return a->signum - b->signum;
-}
-
-static io_t signalio;
-static int pipefd[2] = {-1, -1};
-static splay_tree_t signal_tree = {.compare = (splay_compare_t)signal_compare};
-
-static void signal_handler(int signum) {
- unsigned char num = signum;
- write(pipefd[1], &num, 1);
+ return (int)a->signum - (int)b->signum;
}
-static void signalio_handler(void *data, int flags) {
+static void signalio_handler(event_loop_t *loop, void *data, int flags) {
unsigned char signum;
- if(read(pipefd[0], &signum, 1) != 1)
+ if(read(loop->pipefd[0], &signum, 1) != 1)
return;
- signal_t *sig = splay_search(&signal_tree, &((signal_t){.signum = signum}));
+ signal_t *sig = splay_search(&loop->signals, &((signal_t){.signum = signum}));
if(sig)
- sig->cb(sig->data);
+ sig->cb(loop, sig->data);
}
-static void pipe_init(void) {
- if(!pipe(pipefd))
- io_add(&signalio, signalio_handler, NULL, pipefd[0], IO_READ);
+static void pipe_init(event_loop_t *loop) {
+ if(!pipe(loop->pipefd))
+ io_add(loop, &loop->signalio, signalio_handler, NULL, loop->pipefd[0], IO_READ);
}
-void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum) {
+void signal_add(event_loop_t *loop, signal_t *sig, signal_cb_t cb, void *data, uint8_t signum) {
if(sig->cb)
return;
sig->signum = signum;
sig->node.data = sig;
- if(pipefd[0] == -1)
- pipe_init();
-
- signal(sig->signum, signal_handler);
+ if(loop->pipefd[0] == -1)
+ pipe_init(loop);
- if(!splay_insert_node(&signal_tree, &sig->node))
+ if(!splay_insert_node(&loop->signals, &sig->node))
abort();
}
-void signal_del(signal_t *sig) {
+void signal_del(event_loop_t *loop, signal_t *sig) {
if(!sig->cb)
return;
- signal(sig->signum, SIG_DFL);
-
- splay_unlink_node(&signal_tree, &sig->node);
+ splay_unlink_node(&loop->signals, &sig->node);
sig->cb = NULL;
}
-#endif
-bool event_loop(void) {
- running = true;
+bool event_loop_run(event_loop_t *loop) {
+ loop->running = true;
fd_set readable;
fd_set writable;
- while(running) {
- gettimeofday(&now, NULL);
+ while(loop->running) {
+ gettimeofday(&loop->now, NULL);
+ now = loop->now;
struct timeval diff, *tv = NULL;
- while(timeout_tree.head) {
- timeout_t *timeout = timeout_tree.head->data;
- timersub(&timeout->tv, &now, &diff);
+ while(loop->timeouts.head) {
+ timeout_t *timeout = loop->timeouts.head->data;
+ timersub(&timeout->tv, &loop->now, &diff);
if(diff.tv_sec < 0) {
- timeout->cb(timeout->data);
- if(timercmp(&timeout->tv, &now, <))
- timeout_del(timeout);
+ timeout->cb(loop, timeout->data);
+ if(timercmp(&timeout->tv, &loop->now, <))
+ timeout_del(loop, timeout);
} else {
tv = &diff;
break;
}
}
- memcpy(&readable, &readfds, sizeof readable);
- memcpy(&writable, &writefds, sizeof writable);
+ memcpy(&readable, &loop->readfds, sizeof readable);
+ memcpy(&writable, &loop->writefds, sizeof writable);
int fds = 0;
- if(io_tree.tail) {
- io_t *last = io_tree.tail->data;
+ if(loop->ios.tail) {
+ io_t *last = loop->ios.tail->data;
fds = last->fd + 1;
}
-#ifdef HAVE_MINGW
- LeaveCriticalSection(&mutex);
-#endif
int n = select(fds, &readable, &writable, NULL, tv);
-#ifdef HAVE_MINGW
- EnterCriticalSection(&mutex);
-#endif
if(n < 0) {
if(sockwouldblock(errno))
if(!n)
continue;
- for splay_each(io_t, io, &io_tree) {
+ for splay_each(io_t, io, &loop->ios) {
if(FD_ISSET(io->fd, &writable))
- io->cb(io->data, IO_WRITE);
+ io->cb(loop, io->data, IO_WRITE);
else if(FD_ISSET(io->fd, &readable))
- io->cb(io->data, IO_READ);
+ io->cb(loop, io->data, IO_READ);
}
}
return true;
}
-void event_flush_output(void) {
- for splay_each(io_t, io, &io_tree)
- if(FD_ISSET(io->fd, &writefds))
- io->cb(io->data, IO_WRITE);
+void event_flush_output(event_loop_t *loop) {
+ for splay_each(io_t, io, &loop->ios)
+ if(FD_ISSET(io->fd, &loop->writefds))
+ io->cb(loop, io->data, IO_WRITE);
+}
+
+void event_loop_stop(event_loop_t *loop) {
+ loop->running = false;
+}
+
+void event_loop_init(event_loop_t *loop) {
+ loop->ios.compare = (splay_compare_t)io_compare;
+ loop->timeouts.compare = (splay_compare_t)timeout_compare;
+ loop->signals.compare = (splay_compare_t)signal_compare;
+ loop->pipefd[0] = -1;
+ loop->pipefd[1] = -1;
}
-void event_exit(void) {
- running = false;
+void event_loop_exit(event_loop_t *loop) {
+ for splay_each(io_t, io, &loop->ios)
+ splay_free_node(&loop->ios, node);
+ for splay_each(timeout_t, timeout, &loop->timeouts)
+ splay_free_node(&loop->timeouts, node);
+ for splay_each(signal_t, signal, &loop->signals)
+ splay_free_node(&loop->signals, node);
}
#define IO_READ 1
#define IO_WRITE 2
-typedef void (*io_cb_t)(void *data, int flags);
-typedef void (*timeout_cb_t)(void *data);
-typedef void (*signal_cb_t)(void *data);
+typedef struct event_loop_t event_loop_t;
+
+typedef void (*io_cb_t)(event_loop_t *loop, void *data, int flags);
+typedef void (*timeout_cb_t)(event_loop_t *loop, void *data);
+typedef void (*signal_cb_t)(event_loop_t *loop, void *data);
typedef struct io_t {
int fd;
struct splay_node_t node;
} signal_t;
+struct event_loop_t {
+ fd_set readfds;
+ fd_set writefds;
+
+ volatile bool running;
+ struct timeval now;
+
+ splay_tree_t ios;
+ splay_tree_t timeouts;
+ splay_tree_t signals;
+
+ io_t signalio;
+ int pipefd[2];
+
+ void *data;
+};
+
+extern event_loop_t *loop;
extern struct timeval now;
-extern void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags);
-extern void io_del(io_t *io);
-extern void io_set(io_t *io, int flags);
+extern void io_add(event_loop_t *loop, io_t *io, io_cb_t cb, void *data, int fd, int flags);
+extern void io_del(event_loop_t *loop, io_t *io);
+extern void io_set(event_loop_t *loop, io_t *io, int flags);
-extern void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv);
-extern void timeout_del(timeout_t *timeout);
-extern void timeout_set(timeout_t *timeout, struct timeval *tv);
+extern void timeout_add(event_loop_t *loop, timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv);
+extern void timeout_del(event_loop_t *loop, timeout_t *timeout);
+extern void timeout_set(event_loop_t *loop, timeout_t *timeout, struct timeval *tv);
-extern void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum);
-extern void signal_del(signal_t *sig);
+extern void signal_add(event_loop_t *loop, signal_t *sig, signal_cb_t cb, void *data, uint8_t signum);
+extern void signal_trigger(event_loop_t *loop, signal_t *sig);
+extern void signal_del(event_loop_t *loop, signal_t *sig);
-extern bool event_loop(void);
-extern void event_flush_output(void);
-extern void event_exit(void);
+extern void event_loop_init(event_loop_t *loop);
+extern void event_loop_exit(event_loop_t *loop);
+extern bool event_loop_run(event_loop_t *loop);
+extern void event_loop_flush_output(event_loop_t *loop);
+extern void event_loop_stop(event_loop_t *loop);
#endif
n->minmtu = 0;
n->mtuprobes = 0;
- timeout_del(&n->mtutimeout);
+ timeout_del(&mesh->loop, &n->mtutimeout);
//TODO: callback to application to inform of this node going up/down
// TODO: hack, remove once all global variables are gone.
static void set_mesh(meshlink_handle_t *localmesh) {
mesh = localmesh;
+ loop = &mesh->loop;
}
static bool ecdsa_keygen(meshlink_handle_t *mesh) {
meshlink_handle_t *mesh = xzalloc(sizeof *mesh);
mesh->confbase = xstrdup(confbase);
mesh->name = xstrdup(name);
+ event_loop_init(&mesh->loop);
set_mesh(mesh);
// TODO: should be set by a function.
logger(DEBUG_ALWAYS, LOG_NOTICE, "Terminating");
exit_configuration(&mesh->config);
-
+ event_loop_exit(&mesh->loop);
}
void meshlink_set_receive_cb(meshlink_handle_t *mesh, meshlink_receive_cb_t cb) {
meshlink_log_level_t log_level;
pthread_t thread;
+ event_loop_t loop;
listen_socket_t listen_socket[MAXSOCKETS];
int listen_sockets;
}
buffer_add(&c->outbuf, buffer, length);
- io_set(&c->io, IO_READ | IO_WRITE);
+ io_set(&mesh->loop, &c->io, IO_READ | IO_WRITE);
return true;
}
if(c->allow_request == ID) {
buffer_add(&c->outbuf, buffer, length);
- io_set(&c->io, IO_READ | IO_WRITE);
+ io_set(&mesh->loop, &c->io, IO_READ | IO_WRITE);
return true;
}
end does not reply in time, we consider them dead
and close the connection.
*/
-static void timeout_handler(void *data) {
+static void timeout_handler(event_loop_t *loop, void *data) {
for list_each(connection_t, c, mesh->connections) {
if(c->last_ping_time + mesh->pingtimeout <= now.tv_sec) {
if(c->status.active) {
}
}
- timeout_set(data, &(struct timeval){mesh->pingtimeout, rand() % 100000});
+ timeout_set(&mesh->loop, data, &(struct timeval){mesh->pingtimeout, rand() % 100000});
}
-static void periodic_handler(void *data) {
+static void periodic_handler(event_loop_t *loop, void *data) {
/* Check if there are too many contradicting ADD_EDGE and DEL_EDGE messages.
This usually only happens when another node has the same Name as this node.
If so, sleep for a short while to prevent a storm of contradicting messages.
}
}
- timeout_set(data, &(struct timeval){5, rand() % 100000});
+ timeout_set(&mesh->loop, data, &(struct timeval){5, rand() % 100000});
}
void handle_meta_connection_data(connection_t *c) {
for list_each(outgoing_t, outgoing, mesh->outgoings) {
outgoing->timeout = 0;
if(outgoing->ev.cb)
- timeout_set(&outgoing->ev, &(struct timeval){0, 0});
+ timeout_set(&mesh->loop, &outgoing->ev, &(struct timeval){0, 0});
}
/* Check for outgoing connections that are in progress, and reset their ping timers */
}
/* Kick the ping timeout handler */
- timeout_set(&mesh->pingtimer, &(struct timeval){0, 0});
+ timeout_set(&mesh->loop, &mesh->pingtimer, &(struct timeval){0, 0});
}
/*
this is where it all happens...
*/
int main_loop(void) {
- timeout_add(&mesh->pingtimer, timeout_handler, &mesh->pingtimer, &(struct timeval){mesh->pingtimeout, rand() % 100000});
- timeout_add(&mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timeval){mesh->pingtimeout, rand() % 100000});
+ timeout_add(&mesh->loop, &mesh->pingtimer, timeout_handler, &mesh->pingtimer, &(struct timeval){mesh->pingtimeout, rand() % 100000});
+ timeout_add(&mesh->loop, &mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timeval){mesh->pingtimeout, rand() % 100000});
- if(!event_loop()) {
+ if(!event_loop_run(&mesh->loop)) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while waiting for input: %s", strerror(errno));
return 1;
}
- timeout_del(&mesh->periodictimer);
- timeout_del(&mesh->pingtimer);
+ timeout_del(&mesh->loop, &mesh->periodictimer);
+ timeout_del(&mesh->loop, &mesh->pingtimer);
return 0;
}
#include "node.h"
extern void retry_outgoing(outgoing_t *);
-extern void handle_incoming_vpn_data(void *, int);
+extern void handle_incoming_vpn_data(struct event_loop_t *loop, void *, int);
extern void finish_connecting(struct connection_t *);
extern bool do_outgoing_connection(struct outgoing_t *);
-extern void handle_new_meta_connection(void *, int);
+extern void handle_new_meta_connection(struct event_loop_t *loop, void *, int);
extern int setup_listen_socket(const sockaddr_t *);
extern int setup_vpn_in_socket(const sockaddr_t *);
extern bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len);
extern bool node_read_ecdsa_public_key(struct node_t *);
extern bool read_ecdsa_public_key(struct connection_t *);
extern void send_mtu_probe(struct node_t *);
-extern void handle_device_data(void *, int);
extern void handle_meta_connection_data(struct connection_t *);
extern void regenerate_key(void);
extern void purge(void);
*/
-static void send_mtu_probe_handler(void *data) {
+static void send_mtu_probe_handler(event_loop_t *loop, void *data) {
node_t *n = data;
int timeout = 1;
n->prev_received = n->received;
end:
- timeout_set(&n->mtutimeout, &(struct timeval){timeout, rand() % 100000});
+ timeout_set(&mesh->loop, &n->mtutimeout, &(struct timeval){timeout, rand() % 100000});
}
void send_mtu_probe(node_t *n) {
- timeout_add(&n->mtutimeout, send_mtu_probe_handler, n, &(struct timeval){1, 0});
- send_mtu_probe_handler(n);
+ timeout_add(&mesh->loop, &n->mtutimeout, send_mtu_probe_handler, n, &(struct timeval){1, 0});
+ send_mtu_probe_handler(&mesh->loop, n);
}
static void mtu_probe_h(node_t *n, vpn_packet_t *packet, uint16_t len) {
return n;
}
-void handle_incoming_vpn_data(void *data, int flags) {
+void handle_incoming_vpn_data(event_loop_t *loop, void *data, int flags) {
listen_socket_t *ls = data;
vpn_packet_t pkt;
char *hostname;
continue;
}
- io_add(&mesh->listen_socket[mesh->listen_sockets].tcp, handle_new_meta_connection, &mesh->listen_socket[mesh->listen_sockets], tcp_fd, IO_READ);
- io_add(&mesh->listen_socket[mesh->listen_sockets].udp, handle_incoming_vpn_data, &mesh->listen_socket[mesh->listen_sockets], udp_fd, IO_READ);
+ io_add(&mesh->loop, &mesh->listen_socket[mesh->listen_sockets].tcp, handle_new_meta_connection, &mesh->listen_socket[mesh->listen_sockets], tcp_fd, IO_READ);
+ io_add(&mesh->loop, &mesh->listen_socket[mesh->listen_sockets].udp, handle_incoming_vpn_data, &mesh->listen_socket[mesh->listen_sockets], udp_fd, IO_READ);
if(mesh->debug_level >= DEBUG_CONNECTIONS) {
char *hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
}
for(int i = 0; i < mesh->listen_sockets; i++) {
- io_del(&mesh->listen_socket[i].tcp);
- io_del(&mesh->listen_socket[i].udp);
+ io_del(&mesh->loop, &mesh->listen_socket[i].tcp);
+ io_del(&mesh->loop, &mesh->listen_socket[i].udp);
close(mesh->listen_socket[i].tcp.fd);
close(mesh->listen_socket[i].udp.fd);
}
return nfd;
} /* int setup_vpn_in_socket */
-static void retry_outgoing_handler(void *data) {
+static void retry_outgoing_handler(event_loop_t *loop, void *data) {
setup_outgoing_connection(data);
}
if(outgoing->timeout > mesh->maxtimeout)
outgoing->timeout = mesh->maxtimeout;
- timeout_add(&outgoing->ev, retry_outgoing_handler, outgoing, &(struct timeval){outgoing->timeout, rand() % 100000});
+ timeout_add(&mesh->loop, &outgoing->ev, retry_outgoing_handler, outgoing, &(struct timeval){outgoing->timeout, rand() % 100000});
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Trying to re-establish outgoing connection in %d seconds", outgoing->timeout);
}
buffer_read(&c->outbuf, outlen);
if(!c->outbuf.len)
- io_set(&c->io, IO_READ);
+ io_set(&mesh->loop, &c->io, IO_READ);
}
-static void handle_meta_io(void *data, int flags) {
+static void handle_meta_io(event_loop_t *loop, void *data, int flags) {
connection_t *c = data;
if(c->status.connecting) {
connection_add(c);
- io_add(&c->io, handle_meta_io, c, c->socket, IO_READ|IO_WRITE);
+ io_add(&mesh->loop, &c->io, handle_meta_io, c, c->socket, IO_READ|IO_WRITE);
return true;
}
}
void setup_outgoing_connection(outgoing_t *outgoing) {
- timeout_del(&outgoing->ev);
+ timeout_del(&mesh->loop, &outgoing->ev);
node_t *n = lookup_node(outgoing->name);
accept a new tcp connect and create a
new connection
*/
-void handle_new_meta_connection(void *data, int flags) {
+void handle_new_meta_connection(event_loop_t *loop, void *data, int flags) {
listen_socket_t *l = data;
connection_t *c;
sockaddr_t sa;
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection from %s", c->hostname);
- io_add(&c->io, handle_meta_io, c, c->socket, IO_READ);
+ io_add(&mesh->loop, &c->io, handle_meta_io, c, c->socket, IO_READ);
configure_tcp(c);
}
static void free_outgoing(outgoing_t *outgoing) {
- timeout_del(&outgoing->ev);
+ timeout_del(&mesh->loop, &outgoing->ev);
if(outgoing->ai)
freeaddrinfo(outgoing->ai);
ecdsa_free(n->ecdsa);
sptps_stop(&n->sptps);
- timeout_del(&n->mtutimeout);
+ timeout_del(&mesh->loop, &n->mtutimeout);
if(n->hostname)
free(n->hostname);
static timeout_t past_request_timeout;
-static void age_past_requests(void *data) {
+static void age_past_requests(event_loop_t *loop, void *data) {
int left = 0, deleted = 0;
for splay_each(past_request_t, p, past_request_tree) {
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Aging past requests: deleted %d, left %d", deleted, left);
if(left)
- timeout_set(&past_request_timeout, &(struct timeval){10, rand() % 100000});
+ timeout_set(&mesh->loop, &past_request_timeout, &(struct timeval){10, rand() % 100000});
}
bool seen_request(const char *request) {
new->request = xstrdup(request);
new->firstseen = now.tv_sec;
splay_insert(past_request_tree, new);
- timeout_add(&past_request_timeout, age_past_requests, NULL, &(struct timeval){10, rand() % 100000});
+ timeout_add(&mesh->loop, &past_request_timeout, age_past_requests, NULL, &(struct timeval){10, rand() % 100000});
return false;
}
}
void exit_requests(void) {
splay_delete_tree(past_request_tree);
- timeout_del(&past_request_timeout);
+ timeout_del(&mesh->loop, &past_request_timeout);
}