Drop libevent and use our own event handling again.

There are several reasons for this:

- MacOS/X doesn't support polling the tap device using kqueue, requiring a
  workaround to fall back to select().
- On Windows only sockets are properly handled, therefore tinc uses a second
  thread that does a blocking ReadFile() on the TAP-Win32/64 device. However,
  this does not mix well with libevent.
- Libevent, event just the core, is quite large, and although it is easy to get
  and install on many platforms, it can be a burden.
- Libev is more lightweight and seems technically superior, but it doesn't
  abstract away all the platform differences (for example, async events are not
  supported on Windows).
This commit is contained in:
Guus Sliepen 2012-11-29 12:28:23 +01:00
parent d30b9e1272
commit 6bc5d626a8
28 changed files with 459 additions and 299 deletions

1
README
View file

@ -50,7 +50,6 @@ In order to compile tinc, you will need a GNU C compiler environment. Please
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:

View file

@ -8,7 +8,6 @@ to install the very latest versions of the following packages:
- automake
- autoconf
- gettext
- libevent
Then you have to let the autotools create all the autogenerated files, using
this command:

View file

@ -183,7 +183,6 @@ AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcry
tinc_CURSES
tinc_READLINE
tinc_LIBEVENT
tinc_ZLIB
tinc_LZO

View file

@ -339,7 +339,6 @@ having them installed, configure will give you an error message, and stop.
* OpenSSL::
* zlib::
* lzo::
* libevent::
* libcurses::
* libreadline::
@end menu
@ -458,27 +457,6 @@ make sure you build development and runtime libraries (which is the
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

4
have.h
View file

@ -196,10 +196,6 @@
#include <netinet/if_ether.h>
#endif
#ifdef HAVE_EVENT_H
#include <event.h>
#endif
#ifdef HAVE_MINGW
#define SLASH "\\"
#else

View file

@ -1,33 +0,0 @@
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.")]
)
])

View file

@ -8,7 +8,7 @@ tincd_SOURCES = \
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
@ -46,7 +46,7 @@ INCLUDES = @INCLUDES@ -I$(top_builddir)
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

View file

@ -68,11 +68,7 @@ void free_connection(connection_t *c) {
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);

View file

