ensure you have the latest stable versions of all the required libraries:
- OpenSSL (http://www.openssl.org/) version 1.0.0 or later.
-- Libevent (http://monkey.org/~provos/libevent/)
The following libraries are used by default, but can be disabled if necessary:
- automake
- autoconf
- gettext
-- libevent
Then you have to let the autotools create all the autogenerated files, using
this command:
tinc_CURSES
tinc_READLINE
-tinc_LIBEVENT
tinc_ZLIB
tinc_LZO
* OpenSSL::
* zlib::
* lzo::
-* libevent::
* libcurses::
* libreadline::
@end menu
default).
-@c ==================================================================
-@node libevent
-@subsection libevent
-
-@cindex libevent
-For the main event loop, tinc uses the libevent library.
-
-If this library is not installed, you wil get an error when configuring
-tinc for build.
-
-You can use your operating system's package manager to install this if
-available. Make sure you install the development AND runtime versions
-of this package.
-
-If you have to install libevent manually, you can get the source code
-from @url{http://libevent.org/}. Instructions on how to configure,
-build and install this package are included within the package. Please
-make sure you build development and runtime libraries (which is the
-default).
-
-
@c ==================================================================
@node libcurses
@subsection libcurses
#include <netinet/if_ether.h>
#endif
-#ifdef HAVE_EVENT_H
-#include <event.h>
-#endif
-
#ifdef HAVE_MINGW
#define SLASH "\\"
#else
+++ /dev/null
-dnl Check to find the libevent headers/libraries
-
-AC_DEFUN([tinc_LIBEVENT],
-[
- AC_ARG_WITH(libevent,
- AS_HELP_STRING([--with-libevent=DIR], [libevent base directory, or:]),
- [libevent="$withval"
- CPPFLAGS="$CPPFLAGS -I$withval/include"
- LDFLAGS="$LDFLAGS -L$withval/lib"]
- )
-
- AC_ARG_WITH(libevent-include,
- AS_HELP_STRING([--with-libevent-include=DIR], [libevent headers directory]),
- [libevent_include="$withval"
- CPPFLAGS="$CPPFLAGS -I$withval"]
- )
-
- AC_ARG_WITH(libevent-lib,
- AS_HELP_STRING([--with-libevent-lib=DIR], [libevent library directory]),
- [libevent_lib="$withval"
- LDFLAGS="$LDFLAGS -L$withval"]
- )
-
- AC_CHECK_HEADERS(event.h,
- [],
- [AC_MSG_ERROR("libevent header files not found."); break]
- )
-
- AC_CHECK_LIB(event, event_init,
- [LIBS="-levent $LIBS"],
- [AC_MSG_ERROR("libevent libraries not found.")]
- )
-])
utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c hash.c \
buffer.c conf.c connection.c control.c edge.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \
net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \
- protocol_key.c protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c tincd.c \
+ protocol_key.c protocol_subnet.c route.c sptps.c subnet.c subnet_parse.c event.c tincd.c \
dummy_device.c raw_socket_device.c multicast_device.c
if UML
noinst_HEADERS = \
xalloc.h utils.h getopt.h list.h splay_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h \
buffer.h conf.h connection.h control.h control_common.h device.h edge.h graph.h info.h logger.h meta.h net.h netutl.h node.h process.h \
- protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h
+ protocol.h route.h subnet.h sptps.h tincctl.h top.h bsd/tunemu.h hash.h event.h
nodist_noinst_HEADERS = \
cipher.h crypto.h ecdh.h ecdsa.h digest.h prf.h rsa.h ecdsagen.h rsagen.h
buffer_clear(&c->inbuf);
buffer_clear(&c->outbuf);
- if(event_initialized(&c->inevent))
- event_del(&c->inevent);
-
- if(event_initialized(&c->outevent))
- event_del(&c->outevent);
+ io_del(&c->io);
if(c->socket > 0)
closesocket(c->socket);
struct buffer_t inbuf;
struct buffer_t outbuf;
- struct event inevent; /* input event on this metadata connection */
- struct event outevent; /* output event on this metadata connection */
+ io_t io; /* input/output event on this metadata connection */
int tcplen; /* length of incoming TCPpacket */
int allow_request; /* defined if there's only one request possible */
switch (type) {
case REQ_STOP:
- event_loopexit(NULL);
+ event_exit();
return control_ok(c, REQ_STOP);
case REQ_DUMP_NODES:
// Make sure we have a valid address, and map 0.0.0.0 and :: to 127.0.0.1 and ::1.
- if(getsockname(listen_socket[0].tcp, (struct sockaddr *)&sa, &len)) {
+ if(getsockname(listen_socket[0].tcp.fd, (struct sockaddr *)&sa, &len)) {
xasprintf(&localhost, "127.0.0.1 port %d", myport);
} else {
if(sa.sa.sa_family == AF_INET) {
--- /dev/null
+/*
+ event.c -- I/O, timeout and signal event handling
+ Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "system.h"
+
+#include "event.h"
+#include "net.h"
+#include "utils.h"
+
+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;
+}
+
+static int timeout_compare(const timeout_t *a, const timeout_t *b) {
+ struct timeval diff;
+ timersub(&a->tv, &b->tv, &diff);
+ return diff.tv_sec ?: diff.tv_usec;
+}
+
+static int signal_compare(const signal_t *a, const signal_t *b) {
+ return a->signum - b->signum;
+}
+
+static splay_tree_t io_tree = {.compare = (splay_compare_t)io_compare};
+static splay_tree_t timeout_tree = {.compare = (splay_compare_t)timeout_compare};
+static splay_tree_t signal_tree = {.compare = (splay_compare_t)signal_compare};
+
+void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags) {
+ if(io->cb)
+ return;
+
+ io->fd = fd;
+ io->cb = cb;
+ io->data = data;
+ io->node.data = io;
+
+ io_set(io, flags);
+
+ splay_insert_node(&io_tree, &io->node);
+}
+
+void io_set(io_t *io, int flags) {
+ io->flags = flags;
+
+ if(flags & IO_READ)
+ FD_SET(io->fd, &readfds);
+ else
+ FD_CLR(io->fd, &readfds);
+
+ if(flags & IO_WRITE)
+ FD_SET(io->fd, &writefds);
+ else
+ FD_CLR(io->fd, &writefds);
+}
+
+void io_del(io_t *io) {
+ if(!io->cb)
+ return;
+
+ io_set(io, 0);
+
+ splay_unlink_node(&io_tree, &io->node);
+ io->cb = NULL;
+}
+
+void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv) {
+ if(timeout->cb)
+ return;
+
+ timeout->cb = cb;
+ timeout->data = data;
+ timeout->node.data = timeout;
+
+ timeout_set(timeout, tv);
+}
+
+void timeout_set(timeout_t *timeout, struct timeval *tv) {
+ if(timeout->tv.tv_sec)
+ splay_unlink_node(&timeout_tree, &timeout->node);
+
+ if(!now.tv_sec)
+ gettimeofday(&now, NULL);
+
+ timeradd(&now, tv, &timeout->tv);
+
+ splay_insert_node(&timeout_tree, &timeout->node);
+}
+
+void timeout_del(timeout_t *timeout) {
+ if(!timeout->cb)
+ return;
+
+ splay_unlink_node(&timeout_tree, &timeout->node);
+ timeout->cb = NULL;
+}
+
+#ifndef HAVE_MINGW
+static io_t signalio;
+static int pipefd[2] = {-1, -1};
+
+static void signal_handler(int signum) {
+ unsigned char num = signum;
+ write(pipefd[1], &num, 1);
+}
+
+static void signalio_handler(void *data, int flags) {
+ unsigned char signum;
+ if(read(pipefd[0], &signum, 1) != 1)
+ return;
+
+ signal_t *sig = splay_search(&signal_tree, &((signal_t){.signum = signum}));
+ if(sig)
+ sig->cb(sig->data);
+}
+
+static void pipe_init(void) {
+ if(!pipe(pipefd))
+ io_add(&signalio, signalio_handler, NULL, pipefd[0], IO_READ);
+}
+
+void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum) {
+ if(sig->cb)
+ return;
+
+ sig->cb = cb;
+ sig->data = data;
+ sig->signum = signum;
+ sig->node.data = sig;
+
+ if(pipefd[0] == -1)
+ pipe_init();
+
+ signal(sig->signum, signal_handler);
+
+ splay_insert_node(&signal_tree, &sig->node);
+}
+
+void signal_del(signal_t *sig) {
+ if(!sig->cb)
+ return;
+
+ signal(sig->signum, SIG_DFL);
+
+ splay_unlink_node(&signal_tree, &sig->node);
+ sig->cb = NULL;
+}
+#endif
+
+bool event_loop(void) {
+ running = true;
+
+ fd_set readable;
+ fd_set writable;
+
+ while(running) {
+ gettimeofday(&now, NULL);
+ struct timeval diff, *tv = NULL;
+
+ while(timeout_tree.head) {
+ timeout_t *timeout = timeout_tree.head->data;
+ timersub(&timeout->tv, &now, &diff);
+
+ if(diff.tv_sec <= 0) {
+ timeout->cb(timeout->data);
+ if(timercmp(&timeout->tv, &now, <))
+ timeout_del(timeout);
+ } else {
+ tv = &diff;
+ break;
+ }
+ }
+
+ memcpy(&readable, &readfds, sizeof readable);
+ memcpy(&writable, &writefds, sizeof writable);
+
+ int fds = 0;
+
+ if(io_tree.tail) {
+ io_t *last = io_tree.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))
+ continue;
+ else
+ return false;
+ }
+
+ if(!n)
+ continue;
+
+ for splay_each(io_t, io, &io_tree) {
+ if(FD_ISSET(io->fd, &writable))
+ io->cb(io->data, IO_WRITE);
+ else if(FD_ISSET(io->fd, &readable))
+ io->cb(io->data, IO_READ);
+ }
+ }
+
+ return true;
+}
+
+void event_exit(void) {
+ running = false;
+}
--- /dev/null
+/*
+ event.h -- I/O, timeout and signal event handling
+ Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef __TINC_EVENT_H__
+#define __TINC_EVENT_H__
+
+#include "splay_tree.h"
+
+#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 io_t {
+ int fd;
+ int flags;
+ io_cb_t cb;
+ void *data;
+ splay_node_t node;
+} io_t;
+
+typedef struct timeout_t {
+ struct timeval tv;
+ timeout_cb_t cb;
+ void *data;
+ splay_node_t node;
+} timeout_t;
+
+typedef struct signal_t {
+ int signum;
+ signal_cb_t cb;
+ void *data;
+ splay_node_t node;
+} signal_t;
+
+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 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 signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum);
+extern void signal_del(signal_t *sig);
+
+extern bool event_loop(void);
+extern void event_exit(void);
+
+#endif
n->minmtu = 0;
n->mtuprobes = 0;
- if(timeout_initialized(&n->mtuevent))
- event_del(&n->mtuevent);
+ timeout_del(&n->mtutimeout);
char *name;
char *address;
static void real_logger(int level, int priority, const char *message) {
char timestr[32] = "";
- time_t now;
static bool suppress = false;
// Bail out early if there is nothing to do.
fflush(stderr);
break;
case LOGMODE_FILE:
- now = time(NULL);
- strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&now));
+ if(!now.tv_sec)
+ gettimeofday(&now, NULL);
+ strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&now.tv_sec));
fprintf(logfile, "%s %s[%ld]: %s\n", timestr, logident, (long)logpid, message);
fflush(logfile);
break;
}
buffer_add(&c->outbuf, buffer, length);
- event_add(&c->outevent, NULL);
+ io_set(&c->io, IO_READ | IO_WRITE);
return true;
}
c->name, c->hostname);
return false;
}
-
} else {
buffer_add(&c->outbuf, buffer, length);
}
- event_add(&c->outevent, NULL);
+ io_set(&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(int fd, short events, void *event) {
- time_t now = time(NULL);
-
+static void timeout_handler(void *data) {
for list_each(connection_t, c, connection_list) {
if(c->status.control)
continue;
- if(c->last_ping_time + pingtimeout <= now) {
+ if(c->last_ping_time + pingtimeout <= now.tv_sec) {
if(c->status.active) {
if(c->status.pinged) {
- logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)now - c->last_ping_time);
- } else if(c->last_ping_time + pinginterval <= now) {
+ logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)now.tv_sec - c->last_ping_time);
+ } else if(c->last_ping_time + pinginterval <= now.tv_sec) {
send_ping(c);
continue;
} else {
}
}
- event_add(event, &(struct timeval){pingtimeout, rand() % 100000});
+ timeout_set(data, &(struct timeval){pingtimeout, rand() % 100000});
}
-static void periodic_handler(int fd, short events, void *event) {
+static void periodic_handler(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.
}
}
- event_add(event, &(struct timeval){5, rand() % 100000});
+ timeout_set(data, &(struct timeval){5, rand() % 100000});
}
-void handle_meta_connection_data(int fd, short events, void *data) {
- connection_t *c = data;
+void handle_meta_connection_data(connection_t *c) {
int result;
socklen_t len = sizeof result;
}
}
-static void sigterm_handler(int signal, short events, void *data) {
- logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal));
- event_loopexit(NULL);
+static void sigterm_handler(void *data) {
+ logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(((signal_t *)data)->signum));
+ event_exit();
}
-static void sighup_handler(int signal, short events, void *data) {
- logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal));
+static void sighup_handler(void *data) {
+ logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(((signal_t *)data)->signum));
reopenlogger();
reload_configuration();
}
-static void sigalrm_handler(int signal, short events, void *data) {
- logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(signal));
+static void sigalrm_handler(void *data) {
+ logger(DEBUG_ALWAYS, LOG_NOTICE, "Got %s signal", strsignal(((signal_t *)data)->signum));
retry();
}
if(!read_server_config()) {
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to reread configuration file, exitting.");
- event_loopexit(NULL);
+ event_exit();
return EINVAL;
}
void retry(void) {
for list_each(connection_t, c, connection_list) {
if(c->outgoing && !c->node) {
- if(timeout_initialized(&c->outgoing->ev))
- event_del(&c->outgoing->ev);
+ timeout_del(&c->outgoing->ev);
if(c->status.connecting)
close(c->socket);
c->outgoing->timeout = 0;
this is where it all happens...
*/
int main_loop(void) {
- struct event timeout_event;
- struct event periodic_event;
-
- timeout_set(&timeout_event, timeout_handler, &timeout_event);
- event_add(&timeout_event, &(struct timeval){pingtimeout, rand() % 100000});
+ timeout_t pingtimer = {{0}};
+ timeout_t periodictimer = {{0}};
- timeout_set(&periodic_event, periodic_handler, &periodic_event);
- event_add(&periodic_event, &(struct timeval){5, rand() % 100000});
+ timeout_add(&pingtimer, timeout_handler, &pingtimer, &(struct timeval){pingtimeout, rand() % 100000});
+ timeout_add(&periodictimer, periodic_handler, &periodictimer, &(struct timeval){pingtimeout, rand() % 100000});
#ifndef HAVE_MINGW
- struct event sighup_event;
- struct event sigterm_event;
- struct event sigquit_event;
- struct event sigalrm_event;
-
- signal_set(&sighup_event, SIGHUP, sighup_handler, NULL);
- signal_add(&sighup_event, NULL);
- signal_set(&sigterm_event, SIGTERM, sigterm_handler, NULL);
- signal_add(&sigterm_event, NULL);
- signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL);
- signal_add(&sigquit_event, NULL);
- signal_set(&sigalrm_event, SIGALRM, sigalrm_handler, NULL);
- signal_add(&sigalrm_event, NULL);
+ signal_t sighup = {0};
+ signal_t sigterm = {0};
+ signal_t sigquit = {0};
+ signal_t sigalrm = {0};
+
+ signal_add(&sighup, sighup_handler, &sighup, SIGHUP);
+ signal_add(&sigterm, sigterm_handler, &sigterm, SIGTERM);
+ signal_add(&sigquit, sigterm_handler, &sigquit, SIGQUIT);
+ signal_add(&sigalrm, sigalrm_handler, &sigalrm, SIGALRM);
#endif
- if(event_loop(0) < 0) {
+ if(!event_loop()) {
logger(DEBUG_ALWAYS, LOG_ERR, "Error while waiting for input: %s", strerror(errno));
return 1;
}
#ifndef HAVE_MINGW
- signal_del(&sighup_event);
- signal_del(&sigterm_event);
- signal_del(&sigquit_event);
- signal_del(&sigalrm_event);
+ signal_del(&sighup);
+ signal_del(&sigalrm);
+ signal_del(&sigquit);
+ signal_del(&sigterm);
#endif
- event_del(&timeout_event);
+ timeout_del(&periodictimer);
+ timeout_del(&pingtimer);
return 0;
}
#include "ipv6.h"
#include "cipher.h"
#include "digest.h"
+#include "event.h"
#ifdef ENABLE_JUMBOGRAMS
#define MTU 9018 /* 9000 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
} packet_type_t;
typedef struct listen_socket_t {
- struct event ev_tcp;
- struct event ev_udp;
- int tcp;
- int udp;
+ io_t tcp;
+ io_t udp;
sockaddr_t sa;
} listen_socket_t;
struct config_t *cfg;
struct addrinfo *ai;
struct addrinfo *aip;
- struct event ev;
+ timeout_t ev;
} outgoing_t;
extern list_t *outgoing_list;
#include "node.h"
extern void retry_outgoing(outgoing_t *);
-extern void handle_incoming_vpn_data(int, short, void *);
+extern void handle_incoming_vpn_data(void *, int);
extern void finish_connecting(struct connection_t *);
extern bool do_outgoing_connection(struct outgoing_t *);
-extern void handle_new_meta_connection(int, short, void *);
+extern void handle_new_meta_connection(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 read_ecdsa_public_key(struct connection_t *);
extern bool read_rsa_public_key(struct connection_t *);
extern void send_mtu_probe(struct node_t *);
-extern void handle_device_data(int, short, void *);
-extern void handle_meta_connection_data(int, short, void *);
+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);
extern void retry(void);
which will be broadcast to the local network.
*/
-static void send_mtu_probe_handler(int fd, short events, void *data) {
+static void send_mtu_probe_handler(void *data) {
node_t *n = data;
int timeout = 1;
}
end:
- event_add(&n->mtuevent, &(struct timeval){timeout, rand() % 100000});
+ timeout_set(&n->mtutimeout, &(struct timeval){timeout, rand() % 100000});
}
void send_mtu_probe(node_t *n) {
- if(!timeout_initialized(&n->mtuevent))
- timeout_set(&n->mtuevent, send_mtu_probe_handler, n);
- send_mtu_probe_handler(0, 0, n);
+ timeout_add(&n->mtutimeout, send_mtu_probe_handler, n, &(struct timeval){1, 0});
+ send_mtu_probe_handler(n);
}
static void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
/* Make sure we have a valid key */
if(!n->status.validkey) {
- time_t now = time(NULL);
-
logger(DEBUG_TRAFFIC, LOG_INFO,
"No valid key known yet for %s (%s), forwarding via TCP",
n->name, n->hostname);
- if(n->last_req_key + 10 <= now) {
+ if(n->last_req_key + 10 <= now.tv_sec) {
send_req_key(n);
- n->last_req_key = now;
+ n->last_req_key = now.tv_sec;
}
send_tcppacket(n->nexthop->connection, origpkt);
&& listen_socket[n->sock].sa.sa.sa_family == AF_INET) {
priority = origpriority;
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
- if(setsockopt(listen_socket[n->sock].udp, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */
+ if(setsockopt(listen_socket[n->sock].udp.fd, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
}
#endif
- if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
+ if(sendto(listen_socket[sock].udp.fd, (char *) &inpkt->seqno, inpkt->len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
if(sockmsgsize(sockerrno)) {
if(n->maxmtu >= origlen)
n->maxmtu = origlen - 1;
choose_udp_address(to, &sa, &sock);
- if(sendto(listen_socket[sock].udp, data, len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
+ if(sendto(listen_socket[sock].udp.fd, data, len, 0, &sa->sa, SALEN(sa->sa)) < 0 && !sockwouldblock(sockerrno)) {
if(sockmsgsize(sockerrno)) {
if(to->maxmtu >= len)
to->maxmtu = len - 1;
node_t *n = NULL;
bool hard = false;
static time_t last_hard_try = 0;
- time_t now = time(NULL);
for splay_each(edge_t, e, edge_weight_tree) {
if(!e->to->status.reachable || e->to == myself)
continue;
if(sockaddrcmp_noport(from, &e->address)) {
- if(last_hard_try == now)
+ if(last_hard_try == now.tv_sec)
continue;
hard = true;
}
}
if(hard)
- last_hard_try = now;
+ last_hard_try = now.tv_sec;
- last_hard_try = now;
+ last_hard_try = now.tv_sec;
return n;
}
-void handle_incoming_vpn_data(int sock, short events, void *data) {
+void handle_incoming_vpn_data(void *data, int flags) {
+ listen_socket_t *ls = data;
vpn_packet_t pkt;
char *hostname;
sockaddr_t from = {{0}};
node_t *n;
int len;
- len = recvfrom(sock, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
+ len = recvfrom(ls->udp.fd, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
if(len <= 0 || len > MAXSIZE) {
if(!sockwouldblock(sockerrno))
return;
}
- n->sock = (intptr_t)data;
+ n->sock = ls - listen_socket;
receive_udppacket(n, &pkt);
}
-void handle_device_data(int sock, short events, void *data) {
+void handle_device_data(void *data, int flags) {
vpn_packet_t packet;
packet.priority = 0;
#include "xalloc.h"
char *myport;
-static struct event device_ev;
+static io_t device_io;
devops_t devops;
char *proxyhost;
return result;
}
-static struct event keyexpire_event;
+static timeout_t keyexpire_timeout;
-static void keyexpire_handler(int fd, short events, void *data) {
+static void keyexpire_handler(void *data) {
regenerate_key();
+ timeout_set(data, &(struct timeval){keylifetime, rand() % 100000});
}
void regenerate_key(void) {
- if(timeout_initialized(&keyexpire_event)) {
- logger(DEBUG_STATUS, LOG_INFO, "Expiring symmetric keys");
- event_del(&keyexpire_event);
- send_key_changed();
- } else {
- timeout_set(&keyexpire_event, keyexpire_handler, NULL);
- }
-
- event_add(&keyexpire_event, &(struct timeval){keylifetime, rand() % 100000});
+ logger(DEBUG_STATUS, LOG_INFO, "Expiring symmetric keys");
+ send_key_changed();
}
/*
free(cipher);
- regenerate_key();
+ send_key_changed();
+ timeout_add(&keyexpire_timeout, keyexpire_handler, &keyexpire_timeout, &(struct timeval){keylifetime, rand() % 100000});
/* Check if we want to use message authentication codes... */
if(!devops.setup())
return false;
- if(device_fd >= 0) {
- event_set(&device_ev, device_fd, EV_READ|EV_PERSIST, handle_device_data, NULL);
-
- if (event_add(&device_ev, NULL) < 0) {
- logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
- devops.close();
- return false;
- }
- }
+ if(device_fd >= 0)
+ io_add(&device_io, handle_device_data, NULL, device_fd, IO_READ);
/* Run tinc-up script to further initialize the tap interface */
char *envp[5];
return false;
}
- listen_socket[i].tcp = i + 3;
-
#ifdef FD_CLOEXEC
fcntl(i + 3, F_SETFD, FD_CLOEXEC);
#endif
- listen_socket[i].udp = setup_vpn_in_socket(&sa);
- if(listen_socket[i].udp < 0)
+ int udp_fd = setup_vpn_in_socket(&sa);
+ if(udp_fd < 0)
return false;
- event_set(&listen_socket[i].ev_tcp, listen_socket[i].tcp, EV_READ|EV_PERSIST, handle_new_meta_connection, NULL);
- if(event_add(&listen_socket[i].ev_tcp, NULL) < 0) {
- logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
- abort();
- }
-
- event_set(&listen_socket[i].ev_udp, listen_socket[i].udp, EV_READ|EV_PERSIST, handle_incoming_vpn_data, (void *)(intptr_t)listen_sockets);
- if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
- logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
- abort();
- }
+ io_add(&listen_socket[i].tcp, (io_cb_t)handle_new_meta_connection, &listen_socket[i], i + 3, IO_READ);
+ io_add(&listen_socket[i].udp, (io_cb_t)handle_incoming_vpn_data, &listen_socket[i], udp_fd, IO_READ);
if(debug_level >= DEBUG_CONNECTIONS) {
hostname = sockaddr2hostname(&sa);
return false;
}
- listen_socket[listen_sockets].tcp =
- setup_listen_socket((sockaddr_t *) aip->ai_addr);
+ int tcp_fd = setup_listen_socket((sockaddr_t *) aip->ai_addr);
- if(listen_socket[listen_sockets].tcp < 0)
+ if(tcp_fd < 0)
continue;
- listen_socket[listen_sockets].udp =
- setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
+ int udp_fd = setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
- if(listen_socket[listen_sockets].udp < 0) {
- close(listen_socket[listen_sockets].tcp);
+ if(tcp_fd < 0) {
+ close(tcp_fd);
continue;
}
- event_set(&listen_socket[listen_sockets].ev_tcp,
- listen_socket[listen_sockets].tcp,
- EV_READ|EV_PERSIST,
- handle_new_meta_connection, NULL);
- if(event_add(&listen_socket[listen_sockets].ev_tcp, NULL) < 0) {
- logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
- abort();
- }
-
- event_set(&listen_socket[listen_sockets].ev_udp,
- listen_socket[listen_sockets].udp,
- EV_READ|EV_PERSIST,
- handle_incoming_vpn_data, (void *)(intptr_t)listen_sockets);
- if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
- logger(DEBUG_ALWAYS, LOG_ERR, "event_add failed: %s", strerror(errno));
- abort();
- }
+ io_add(&listen_socket[listen_sockets].tcp, handle_new_meta_connection, &listen_socket[listen_sockets], tcp_fd, IO_READ);
+ io_add(&listen_socket[listen_sockets].udp, handle_incoming_vpn_data, &listen_socket[listen_sockets], udp_fd, IO_READ);
if(debug_level >= DEBUG_CONNECTIONS) {
hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
}
for(int i = 0; i < listen_sockets; i++) {
- event_del(&listen_socket[i].ev_tcp);
- event_del(&listen_socket[i].ev_udp);
- close(listen_socket[i].tcp);
- close(listen_socket[i].udp);
+ io_del(&listen_socket[i].tcp);
+ io_del(&listen_socket[i].udp);
+ close(listen_socket[i].tcp.fd);
+ close(listen_socket[i].udp.fd);
}
char *envp[5];
return nfd;
} /* int setup_vpn_in_socket */
-static void retry_outgoing_handler(int fd, short events, void *data) {
+static void retry_outgoing_handler(void *data) {
setup_outgoing_connection(data);
}
if(outgoing->timeout > maxtimeout)
outgoing->timeout = maxtimeout;
- timeout_set(&outgoing->ev, retry_outgoing_handler, outgoing);
- event_add(&outgoing->ev, &(struct timeval){outgoing->timeout, rand() % 100000});
+ timeout_add(&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);
+ logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Trying to re-establish outgoing connection in %d seconds", outgoing->timeout);
}
void finish_connecting(connection_t *c) {
#endif
}
-static void handle_meta_write(int sock, short events, void *data) {
- connection_t *c = data;
-
+static void handle_meta_write(connection_t *c) {
ssize_t outlen = send(c->socket, c->outbuf.data + c->outbuf.offset, c->outbuf.len - c->outbuf.offset, 0);
if(outlen <= 0) {
if(!errno || errno == EPIPE) {
}
buffer_read(&c->outbuf, outlen);
- if(!c->outbuf.len && event_initialized(&c->outevent))
- event_del(&c->outevent);
+ if(!c->outbuf.len)
+ io_set(&c->io, IO_READ);
}
+static void handle_meta_io(void *data, int flags) {
+ if(flags & IO_WRITE)
+ handle_meta_write(data);
+ else
+ handle_meta_connection_data(data);
+}
bool do_outgoing_connection(outgoing_t *outgoing) {
char *address, *port, *space;
connection_add(c);
- event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c);
- event_set(&c->outevent, c->socket, EV_WRITE | EV_PERSIST, handle_meta_write, c);
- event_add(&c->inevent, NULL);
+ io_add(&c->io, handle_meta_io, c, c->socket, IO_READ);
return true;
}
void setup_outgoing_connection(outgoing_t *outgoing) {
- if(event_initialized(&outgoing->ev))
- event_del(&outgoing->ev);
+ timeout_del(&outgoing->ev);
node_t *n = lookup_node(outgoing->name);
accept a new tcp connect and create a
new connection
*/
-void handle_new_meta_connection(int sock, short events, void *data) {
+void handle_new_meta_connection(void *data, int flags) {
+ listen_socket_t *l = data;
connection_t *c;
sockaddr_t sa;
int fd;
socklen_t len = sizeof sa;
- fd = accept(sock, &sa.sa, &len);
+ fd = accept(l->tcp.fd, &sa.sa, &len);
if(fd < 0) {
logger(DEBUG_ALWAYS, LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno));
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection from %s", c->hostname);
- event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c);
- event_set(&c->outevent, c->socket, EV_WRITE | EV_PERSIST, handle_meta_write, c);
- event_add(&c->inevent, NULL);
+ io_add(&c->io, handle_meta_io, c, c->socket, IO_READ);
configure_tcp(c);
}
static void free_outgoing(outgoing_t *outgoing) {
- if(event_initialized(&outgoing->ev))
- event_del(&outgoing->ev);
+ timeout_del(&outgoing->ev);
if(outgoing->ai)
freeaddrinfo(outgoing->ai);
ecdsa_free(&n->ecdsa);
sptps_stop(&n->sptps);
- if(timeout_initialized(&n->mtuevent))
- event_del(&n->mtuevent);
+ timeout_del(&n->mtutimeout);
if(n->hostname)
free(n->hostname);
#include "cipher.h"
#include "connection.h"
#include "digest.h"
+#include "event.h"
#include "subnet.h"
typedef struct node_status_t {
length_t minmtu; /* Probed minimum MTU */
length_t maxmtu; /* Probed maximum MTU */
int mtuprobes; /* Number of probes */
- struct event mtuevent; /* Probe event */
+ timeout_t mtutimeout; /* Probe event */
uint64_t in_packets;
uint64_t in_bytes;
free(r);
}
-static struct event past_request_event;
+static timeout_t past_request_timeout;
+
+static void age_past_requests(void *data) {
+ int left = 0, deleted = 0;
+
+ for splay_each(past_request_t, p, past_request_tree) {
+ if(p->firstseen + pinginterval <= now.tv_sec)
+ splay_delete_node(past_request_tree, node), deleted++;
+ else
+ left++;
+ }
+
+ if(left || deleted)
+ 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});
+}
bool seen_request(const char *request) {
past_request_t *new, p = {NULL};
new->request = xstrdup(request);
new->firstseen = time(NULL);
splay_insert(past_request_tree, new);
- event_add(&past_request_event, &(struct timeval){10, rand() % 100000});
+ timeout_add(&past_request_timeout, age_past_requests, NULL, &(struct timeval){10, rand() % 100000});
return false;
}
}
-static void age_past_requests(int fd, short events, void *data) {
- int left = 0, deleted = 0;
- time_t now = time(NULL);
-
- for splay_each(past_request_t, p, past_request_tree) {
- if(p->firstseen + pinginterval <= now)
- splay_delete_node(past_request_tree, node), deleted++;
- else
- left++;
- }
-
- if(left || deleted)
- logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Aging past requests: deleted %d, left %d",
- deleted, left);
-
- if(left)
- event_add(&past_request_event, &(struct timeval){10, rand() % 100000});
-}
-
void init_requests(void) {
past_request_tree = splay_alloc_tree((splay_compare_t) past_request_compare, (splay_action_t) free_past_request);
-
- timeout_set(&past_request_event, age_past_requests, NULL);
}
void exit_requests(void) {
splay_delete_tree(past_request_tree);
- if(timeout_initialized(&past_request_event))
- event_del(&past_request_event);
+ timeout_del(&past_request_timeout);
}
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
-static struct event age_subnets_event;
+static timeout_t age_subnets_timeout;
/* RFC 1071 */
static bool ratelimit(int frequency) {
static time_t lasttime = 0;
static int count = 0;
- time_t now = time(NULL);
- if(lasttime == now) {
+ if(lasttime == now.tv_sec) {
if(count >= frequency)
return true;
} else {
- lasttime = now;
+ lasttime = now.tv_sec;
count = 0;
}
memcpy(&packet->data[6], &tmp, sizeof tmp);
}
-static void age_subnets(int fd, short events, void *data) {
+static void age_subnets(void *data) {
bool left = false;
- time_t now = time(NULL);
for splay_each(subnet_t, s, myself->subnet_tree) {
- if(s->expires && s->expires < now) {
+ if(s->expires && s->expires < now.tv_sec) {
if(debug_level >= DEBUG_TRAFFIC) {
char netstr[MAXNETSTR];
if(net2str(netstr, sizeof netstr, s))
}
if(left)
- event_add(&age_subnets_event, &(struct timeval){10, rand() % 100000});
+ timeout_set(&age_subnets_timeout, &(struct timeval){10, rand() % 100000});
}
static void learn_mac(mac_t *address) {
if(c->status.active)
send_add_subnet(c, subnet);
- if(!timeout_initialized(&age_subnets_event))
- timeout_set(&age_subnets_event, age_subnets, NULL);
- event_add(&age_subnets_event, &(struct timeval){10, rand() % 100000});
+ timeout_add(&age_subnets_timeout, age_subnets, NULL, &(struct timeval){10, rand() % 100000});
} else {
if(subnet->expires)
subnet->expires = time(NULL) + macexpire;
struct list_t *connection_list = NULL;
bool send_meta(void *c, const char *msg , int len) { return false; }
char *logfilename = NULL;
+struct timeval now;
ecdsa_t mykey, hiskey;
char *confbase = NULL;
static char *tinc_conf = NULL;
static char *hosts_dir = NULL;
+struct timeval now;
// Horrible global variables...
static int pid = 0;
}
#endif
-#ifdef HAVE_DARWIN
- if(!getenv("EVENT_KQUEUE"))
- setenv("EVENT_NOKQUEUE", "1", 0);
- if(!getenv("EVENT_POLL"))
- setenv("EVENT_NOPOLL", "1", 0);
-#endif
-
- if(!event_init()) {
- logger(DEBUG_ALWAYS, LOG_ERR, "Error initializing libevent!");
- return 1;
- }
-
/* Setup sockets and open device. */
if(!setup_network())
static bool cumulative = false;
static list_t node_list;
-static struct timeval now, prev, diff;
+static struct timeval cur, prev, diff;
static int delay = 1000;
static bool changed = true;
static const char *unit = "bytes";
static void update(int fd) {
sendline(fd, "%d %d", CONTROL, REQ_DUMP_TRAFFIC);
- gettimeofday(&now, NULL);
+ gettimeofday(&cur, NULL);
- timersub(&now, &prev, &diff);
- prev = now;
+ timersub(&cur, &prev, &diff);
+ prev = cur;
float interval = diff.tv_sec + diff.tv_usec * 1e-6;
char line[4096];