@ -90,8 +90,7 @@ typedef struct connection_t {
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 */

View file

@ -58,7 +58,7 @@ bool control_h(connection_t *c, const char *request) {
switch (type) {
case REQ_STOP:
event_loopexit(NULL);
event_exit();
return control_ok(c, REQ_STOP);
case REQ_DUMP_NODES:
@ -156,7 +156,7 @@ bool init_control(void) {
// 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) {

236
src/event.c Normal file
View file

@ -0,0 +1,236 @@
/*
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;
}

70
src/event.h Normal file
View file

@ -0,0 +1,70 @@
/*
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

View file

@ -213,8 +213,7 @@ static void check_reachability(void) {
n->minmtu = 0;
n->mtuprobes = 0;
if(timeout_initialized(&n->mtuevent))
event_del(&n->mtuevent);
timeout_del(&n->mtutimeout);
char *name;
char *address;

View file

@ -41,7 +41,6 @@ bool logcontrol = false;
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.
@ -58,8 +57,9 @@ static void real_logger(int level, int priority, const char *message) {
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;

View file

@ -39,7 +39,7 @@ bool send_meta_sptps(void *handle, uint8_t type, const char *buffer, size_t leng
}
buffer_add(&c->outbuf, buffer, length);
event_add(&c->outevent, NULL);
io_set(&c->io, IO_READ | IO_WRITE);
return true;
}
@ -65,12 +65,11 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
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;
}

View file

@ -137,18 +137,16 @@ void terminate_connection(connection_t *c, bool report) {
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 {
@ -164,10 +162,10 @@ static void timeout_handler(int fd, short events, void *event) {
}
}
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.
@ -278,11 +276,10 @@ static void periodic_handler(int fd, short events, void *event) {
}
}
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;
@ -306,19 +303,19 @@ void handle_meta_connection_data(int fd, short events, void *data) {
}
}
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();
}
@ -332,7 +329,7 @@ int reload_configuration(void) {
if(!read_server_config()) {
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to reread configuration file, exitting.");
event_loopexit(NULL);
event_exit();
return EINVAL;
}
@ -431,8 +428,7 @@ int reload_configuration(void) {
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;
@ -445,44 +441,38 @@ void retry(void) {
this is where it all happens...
*/
int main_loop(void) {
struct event timeout_event;
struct event periodic_event;
timeout_t pingtimer = {{0}};
timeout_t periodictimer = {{0}};
timeout_set(&timeout_event, timeout_handler, &timeout_event);
event_add(&timeout_event, &(struct timeval){pingtimeout, rand() % 100000});
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_t sighup = {0};
signal_t sigterm = {0};
signal_t sigquit = {0};
signal_t sigalrm = {0};
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_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;
}

View file

@ -24,6 +24,7 @@
#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 */
@ -99,10 +100,8 @@ typedef enum packet_type_t {
} 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;
@ -116,7 +115,7 @@ typedef struct outgoing_t {
struct config_t *cfg;
struct addrinfo *ai;
struct addrinfo *aip;
struct event ev;
timeout_t ev;
} outgoing_t;
extern list_t *outgoing_list;
@ -161,10 +160,10 @@ extern char *scriptextension;
#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);
@ -184,8 +183,8 @@ extern bool node_read_ecdsa_public_key(struct node_t *);
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);

View file

@ -77,7 +77,7 @@ bool localdiscovery = false;
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;
@ -151,13 +151,12 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
}
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) {
@ -557,15 +556,13 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
/* 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);
@ -644,12 +641,12 @@ static void send_udppacket(node_t *n, vpn_packet_t *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;
@ -686,7 +683,7 @@ bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len) {
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;
@ -869,14 +866,13 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
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;
}
@ -889,13 +885,14 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
}
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}};
@ -903,7 +900,7 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
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))
@ -931,12 +928,12 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
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;

View file

@ -42,7 +42,7 @@
#include "xalloc.h"
char *myport;
static struct event device_ev;
static io_t device_io;
devops_t devops;
char *proxyhost;
@ -270,22 +270,16 @@ static bool read_rsa_private_key(void) {
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();
}
/*
@ -716,7 +710,8 @@ static bool setup_myself(void) {
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... */
@ -790,15 +785,8 @@ static bool setup_myself(void) {
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];
@ -840,27 +828,16 @@ static bool setup_myself(void) {
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);
@ -913,37 +890,20 @@ static bool setup_myself(void) {
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);
@ -1025,10 +985,10 @@ void close_network_connections(void) {
}
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];

View file

@ -271,7 +271,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
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);
}
@ -281,12 +281,9 @@ void retry_outgoing(outgoing_t *outgoing) {
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) {
@ -349,9 +346,7 @@ static void do_outgoing_pipe(connection_t *c, char *command) {
#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) {
@ -368,10 +363,16 @@ static void handle_meta_write(int sock, short events, void *data) {
}
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;
@ -487,16 +488,13 @@ begin:
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);
@ -523,13 +521,14 @@ void setup_outgoing_connection(outgoing_t *outgoing) {
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));
@ -552,9 +551,7 @@ void handle_new_meta_connection(int sock, short events, void *data) {
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);
@ -565,8 +562,7 @@ void handle_new_meta_connection(int sock, short events, void *data) {
}
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);

View file

@ -78,8 +78,7 @@ void free_node(node_t *n) {
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);

View file

@ -25,6 +25,7 @@
#include "cipher.h"
#include "connection.h"
#include "digest.h"
#include "event.h"
#include "subnet.h"
typedef struct node_status_t {
@ -83,7 +84,7 @@ typedef struct node_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;

View file

@ -165,7 +165,24 @@ static void free_past_request(past_request_t *r) {
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};
@ -180,39 +197,17 @@ bool seen_request(const char *request) {
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);
}

View file

@ -59,7 +59,7 @@ static const size_t opt_size = sizeof(struct nd_opt_hdr);
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
static struct event age_subnets_event;
static timeout_t age_subnets_timeout;
/* RFC 1071 */
@ -84,13 +84,12 @@ static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) {
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;
}
@ -192,12 +191,11 @@ static void swap_mac_addresses(vpn_packet_t *packet) {
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))
@ -216,7 +214,7 @@ static void age_subnets(int fd, short events, void *data) {
}
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) {
@ -243,9 +241,7 @@ 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;

View file

@ -29,6 +29,7 @@ bool send_request(void *c, const char *msg, ...) { return false; }
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;

View file

@ -62,6 +62,7 @@ char *netname = NULL;
char *confbase = NULL;
static char *tinc_conf = NULL;
static char *hosts_dir = NULL;
struct timeval now;
// Horrible global variables...
static int pid = 0;

View file

@ -450,18 +450,6 @@ int main2(int argc, char **argv) {
}
#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())

View file

@ -57,7 +57,7 @@ static int sortmode = 0;
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";
@ -69,10 +69,10 @@ static float scale = 1;
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];