Merge branch 'master' into 1.1
authorGuus Sliepen <guus@tinc-vpn.org>
Tue, 29 Sep 2009 12:55:29 +0000 (14:55 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Tue, 29 Sep 2009 12:55:29 +0000 (14:55 +0200)
Conflicts:
NEWS
configure.in
lib/Makefile.am
lib/pidfile.c
lib/pidfile.h
lib/utils.c
po/POTFILES.in
po/nl.po
src/Makefile.am
src/bsd/device.c
src/conf.c
src/connection.c
src/cygwin/device.c
src/edge.c
src/event.c
src/graph.c
src/linux/device.c
src/meta.c
src/mingw/device.c
src/net.c
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/netutl.c
src/node.c
src/process.c
src/protocol.c
src/protocol_auth.c
src/protocol_edge.c
src/protocol_key.c
src/protocol_misc.c
src/protocol_subnet.c
src/raw_socket/device.c
src/route.c
src/solaris/device.c
src/subnet.c
src/tincd.c
src/uml_socket/device.c

49 files changed:
1  2 
NEWS
configure.in
doc/tinc.texi
doc/tincd.8.in
have.h
lib/Makefile.am
lib/avl_tree.c
src/Makefile.am
src/bsd/device.c
src/conf.c
src/conf.h
src/connection.c
src/connection.h
src/cygwin/device.c
src/edge.c
src/edge.h
src/graph.c
src/graph.h
src/linux/device.c
src/logger.c
src/meta.c
src/meta.h
src/mingw/device.c
src/net.c
src/net.h
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/netutl.c
src/node.c
src/node.h
src/openssl/rsagen.h
src/process.c
src/process.h
src/protocol.c
src/protocol.h
src/protocol_auth.c
src/protocol_edge.c
src/protocol_key.c
src/protocol_misc.c
src/protocol_subnet.c
src/raw_socket/device.c
src/route.c
src/route.h
src/solaris/device.c
src/subnet.c
src/subnet.h
src/tincd.c
src/uml_socket/device.c

diff --cc NEWS
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -1,9 -1,36 +1,42 @@@
 +Version 1.1-cvs              Work in progress
 +
 + * Use libevent to handle I/O events and timeouts.
 +
 + * Use splay trees instead of AVL trees.
 +
+ Version 1.0.10               not yet released
+  * Fixed potential crashes during shutdown and (in rare conditions) when other
+    nodes disconnected from the VPN.
+  * Improved NAT handling: tinc now copes with mangled port numbers, and will
+    automatically fall back to TCP if direct UDP connection between nodes is not
+    possible.
+  * Allow configuration files with CRLF line endings to be read on UNIX.
+  * Disable old RSA keys when generating new ones.
+  * Many fixes in the path MTU discovery code.
+  * Tinc can now drop privileges and/or chroot itself.
+  * The TunnelServer code now just ignores information from clients instead of
+    disconnecting them.
+  * Improved performance on Windows by using the new ProcessPriority option and
+    by making the handling of packets received from the TAP-Win32 adapter more
+    efficient.
+  * Code cleanups: tinc now follows the C99 standard, copyright headers have
+    been updated to include patch authors, checkpoint tracing and localisation
+    features have been removed.
+  * Support for (jailbroken) iPhone and iPod Touch has been added.
+  Thanks to Florian Forster, Grzegorz Dymarek and especially Michael Tokarev for
+  their contributions to this version of tinc.
  Version 1.0.9                Dec 26 2008
  
   * Fixed tinc as a service under Windows 2003.
diff --cc configure.in
@@@ -1,12 -1,9 +1,10 @@@
  dnl Process this file with autoconf to produce a configure script.
  
- dnl $Id$
- AC_PREREQ(2.59)
+ AC_PREREQ(2.61)
  AC_INIT
  AC_CONFIG_SRCDIR([src/tincd.c])
 -AM_INIT_AUTOMAKE(tinc, 1.0-cvs)
 +AC_GNU_SOURCE
 +AM_INIT_AUTOMAKE(tinc, 1.1-cvs)
  AC_CONFIG_HEADERS([config.h])
  AM_MAINTAINER_MODE
  
diff --cc doc/tinc.texi
Simple merge
diff --cc doc/tincd.8.in
Simple merge
diff --cc have.h
Simple merge
diff --cc lib/Makefile.am
@@@ -10,6 -9,6 +9,6 @@@ libvpn_a_SOURCES = xmalloc.c utils.c ge
  libvpn_a_LIBADD = @LIBOBJS@ @ALLOCA@
  libvpn_a_DEPENDENCIES = $(libvpn_a_LIBADD)
  
- 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 gettext.h ipv6.h ipv4.h ethernet.h
 -noinst_HEADERS = xalloc.h pidfile.h utils.h getopt.h list.h avl_tree.h dropin.h fake-getaddrinfo.h fake-getnameinfo.h fake-gai-errnos.h ipv6.h ipv4.h ethernet.h
++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
  
  EXTRA_DIST = 
diff --cc lib/avl_tree.c
Simple merge
diff --cc src/Makefile.am
@@@ -1,7 -1,6 +1,6 @@@
  ## Produce this file with automake to get Makefile.in
- # $Id: Makefile.am,v 1.4.4.33 2003/08/02 15:13:08 guus Exp $
  
 -sbin_PROGRAMS = tincd
 +sbin_PROGRAMS = tincd tincctl
  
  EXTRA_DIST = linux/device.c bsd/device.c solaris/device.c cygwin/device.c mingw/device.c mingw/common.h raw_socket/device.c uml_socket/device.c
  
@@@ -21,10 -18,10 +20,10 @@@ DEFAULT_INCLUDES 
  
  INCLUDES = @INCLUDES@ -I$(top_builddir) -I$(top_srcdir)/lib
  
 -noinst_HEADERS = conf.h connection.h device.h edge.h event.h graph.h logger.h meta.h net.h netutl.h node.h process.h  \
 -      protocol.h route.h subnet.h bsd/tunemu.h
 +noinst_HEADERS = cipher.h conf.h connection.h control.h crypto.h device.h digest.h edge.h graph.h logger.h meta.h net.h netutl.h node.h process.h     \
 +      protocol.h route.h rsa.h rsagen.h subnet.h bsd/tunemu.h
  
- LIBS = @LIBS@ @LIBGCRYPT_LIBS@ @LIBINTL@
 -LIBS = @LIBS@
++LIBS = @LIBS@ @LIBGCRYPT_LIBS@
  
  if TUNEMU
  LIBS += -lpcap
@@@ -184,23 -179,21 +179,21 @@@ void close_device(void) 
  }
  
  bool read_packet(vpn_packet_t *packet) {
 -      int lenin;
 +      int inlen;
  
-       cp();
        switch(device_type) {
                case DEVICE_TYPE_TUN:
  #ifdef HAVE_TUNEMU
                case DEVICE_TYPE_TUNEMU:
                        if(device_type == DEVICE_TYPE_TUNEMU)
 -                              lenin = tunemu_read(device_fd, packet->data + 14, MTU - 14);
 +                              inlen = tunemu_read(device_fd, packet->data + 14, MTU - 14);
                        else
  #else
 -                              lenin = read(device_fd, packet->data + 14, MTU - 14);
 +                              inlen = read(device_fd, packet->data + 14, MTU - 14);
  #endif
  
 -                      if(lenin <= 0) {
 +                      if(inlen <= 0) {
-                               logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
+                               logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
                                           device, strerror(errno));
                                return false;
                        }
  
                case DEVICE_TYPE_TUNIFHEAD: {
                        u_int32_t type;
 -                      struct iovec vector[2] = {{&type, sizeof(type)}, {packet->data + 14, MTU - 14}};
 +                      struct iovec vector[2] = {{&type, sizeof type}, {packet->data + 14, MTU - 14}};
  
 -                      if((lenin = readv(device_fd, vector, 2)) <= 0) {
 +                      if((inlen = readv(device_fd, vector, 2)) <= 0) {
-                               logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
+                               logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
                                           device, strerror(errno));
                                return false;
                        }
                }
  
                case DEVICE_TYPE_TAP:
 -                      if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
 +                      if((inlen = read(device_fd, packet->data, MTU)) <= 0) {
-                               logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
+                               logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
                                           device, strerror(errno));
                                return false;
                        }
diff --cc src/conf.c
@@@ -54,16 -52,12 +52,12 @@@ static int config_compare(const config_
                return strcmp(a->file, b->file);
  }
  
 -void init_configuration(avl_tree_t ** config_tree) {
 -      *config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
 +void init_configuration(splay_tree_t ** config_tree) {
-       cp();
 +      *config_tree = splay_alloc_tree((splay_compare_t) config_compare, (splay_action_t) free_config);
  }
  
 -void exit_configuration(avl_tree_t ** config_tree) {
 -      avl_delete_tree(*config_tree);
 +void exit_configuration(splay_tree_t ** config_tree) {
-       cp();
 +      splay_delete_tree(*config_tree);
        *config_tree = NULL;
  }
  
@@@ -88,17 -78,13 +78,13 @@@ void free_config(config_t *cfg) 
        free(cfg);
  }
  
 -void config_add(avl_tree_t *config_tree, config_t *cfg) {
 -      avl_insert(config_tree, cfg);
 +void config_add(splay_tree_t *config_tree, config_t *cfg) {
-       cp();
 +      splay_insert(config_tree, cfg);
  }
  
 -config_t *lookup_config(avl_tree_t *config_tree, char *variable) {
 +config_t *lookup_config(splay_tree_t *config_tree, char *variable) {
        config_t cfg, *found;
  
-       cp();
        cfg.variable = variable;
        cfg.file = "";
        cfg.line = 0;
        return found;
  }
  
 -config_t *lookup_config_next(avl_tree_t *config_tree, const config_t *cfg) {
 -      avl_node_t *node;
 +config_t *lookup_config_next(splay_tree_t *config_tree, const config_t *cfg) {
 +      splay_node_t *node;
        config_t *found;
  
-       cp();
 -      node = avl_search_node(config_tree, cfg);
 +      node = splay_search_node(config_tree, cfg);
  
        if(node) {
                if(node->next) {
@@@ -218,10 -192,10 +192,10 @@@ bool get_config_subnet(const config_t *
        /* Teach newbies what subnets are... */
  
        if(((subnet.type == SUBNET_IPV4)
 -              && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t)))
 +              && !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof subnet.net.ipv4.address))
                || ((subnet.type == SUBNET_IPV6)
 -              && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) {
 +              && !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof subnet.net.ipv6.address))) {
-               logger(LOG_ERR, _ ("Network address and prefix length do not match for configuration variable %s in %s line %d"),
+               logger(LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
                           cfg->variable, cfg->file, cfg->line);
                return false;
        }
diff --cc src/conf.h
Simple merge
@@@ -41,33 -39,31 +40,25 @@@ static int connection_compare(const con
  }
  
  void init_connections(void) {
-       cp();
 -      connection_tree = avl_alloc_tree((avl_compare_t) connection_compare, (avl_action_t) free_connection);
 +      connection_tree = splay_alloc_tree((splay_compare_t) connection_compare, (splay_action_t) free_connection);
        broadcast = new_connection();
-       broadcast->name = xstrdup(_("everyone"));
-       broadcast->hostname = xstrdup(_("BROADCAST"));
+       broadcast->name = xstrdup("everyone");
+       broadcast->hostname = xstrdup("BROADCAST");
  }
  
  void exit_connections(void) {
-       cp();
 -      avl_delete_tree(connection_tree);
 +      splay_delete_tree(connection_tree);
        free_connection(broadcast);
  }
  
  connection_t *new_connection(void) {
-       cp();
 -      connection_t *c;
 -
 -      c = xmalloc_and_zero(sizeof(connection_t));
 -
 -      if(!c)
 -              return NULL;
 -
 -      gettimeofday(&c->start, NULL);
--
 -      return c;
 +      return xmalloc_and_zero(sizeof(connection_t));
  }
  
  void free_connection(connection_t *c) {
-       cp();
 +      if(!c)
 +              return;
 +
        if(c->name)
                free(c->name);
  
  }
  
  void connection_add(connection_t *c) {
-       cp();
 -      avl_insert(connection_tree, c);
 +      splay_insert(connection_tree, c);
  }
  
  void connection_del(connection_t *c) {
-       cp();
 -      avl_delete(connection_tree, c);
 +      splay_delete(connection_tree, c);
  }
  
 -void dump_connections(void) {
 -      avl_node_t *node;
 +int dump_connections(struct evbuffer *out) {
 +      splay_node_t *node;
        connection_t *c;
  
-       cp();
 -      logger(LOG_DEBUG, "Connections:");
--
        for(node = connection_tree->head; node; node = node->next) {
                c = node->data;
 -              logger(LOG_DEBUG, " %s at %s options %lx socket %d status %04x outbuf %d/%d/%d",
 -                         c->name, c->hostname, c->options, c->socket, bitfield_to_int(&c->status, sizeof c->status),
 -                         c->outbufsize, c->outbufstart, c->outbuflen);
 +              if(evbuffer_add_printf(out,
-                                  _(" %s at %s options %lx socket %d status %04x\n"),
++                                 " %s at %s options %lx socket %d status %04x\n",
 +                                 c->name, c->hostname, c->options, c->socket,
 +                                 bitfield_to_int(&c->status, sizeof c->status)) == -1)
 +                      return errno;
        }
  
 -      logger(LOG_DEBUG, "End of connections.");
 +      return 0;
  }
  
  bool read_connection_config(connection_t *c) {
Simple merge
@@@ -153,8 -149,8 +149,8 @@@ bool setup_device(void) 
  
        /* Get MAC address from tap device */
  
 -      if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
 +      if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) {
-               logger(LOG_ERR, _("Could not get MAC address from Windows tap device %s (%s): %s"), device, iface, winerror(GetLastError()));
+               logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
                return false;
        }
  
@@@ -231,12 -225,10 +225,10 @@@ void close_device(void) 
  }
  
  bool read_packet(vpn_packet_t *packet) {
 -      int lenin;
 +      int inlen;
  
-       cp();
 -      if((lenin = read(sp[0], packet->data, MTU)) <= 0) {
 +      if((inlen = read(sp[0], packet->data, MTU)) <= 0) {
-               logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
+               logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
                           device, strerror(errno));
                return false;
        }
  }
  
  bool write_packet(vpn_packet_t *packet) {
 -      long lenout;
 +      long outlen;
  
-       cp();
-       ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
+       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
                           packet->len, device_info);
  
 -      if(!WriteFile (device_handle, packet->data, packet->len, &lenout, NULL)) {
 +      if(!WriteFile (device_handle, packet->data, packet->len, &outlen, NULL)) {
-               logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info, device, winerror(GetLastError()));
+               logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
                return false;
        }
  
diff --cc src/edge.c
@@@ -53,27 -51,19 +51,19 @@@ static int edge_weight_compare(const ed
  }
  
  void init_edges(void) {
-       cp();
 -      edge_weight_tree = avl_alloc_tree((avl_compare_t) edge_weight_compare, NULL);
 +      edge_weight_tree = splay_alloc_tree((splay_compare_t) edge_weight_compare, NULL);
  }
  
 -avl_tree_t *new_edge_tree(void) {
 -      return avl_alloc_tree((avl_compare_t) edge_compare, (avl_action_t) free_edge);
 +splay_tree_t *new_edge_tree(void) {
-       cp();
 +      return splay_alloc_tree((splay_compare_t) edge_compare, (splay_action_t) free_edge);
  }
  
 -void free_edge_tree(avl_tree_t *edge_tree) {
 -      avl_delete_tree(edge_tree);
 +void free_edge_tree(splay_tree_t *edge_tree) {
-       cp();
 +      splay_delete_tree(edge_tree);
  }
  
  void exit_edges(void) {
-       cp();
 -      avl_delete_tree(edge_weight_tree);
 +      splay_delete_tree(edge_weight_tree);
  }
  
  /* Creation and deletion of connection elements */
@@@ -93,10 -79,8 +79,8 @@@ void free_edge(edge_t *e) 
  }
  
  void edge_add(edge_t *e) {
-       cp();
 -      avl_insert(edge_weight_tree, e);
 -      avl_insert(e->from->edge_tree, e);
 +      splay_insert(edge_weight_tree, e);
 +      splay_insert(e->from->edge_tree, e);
  
        e->reverse = lookup_edge(e->to, e->from);
  
@@@ -131,20 -111,15 +111,18 @@@ int dump_edges(struct evbuffer *out) 
        edge_t *e;
        char *address;
  
-       cp();
 -      logger(LOG_DEBUG, "Edges:");
--
        for(node = node_tree->head; node; node = node->next) {
                n = node->data;
                for(node2 = n->edge_tree->head; node2; node2 = node2->next) {
                        e = node2->data;
                        address = sockaddr2hostname(&e->address);
 -                      logger(LOG_DEBUG, " %s to %s at %s options %lx weight %d",
 -                                 e->from->name, e->to->name, address, e->options, e->weight);
 +                      if(evbuffer_add_printf(out,
-                                                                  _(" %s to %s at %s options %lx weight %d\n"),
++                                                                 " %s to %s at %s options %lx weight %d\n",
 +                                                                 e->from->name, e->to->name, address,
 +                                                                 e->options, e->weight) == -1) {
 +                              free(address);
 +                              return errno;
 +                      }
                        free(address);
                }
        }
diff --cc src/edge.h
Simple merge
diff --cc src/graph.c
@@@ -69,9 -69,10 +67,7 @@@ void mst_kruskal(void) 
        edge_t *e;
        node_t *n;
        connection_t *c;
 -      int nodes = 0;
 -      int safe_edges = 0;
 -      bool skipped;
  
-       cp();
-       
        /* Clear MST status on connections */
  
        for(node = connection_tree->head; node; node = node->next) {
                if(e->reverse->connection)
                        e->reverse->connection->status.mst = true;
  
 -              safe_edges++;
 -
                ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name,
                                   e->to->name, e->weight);
 +      }
 +}
  
 -              if(skipped) {
 -                      skipped = false;
 -                      next = edge_weight_tree->head;
 -                      continue;
 +/* Implementation of Dijkstra's algorithm.
 +   Running time: O(N^2)
 +*/
 +
 +void sssp_dijkstra(void) {
 +      splay_node_t *node, *to;
 +      edge_t *e;
 +      node_t *n, *m;
 +      list_t *todo_list;
 +      list_node_t *lnode, *nnode;
 +      bool indirect;
 +
-       cp();
 +      todo_list = list_alloc(NULL);
 +
 +      ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Dijkstra's algorithm:");
 +
 +      /* Clear visited status on nodes */
 +
 +      for(node = node_tree->head; node; node = node->next) {
 +              n = node->data;
 +              n->status.visited = false;
 +              n->status.indirect = true;
 +              n->distance = -1;
 +      }
 +
 +      /* Begin with myself */
 +
 +      myself->status.indirect = false;
 +      myself->nexthop = myself;
 +      myself->via = myself;
 +      myself->distance = 0;
 +      list_insert_head(todo_list, myself);
 +
 +      /* Loop while todo_list is filled */
 +
 +      while(todo_list->head) {
 +              n = NULL;
 +              nnode = NULL;
 +
 +              /* Select node from todo_list with smallest distance */
 +
 +              for(lnode = todo_list->head; lnode; lnode = lnode->next) {
 +                      m = lnode->data;
 +                      if(!n || m->status.indirect < n->status.indirect || m->distance < n->distance) {
 +                              n = m;
 +                              nnode = lnode;
 +                      }
 +              }
 +
 +              /* Mark this node as visited and remove it from the todo_list */
 +
 +              n->status.visited = true;
 +              list_unlink_node(todo_list, nnode);
 +
 +              /* Update distance of neighbours and add them to the todo_list */
 +
 +              for(to = n->edge_tree->head; to; to = to->next) {       /* "to" is the edge connected to "from" */
 +                      e = to->data;
 +
 +                      if(e->to->status.visited || !e->reverse)
 +                              continue;
 +
 +                      /* Situation:
 +
 +                                 /
 +                                /
 +                         ----->(n)---e-->(e->to)
 +                                \
 +                                 \
 +
 +                         Where e is an edge, (n) and (e->to) are nodes.
 +                         n->address is set to the e->address of the edge left of n to n.
 +                         We are currently examining the edge e right of n from n:
 +
 +                         - If e->reverse->address != n->address, then e->to is probably
 +                           not reachable for the nodes left of n. We do as if the indirectdata
 +                           flag is set on edge e.
 +                         - If edge e provides for better reachability of e->to, update e->to.
 +                       */
 +
 +                      if(e->to->distance < 0)
 +                              list_insert_tail(todo_list, e->to);
 +
 +                      indirect = n->status.indirect || e->options & OPTION_INDIRECT || ((n != myself) && sockaddrcmp(&n->address, &e->reverse->address));
 +
 +                      if(e->to->distance >= 0 && (!e->to->status.indirect || indirect) && e->to->distance <= n->distance + e->weight)
 +                              continue;
 +
 +                      e->to->distance = n->distance + e->weight;
 +                      e->to->status.indirect = indirect;
 +                      e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
 +                      e->to->via = indirect ? n->via : e->to;
 +                      e->to->options = e->options;
 +
 +                      if(sockaddrcmp(&e->to->address, &e->address)) {
 +                              node = splay_unlink(node_udp_tree, e->to);
 +                              sockaddrfree(&e->to->address);
 +                              sockaddrcpy(&e->to->address, &e->address);
 +
 +                              if(e->to->hostname)
 +                                      free(e->to->hostname);
 +
 +                              e->to->hostname = sockaddr2hostname(&e->to->address);
 +
 +                              if(node)
 +                                      splay_insert_node(node_udp_tree, node);
 +
 +                              if(e->to->options & OPTION_PMTU_DISCOVERY) {
 +                                      e->to->mtuprobes = 0;
 +                                      e->to->minmtu = 0;
 +                                      e->to->maxmtu = MTU;
 +                                      if(e->to->status.validkey)
 +                                              send_mtu_probe(e->to);
 +                              }
 +                      }
 +
 +                      ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Updating edge %s - %s weight %d distance %d", e->from->name,
 +                                         e->to->name, e->weight, e->to->distance);
                }
        }
  
@@@ -248,9 -152,11 +242,7 @@@ void sssp_bfs(void) 
        list_t *todo_list;
        list_node_t *from, *todonext;
        bool indirect;
 -      char *name;
 -      char *address, *port;
 -      char *envp[7];
 -      int i;
  
-       cp();
        todo_list = list_alloc(NULL);
  
        /* Clear visited status on nodes */
diff --cc src/graph.h
Simple merge
@@@ -127,38 -121,36 +121,36 @@@ void close_device(void) 
  }
  
  bool read_packet(vpn_packet_t *packet) {
 -      int lenin;
 +      int inlen;
        
-       cp();
        switch(device_type) {
                case DEVICE_TYPE_TUN:
 -                      lenin = read(device_fd, packet->data + 10, MTU - 10);
 +                      inlen = read(device_fd, packet->data + 10, MTU - 10);
  
 -                      if(lenin <= 0) {
 +                      if(inlen <= 0) {
-                               logger(LOG_ERR, _("Error while reading from %s %s: %s"),
+                               logger(LOG_ERR, "Error while reading from %s %s: %s",
                                           device_info, device, strerror(errno));
                                return false;
                        }
  
 -                      packet->len = lenin + 10;
 +                      packet->len = inlen + 10;
                        break;
                case DEVICE_TYPE_TAP:
 -                      lenin = read(device_fd, packet->data, MTU);
 +                      inlen = read(device_fd, packet->data, MTU);
  
 -                      if(lenin <= 0) {
 +                      if(inlen <= 0) {
-                               logger(LOG_ERR, _("Error while reading from %s %s: %s"),
+                               logger(LOG_ERR, "Error while reading from %s %s: %s",
                                           device_info, device, strerror(errno));
                                return false;
                        }
  
 -                      packet->len = lenin;
 +                      packet->len = inlen;
                        break;
                case DEVICE_TYPE_ETHERTAP:
 -                      lenin = read(device_fd, packet->data - 2, MTU + 2);
 +                      inlen = read(device_fd, packet->data - 2, MTU + 2);
  
 -                      if(lenin <= 0) {
 +                      if(inlen <= 0) {
-                               logger(LOG_ERR, _("Error while reading from %s %s: %s"),
+                               logger(LOG_ERR, "Error while reading from %s %s: %s",
                                           device_info, device, strerror(errno));
                                return false;
                        }
diff --cc src/logger.c
Simple merge
diff --cc src/meta.c
  #include "xalloc.h"
  
  bool send_meta(connection_t *c, const char *buffer, int length) {
-       cp();
 -      int outlen;
 -      int result;
--
        if(!c) {
-               logger(LOG_ERR, _("send_meta() called with NULL pointer!"));
+               logger(LOG_ERR, "send_meta() called with NULL pointer!");
                abort();
        }
  
-       ifdebug(META) logger(LOG_DEBUG, _("Sending %d bytes of metadata to %s (%s)"), length,
+       ifdebug(META) logger(LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length,
                           c->name, c->hostname);
  
 -      if(!c->outbuflen)
 -              c->last_flushed_time = now;
 -
 -      /* Find room in connection's buffer */
 -      if(length + c->outbuflen > c->outbufsize) {
 -              c->outbufsize = length + c->outbuflen;
 -              c->outbuf = xrealloc(c->outbuf, c->outbufsize);
 -      }
 -
 -      if(length + c->outbuflen + c->outbufstart > c->outbufsize) {
 -              memmove(c->outbuf, c->outbuf + c->outbufstart, c->outbuflen);
 -              c->outbufstart = 0;
 -      }
 -
        /* Add our data to buffer */
        if(c->status.encryptout) {
 -              result = EVP_EncryptUpdate(c->outctx, (unsigned char *)c->outbuf + c->outbufstart + c->outbuflen,
 -                              &outlen, (unsigned char *)buffer, length);
 -              if(!result || outlen < length) {
 -                      logger(LOG_ERR, "Error while encrypting metadata to %s (%s): %s",
 -                                      c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
 -                      return false;
 -              } else if(outlen > length) {
 -                      logger(LOG_EMERG, "Encrypted data too long! Heap corrupted!");
 -                      abort();
 -              }
 -              c->outbuflen += outlen;
 -      } else {
 -              memcpy(c->outbuf + c->outbufstart + c->outbuflen, buffer, length);
 -              c->outbuflen += length;
 -      }
 -
 -      return true;
 -}
 -
 -bool flush_meta(connection_t *c) {
 -      int result;
 -      
 -      ifdebug(META) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s)",
 -                       c->outbuflen, c->name, c->hostname);
 -
 -      while(c->outbuflen) {
 -              result = send(c->socket, c->outbuf + c->outbufstart, c->outbuflen, 0);
 -              if(result <= 0) {
 -                      if(!errno || errno == EPIPE) {
 -                              ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
 -                                                 c->name, c->hostname);
 -                      } else if(errno == EINTR) {
 -                              continue;
 -#ifdef EWOULDBLOCK
 -                      } else if(errno == EWOULDBLOCK) {
 -                              ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s) would block",
 -                                              c->outbuflen, c->name, c->hostname);
 -                              return true;
 -#endif
 -                      } else {
 -                              logger(LOG_ERR, "Flushing meta data to %s (%s) failed: %s", c->name,
 -                                         c->hostname, strerror(errno));
 -                      }
 +              char outbuf[length];
 +              size_t outlen = length;
  
-                       logger(LOG_ERR, _("Error while encrypting metadata to %s (%s)"),
 +              if(!cipher_encrypt(&c->outcipher, buffer, length, outbuf, &outlen, false) || outlen != length) {
++                      logger(LOG_ERR, "Error while encrypting metadata to %s (%s)",
 +                                      c->name, c->hostname);
                        return false;
                }
 -
 -              c->outbufstart += result;
 -              c->outbuflen -= result;
 +              
-               ifdebug(META) logger(LOG_DEBUG, _("Encrypted write %p %p %p %d"), c, c->buffer, outbuf, length);
++              ifdebug(META) logger(LOG_DEBUG, "Encrypted write %p %p %p %d", c, c->buffer, outbuf, length);
 +              bufferevent_write(c->buffer, (void *)outbuf, length);
-               ifdebug(META) logger(LOG_DEBUG, _("Done."));
++              ifdebug(META) logger(LOG_DEBUG, "Done.");
 +      } else {
-               ifdebug(META) logger(LOG_DEBUG, _("Unencrypted write %p %p %p %d"), c, c->buffer, buffer, length);
++              ifdebug(META) logger(LOG_DEBUG, "Unencrypted write %p %p %p %d", c, c->buffer, buffer, length);
 +              bufferevent_write(c->buffer, (void *)buffer, length);
-               ifdebug(META) logger(LOG_DEBUG, _("Done."));
++              ifdebug(META) logger(LOG_DEBUG, "Done.");
        }
  
 -      c->outbufstart = 0; /* avoid unnecessary memmoves */
        return true;
  }
  
  void broadcast_meta(connection_t *from, const char *buffer, int length) {
 -      avl_node_t *node;
 +      splay_node_t *node;
        connection_t *c;
  
-       cp();
        for(node = connection_tree->head; node; node = node->next) {
                c = node->data;
  
  }
  
  bool receive_meta(connection_t *c) {
 -      int oldlen, i, result;
 -      int lenin, lenout, reqlen;
 -      bool decrypted = false;
 +      size_t inlen;
        char inbuf[MAXBUFSIZE];
 +      char *bufp = inbuf, *endp;
  
-       cp();
        /* Strategy:
           - Read as much as possible from the TCP socket in one go.
           - Decrypt it.
           - If not, keep stuff in buffer and exit.
         */
  
 -      lenin = recv(c->socket, c->buffer + c->buflen, MAXBUFSIZE - c->buflen, 0);
 -
 -      if(lenin <= 0) {
 -              if(!lenin || !errno) {
 -                      ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
 -                                         c->name, c->hostname);
 -              } else if(errno == EINTR)
 -                      return true;
 -              else
 -                      logger(LOG_ERR, "Metadata socket read error for %s (%s): %s",
 -                                 c->name, c->hostname, strerror(errno));
 +      inlen = recv(c->socket, inbuf, sizeof inbuf, 0);
  
-               logger(LOG_ERR, _("Receive callback called for %s (%s) but no data to receive: %s"), c->name, c->hostname, strerror(errno));
 +      if(inlen <= 0) {
++              logger(LOG_ERR, "Receive callback called for %s (%s) but no data to receive: %s", c->name, c->hostname, strerror(errno));
                return false;
        }
  
 -      oldlen = c->buflen;
 -      c->buflen += lenin;
 +      do {
 +              if(!c->status.decryptin) {
 +                      endp = memchr(bufp, '\n', inlen);
 +                      if(endp)
 +                              endp++;
 +                      else
 +                              endp = bufp + inlen;
  
 -      while(lenin > 0) {
 -              /* Decrypt */
 +                      evbuffer_add(c->buffer->input, bufp, endp - bufp);
  
 -              if(c->status.decryptin && !decrypted) {
 -                      result = EVP_DecryptUpdate(c->inctx, (unsigned char *)inbuf, &lenout, (unsigned char *)c->buffer + oldlen, lenin);
 -                      if(!result || lenout != lenin) {
 -                              logger(LOG_ERR, "Error while decrypting metadata from %s (%s): %s",
 -                                              c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
 +                      inlen -= endp - bufp;
 +                      bufp = endp;
 +              } else {
 +                      size_t outlen = inlen;
-                       ifdebug(META) logger(LOG_DEBUG, _("Received encrypted %zu bytes"), inlen);
++                      ifdebug(META) logger(LOG_DEBUG, "Received encrypted %zu bytes", inlen);
 +                      evbuffer_expand(c->buffer->input, c->buffer->input->off + inlen);
 +
 +                      if(!cipher_decrypt(&c->incipher, bufp, inlen, c->buffer->input->buffer + c->buffer->input->off, &outlen, false) || inlen != outlen) {
-                               logger(LOG_ERR, _("Error while decrypting metadata from %s (%s)"),
++                              logger(LOG_ERR, "Error while decrypting metadata from %s (%s)",
 +                                         c->name, c->hostname);
                                return false;
                        }
 -                      memcpy(c->buffer + oldlen, inbuf, lenin);
 -                      decrypted = true;
 +                      c->buffer->input->off += inlen;
 +
 +                      inlen = 0;
                }
  
 -              /* Are we receiving a TCPpacket? */
 +              while(c->buffer->input->off) {
 +                      /* Are we receiving a TCPpacket? */
 +
 +                      if(c->tcplen) {
 +                              if(c->tcplen <= c->buffer->input->off) {
 +                                      receive_tcppacket(c, (char *)c->buffer->input->buffer, c->tcplen);
 +                                      evbuffer_drain(c->buffer->input, c->tcplen);
 +                                      c->tcplen = 0;
 +                                      continue;
 +                              } else {
 +                                      break;
 +                              }
 +                      }
  
 -              if(c->tcplen) {
 -                      if(c->tcplen <= c->buflen) {
 -                              receive_tcppacket(c, c->buffer, c->tcplen);
 +                      /* Otherwise we are waiting for a request */
  
 -                              c->buflen -= c->tcplen;
 -                              lenin -= c->tcplen - oldlen;
 -                              memmove(c->buffer, c->buffer + c->tcplen, c->buflen);
 -                              oldlen = 0;
 -                              c->tcplen = 0;
 +                      char *request = evbuffer_readline(c->buffer->input);
 +                      if(request) {
 +                              bool result = receive_request(c, request);
 +                              free(request);
 +                              if(!result)
 +                                      return false;
                                continue;
                        } else {
                                break;
diff --cc src/meta.h
Simple merge
@@@ -191,8 -187,8 +187,8 @@@ bool setup_device(void) 
  
        /* Get MAC address from tap device */
  
 -      if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
 +      if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) {
-               logger(LOG_ERR, _("Could not get MAC address from Windows tap device %s (%s): %s"), device, iface, winerror(GetLastError()));
+               logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
                return false;
        }
  
        /* Set media status for newer TAP-Win32 devices */
  
        status = true;
 -      DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL);
 +      DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof status, &status, sizeof status, &len, NULL);
  
-       device_info = _("Windows tap device");
+       device_info = "Windows tap device";
  
-       logger(LOG_INFO, _("%s (%s) is a %s"), device, iface, device_info);
+       logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
  
        return true;
  }
@@@ -235,16 -229,14 +229,14 @@@ bool read_packet(vpn_packet_t *packet) 
  }
  
  bool write_packet(vpn_packet_t *packet) {
 -      long lenout;
 +      long outlen;
        OVERLAPPED overlapped = {0};
  
-       cp();
-       ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Writing packet of %d bytes to %s"),
+       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
                           packet->len, device_info);
  
 -      if(!WriteFile(device_handle, packet->data, packet->len, &lenout, &overlapped)) {
 +      if(!WriteFile(device_handle, packet->data, packet->len, &outlen, &overlapped)) {
-               logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info, device, winerror(GetLastError()));
+               logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
                return false;
        }
  
diff --cc src/net.c
+++ b/src/net.c
@@@ -108,11 -158,13 +105,9 @@@ void purge(void) 
    - Deactivate the host
  */
  void terminate_connection(connection_t *c, bool report) {
-       cp();
 -      if(c->status.remove)
 -              return;
--
-       ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Closing connection with %s (%s)"),
+       ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Closing connection with %s (%s)",
                           c->name, c->hostname);
  
 -      c->status.remove = true;
        c->status.active = false;
  
        if(c->node)
    end does not reply in time, we consider them dead
    and close the connection.
  */
 -static void check_dead_connections(void) {
 -      avl_node_t *node, *next;
 +static void timeout_handler(int fd, short events, void *event) {
 +      splay_node_t *node, *next;
        connection_t *c;
 +      time_t now = time(NULL);
  
-       cp();
        for(node = connection_tree->head; node; node = next) {
                next = node->next;
                c = node->data;
                if(c->last_ping_time + pingtimeout < now) {
                        if(c->status.active) {
                                if(c->status.pinged) {
-                                       ifdebug(CONNECTIONS) logger(LOG_INFO, _("%s (%s) didn't respond to PING in %ld seconds"),
+                                       ifdebug(CONNECTIONS) logger(LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds",
                                                           c->name, c->hostname, now - c->last_ping_time);
 -                                      c->status.timeout = true;
                                        terminate_connection(c, true);
 +                                      continue;
                                } else if(c->last_ping_time + pinginterval < now) {
                                        send_ping(c);
                                }
                        } else {
 -                              if(c->status.remove) {
 -                                      logger(LOG_WARNING, "Old connection_t for %s (%s) status %04x still lingering, deleting...",
 -                                                 c->name, c->hostname, bitfield_to_int(&c->status, sizeof c->status));
 -                                      connection_del(c);
 -                                      continue;
 -                              }
 -                              ifdebug(CONNECTIONS) logger(LOG_WARNING, "Timeout from %s (%s) during authentication",
 -                                                 c->name, c->hostname);
                                if(c->status.connecting) {
-                                               logger(LOG_WARNING, _("Timeout while connecting to %s (%s)"), c->name, c->hostname);
 +                                      ifdebug(CONNECTIONS)
++                                              logger(LOG_WARNING, "Timeout while connecting to %s (%s)", c->name, c->hostname);
                                        c->status.connecting = false;
                                        closesocket(c->socket);
                                        do_outgoing_connection(c);
                                } else {
-                                       ifdebug(CONNECTIONS) logger(LOG_WARNING, _("Timeout from %s (%s) during authentication"), c->name, c->hostname);
++                                      ifdebug(CONNECTIONS) logger(LOG_WARNING, "Timeout from %s (%s) during authentication", c->name, c->hostname);
                                        terminate_connection(c, false);
 +                                      continue;
                                }
                        }
                }
 -
 -              if(c->outbuflen > 0 && c->last_flushed_time + pingtimeout < now) {
 -                      if(c->status.active) {
 -                              ifdebug(CONNECTIONS) logger(LOG_INFO,
 -                                              "%s (%s) could not flush for %ld seconds (%d bytes remaining)",
 -                                              c->name, c->hostname, now - c->last_flushed_time, c->outbuflen);
 -                              c->status.timeout = true;
 -                              terminate_connection(c, true);
 -                      }
 -              }
 -      }
 -}
 -
 -/*
 -  check all connections to see if anything
 -  happened on their sockets
 -*/
 -static void check_network_activity(fd_set * readset, fd_set * writeset) {
 -      connection_t *c;
 -      avl_node_t *node;
 -      int result, i;
 -      socklen_t len = sizeof(result);
 -      vpn_packet_t packet;
 -
 -      /* check input from kernel */
 -      if(device_fd >= 0 && FD_ISSET(device_fd, readset)) {
 -              if(read_packet(&packet)) {
 -                      packet.priority = 0;
 -                      route(myself, &packet);
 -              }
        }
  
 -      /* check meta connections */
 -      for(node = connection_tree->head; node; node = node->next) {
 -              c = node->data;
 -
 -              if(c->status.remove)
 -                      continue;
 -
 -              if(FD_ISSET(c->socket, readset)) {
 -                      if(c->status.connecting) {
 -                              c->status.connecting = false;
 -                              getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len);
 -
 -                              if(!result)
 -                                      finish_connecting(c);
 -                              else {
 -                                      ifdebug(CONNECTIONS) logger(LOG_DEBUG,
 -                                                         "Error while connecting to %s (%s): %s",
 -                                                         c->name, c->hostname, strerror(result));
 -                                      closesocket(c->socket);
 -                                      do_outgoing_connection(c);
 -                                      continue;
 -                              }
 -                      }
 -
 -                      if(!receive_meta(c)) {
 -                              terminate_connection(c, c->status.active);
 -                              continue;
 -                      }
 -              }
 +      event_add(event, &(struct timeval){pingtimeout, 0});
 +}
  
 -              if(FD_ISSET(c->socket, writeset)) {
 -                      if(!flush_meta(c)) {
 -                              terminate_connection(c, c->status.active);
 -                              continue;
 -                      }
 +void handle_meta_connection_data(int fd, short events, void *data) {
 +      connection_t *c = data;
 +      int result;
 +      socklen_t len = sizeof result;
 +
 +      if(c->status.connecting) {
 +              c->status.connecting = false;
 +
 +              getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len);
 +
 +              if(!result)
 +                      finish_connecting(c);
 +              else {
 +                      ifdebug(CONNECTIONS) logger(LOG_DEBUG,
-                                          _("Error while connecting to %s (%s): %s"),
++                                         "Error while connecting to %s (%s): %s",
 +                                         c->name, c->hostname, strerror(result));
 +                      closesocket(c->socket);
 +                      do_outgoing_connection(c);
 +                      return;
                }
        }
  
        }
  }
  
 -/*
 -  this is where it all happens...
 -*/
 -int main_loop(void) {
 -      fd_set readset, writeset;
 -      struct timeval tv;
 -      int r, maxfd;
 -      time_t last_ping_check, last_config_check, last_graph_dump;
 -      event_t *event;
 -
 -      last_ping_check = now;
 -      last_config_check = now;
 -      last_graph_dump = now;
 -      
 -      srand(now);
 -
 -      running = true;
 -
 -      while(running) {
 -              now = time(NULL);
 -
 -      //      tv.tv_sec = 1 + (rand() & 7);   /* Approx. 5 seconds, randomized to prevent global synchronisation effects */
 -              tv.tv_sec = 1;
 -              tv.tv_usec = 0;
 -
 -              maxfd = build_fdset(&readset, &writeset);
 -
 -#ifdef HAVE_MINGW
 -              LeaveCriticalSection(&mutex);
 -#endif
 -              r = select(maxfd + 1, &readset, &writeset, NULL, &tv);
 -#ifdef HAVE_MINGW
 -              EnterCriticalSection(&mutex);
 -#endif
 -
 -              if(r < 0) {
 -                      if(errno != EINTR && errno != EAGAIN) {
 -                              logger(LOG_ERR, "Error while waiting for input: %s",
 -                                         strerror(errno));
 -                              dump_connections();
 -                              return 1;
 -                      }
 -
 -                      continue;
 -              }
 -
 -              check_network_activity(&readset, &writeset);
 -
 -              if(do_purge) {
 -                      purge();
 -                      do_purge = false;
 -              }
 -
 -              /* Let's check if everybody is still alive */
 -
 -              if(last_ping_check + pingtimeout < now) {
 -                      check_dead_connections();
 -                      last_ping_check = now;
 -
 -                      if(routing_mode == RMODE_SWITCH)
 -                              age_subnets();
 -
 -                      age_past_requests();
 +static void sigterm_handler(int signal, short events, void *data) {
-       logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
++      logger(LOG_NOTICE, "Got %s signal", strsignal(signal));
 +      event_loopexit(NULL);
 +}
  
 -                      /* Should we regenerate our key? */
 +static void sighup_handler(int signal, short events, void *data) {
-       logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal));
++      logger(LOG_NOTICE, "Got %s signal", strsignal(signal));
 +      reload_configuration();
 +}
  
 -                      if(keyexpires < now) {
 -                              avl_node_t *node;
 -                              node_t *n;
 +int reload_configuration(void) {
 +      connection_t *c;
 +      splay_node_t *node, *next;
 +      char *fname;
 +      struct stat s;
 +      static time_t last_config_check = 0;
  
 -                              ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys");
 +      /* Reread our own configuration file */
  
 -                              for(node = node_tree->head; node; node = node->next) {
 -                                      n = node->data;
 -                                      if(n->inkey) {
 -                                              free(n->inkey);
 -                                              n->inkey = NULL;
 -                                      }
 -                              }
 +      exit_configuration(&config_tree);
 +      init_configuration(&config_tree);
  
 -                              send_key_changed(broadcast, myself);
 -                              keyexpires = now + keylifetime;
 -                      }
 -              }
 +      if(!read_server_config()) {
-               logger(LOG_ERR, _("Unable to reread configuration file, exitting."));
++              logger(LOG_ERR, "Unable to reread configuration file, exitting.");
 +              event_loopexit(NULL);
 +              return EINVAL;
 +      }
  
 -              if(sigalrm) {
 -                      logger(LOG_INFO, "Flushing event queue");
 -                      expire_events();
 -                      sigalrm = false;
 +      /* Close connections to hosts that have a changed or deleted host config file */
 +      
 +      for(node = connection_tree->head; node; node = next) {
 +              c = node->data;
 +              next = node->next;
 +              
 +              if(c->outgoing) {
 +                      free(c->outgoing->name);
 +                      if(c->outgoing->ai)
 +                              freeaddrinfo(c->outgoing->ai);
 +                      free(c->outgoing);
 +                      c->outgoing = NULL;
                }
 +              
 +              xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
 +              if(stat(fname, &s) || s.st_mtime > last_config_check)
 +                      terminate_connection(c, c->status.active);
 +              free(fname);
 +      }
  
 -              while((event = get_expired_event())) {
 -                      event->handler(event->data);
 -                      free_event(event);
 -              }
 +      last_config_check = time(NULL);
  
 -              if(sighup) {
 -                      connection_t *c;
 -                      avl_node_t *node;
 -                      char *fname;
 -                      struct stat s;
 -                      
 -                      sighup = false;
 -                      
 -                      /* Reread our own configuration file */
 -
 -                      exit_configuration(&config_tree);
 -                      init_configuration(&config_tree);
 -
 -                      if(!read_server_config()) {
 -                              logger(LOG_ERR, "Unable to reread configuration file, exitting.");
 -                              return 1;
 -                      }
 +      /* Try to make outgoing connections */
 +      
 +      try_outgoing_connections();
  
 -                      /* Close connections to hosts that have a changed or deleted host config file */
 -                      
 -                      for(node = connection_tree->head; node; node = node->next) {
 -                              c = node->data;
 -                              
 -                              xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
 -                              if(stat(fname, &s) || s.st_mtime > last_config_check)
 -                                      terminate_connection(c, c->status.active);
 -                              free(fname);
 -                      }
 +      return 0;
 +}
  
 -                      last_config_check = now;
 +void retry(void) {
 +      connection_t *c;
 +      splay_node_t *node;
  
 -                      /* Try to make outgoing connections */
 -                      
 -                      try_outgoing_connections();
 -              }
 +      for(node = connection_tree->head; node; node = node->next) {
 +              c = node->data;
                
 -              /* Dump graph if wanted every 60 seconds*/
 -
 -              if(last_graph_dump + 60 < now) {
 -                      dump_graph();
 -                      last_graph_dump = now;
 +              if(c->outgoing && !c->node) {
 +                      if(timeout_initialized(&c->outgoing->ev))
 +                              event_del(&c->outgoing->ev);
 +                      if(c->status.connecting)
 +                              close(c->socket);
 +                      c->outgoing->timeout = 0;
 +                      do_outgoing_connection(c);
                }
        }
-       cp();
 +}
 +
 +/*
 +  this is where it all happens...
 +*/
 +int main_loop(void) {
 +      struct event timeout_event;
 +      struct event sighup_event;
 +      struct event sigterm_event;
 +      struct event sigquit_event;
 +
-               logger(LOG_ERR, _("Error while waiting for input: %s"), strerror(errno));
 +      timeout_set(&timeout_event, timeout_handler, &timeout_event);
 +      event_add(&timeout_event, &(struct timeval){pingtimeout, 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);
 +
 +      if(event_loop(0) < 0) {
++              logger(LOG_ERR, "Error while waiting for input: %s", strerror(errno));
 +              return 1;
 +      }
 +
 +      signal_del(&sighup_event);
 +      signal_del(&sigterm_event);
 +      signal_del(&sigquit_event);
 +      event_del(&timeout_event);
  
        return 0;
  }
diff --cc src/net.h
Simple merge
@@@ -61,12 -62,11 +59,10 @@@ static void send_mtu_probe_handler(int 
        vpn_packet_t packet;
        int len, i;
        
-       cp();
        n->mtuprobes++;
 -      n->mtuevent = NULL;
  
        if(!n->status.reachable) {
-               logger(LOG_DEBUG, _("Trying to send MTU probe to unreachable node %s (%s)"), n->name, n->hostname);
+               logger(LOG_DEBUG, "Trying to send MTU probe to unreachable node %s (%s)", n->name, n->hostname);
                return;
        }
  
@@@ -166,54 -162,65 +160,50 @@@ static void receive_packet(node_t *n, v
        route(n, packet);
  }
  
- static bool try_mac(node_t *n, const vpn_packet_t *inpkt)
- {
 -static bool try_mac(const node_t *n, const vpn_packet_t *inpkt) {
 -      unsigned char hmac[EVP_MAX_MD_SIZE];
 -
 -      if(!n->indigest || !n->inmaclength || !n->inkey || inpkt->len < sizeof inpkt->seqno + n->inmaclength)
++static bool try_mac(node_t *n, const vpn_packet_t *inpkt) {
 +      if(!digest_active(&n->indigest) || inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest))
                return false;
  
 -      HMAC(n->indigest, n->inkey, n->inkeylength, (unsigned char *) &inpkt->seqno, inpkt->len - n->inmaclength, (unsigned char *)hmac, NULL);
 -
 -      return !memcmp(hmac, (char *) &inpkt->seqno + inpkt->len - n->inmaclength, n->inmaclength);
 +      return digest_verify(&n->indigest, &inpkt->seqno, inpkt->len, (const char *)&inpkt->seqno + inpkt->len);
  }
  
- static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
- {
+ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
        vpn_packet_t pkt1, pkt2;
        vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
        int nextpkt = 0;
        vpn_packet_t *outpkt = pkt[0];
 -      int outlen, outpad;
 -      unsigned char hmac[EVP_MAX_MD_SIZE];
 +      size_t outlen;
        int i;
  
-       cp();
 -      if(!n->inkey) {
 +      if(!cipher_active(&n->incipher)) {
-               ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got packet from %s (%s) but he hasn't got our key yet"),
+               ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet",
                                        n->name, n->hostname);
                return;
        }
  
        /* Check packet length */
  
 -      if(inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) {
 +      if(inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest)) {
-               ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got too short packet from %s (%s)"),
+               ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got too short packet from %s (%s)",
                                        n->name, n->hostname);
                return;
        }
  
        /* Check the message authentication code */
  
 -      if(n->indigest && n->inmaclength) {
 -              inpkt->len -= n->inmaclength;
 -              HMAC(n->indigest, n->inkey, n->inkeylength,
 -                       (unsigned char *) &inpkt->seqno, inpkt->len, (unsigned char *)hmac, NULL);
 -
 -              if(memcmp(hmac, (char *) &inpkt->seqno + inpkt->len, n->inmaclength)) {
 -                      ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got unauthenticated packet from %s (%s)",
 -                                         n->name, n->hostname);
 -                      return;
 -              }
 +      if(digest_active(&n->indigest) && !digest_verify(&n->indigest, &inpkt->seqno, inpkt->len, (const char *)&inpkt->seqno + inpkt->len)) {
-               ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"), n->name, n->hostname);
++              ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got unauthenticated packet from %s (%s)", n->name, n->hostname);
 +              return;
        }
  
        /* Decrypt the packet */
  
 -      if(n->incipher) {
 +      if(cipher_active(&n->incipher)) {
                outpkt = pkt[nextpkt++];
 +              outlen = MAXSIZE;
  
 -              if(!EVP_DecryptInit_ex(&n->inctx, NULL, NULL, NULL, NULL)
 -                              || !EVP_DecryptUpdate(&n->inctx, (unsigned char *) &outpkt->seqno, &outlen,
 -                                      (unsigned char *) &inpkt->seqno, inpkt->len)
 -                              || !EVP_DecryptFinal_ex(&n->inctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
 -                      ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error decrypting packet from %s (%s): %s",
 -                                              n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
 +              if(!cipher_decrypt(&n->incipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
-                       ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Error decrypting packet from %s (%s)"), n->name, n->hostname);
++                      ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error decrypting packet from %s (%s)", n->name, n->hostname);
                        return;
                }
                
        inpkt->seqno = ntohl(inpkt->seqno);
  
        if(inpkt->seqno != n->received_seqno + 1) {
 -              if(inpkt->seqno >= n->received_seqno + sizeof(n->late) * 8) {
 +              if(inpkt->seqno >= n->received_seqno + sizeof n->late * 8) {
-                       logger(LOG_WARNING, _("Lost %d packets from %s (%s)"),
+                       logger(LOG_WARNING, "Lost %d packets from %s (%s)",
                                           inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
                        
 -                      memset(n->late, 0, sizeof(n->late));
 +                      memset(n->late, 0, sizeof n->late);
                } else if (inpkt->seqno <= n->received_seqno) {
 -                      if((n->received_seqno >= sizeof(n->late) * 8 && inpkt->seqno <= n->received_seqno - sizeof(n->late) * 8) || !(n->late[(inpkt->seqno / 8) % sizeof(n->late)] & (1 << inpkt->seqno % 8))) {
 +                      if((n->received_seqno >= sizeof n->late * 8 && inpkt->seqno <= n->received_seqno - sizeof n->late * 8) || !(n->late[(inpkt->seqno / 8) % sizeof n->late] & (1 << inpkt->seqno % 8))) {
-                               logger(LOG_WARNING, _("Got late or replayed packet from %s (%s), seqno %d, last received %d"),
+                               logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
                                           n->name, n->hostname, inpkt->seqno, n->received_seqno);
                                return;
                        }
@@@ -363,12 -369,15 +349,12 @@@ static void send_udppacket(node_t *n, v
  
        /* Encrypt the packet */
  
 -      if(n->outcipher) {
 +      if(cipher_active(&n->outcipher)) {
                outpkt = pkt[nextpkt++];
 +              outlen = MAXSIZE;
  
 -              if(!EVP_EncryptInit_ex(&n->outctx, NULL, NULL, NULL, NULL)
 -                              || !EVP_EncryptUpdate(&n->outctx, (unsigned char *) &outpkt->seqno, &outlen,
 -                                      (unsigned char *) &inpkt->seqno, inpkt->len)
 -                              || !EVP_EncryptFinal_ex(&n->outctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
 -                      ifdebug(TRAFFIC) logger(LOG_ERR, "Error while encrypting packet to %s (%s): %s",
 -                                              n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
 +              if(!cipher_encrypt(&n->outcipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
-                       ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while encrypting packet to %s (%s)"), n->name, n->hostname);
++                      ifdebug(TRAFFIC) logger(LOG_ERR, "Error while encrypting packet to %s (%s)", n->name, n->hostname);
                        goto end;
                }
  
        if(priorityinheritance && origpriority != priority
           && listen_socket[sock].sa.sa.sa_family == AF_INET) {
                priority = origpriority;
-               ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Setting outgoing packet priority to %d"), priority);
+               ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting outgoing packet priority to %d", priority);
 -              if(setsockopt(listen_socket[sock].udp, SOL_IP, IP_TOS, &priority, sizeof(priority)))    /* SO_PRIORITY doesn't seem to work */
 +              if(setsockopt(listen_socket[sock].udp, SOL_IP, IP_TOS, &priority, sizeof priority))     /* SO_PRIORITY doesn't seem to work */
-                       logger(LOG_ERR, _("System call `%s' failed: %s"), "setsockopt", strerror(errno));
+                       logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
        }
  #endif
  
@@@ -458,12 -466,10 +442,10 @@@ void send_packet(const node_t *n, vpn_p
  /* Broadcast a packet using the minimum spanning tree */
  
  void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
 -      avl_node_t *node;
 +      splay_node_t *node;
        connection_t *c;
  
-       cp();
-       ifdebug(TRAFFIC) logger(LOG_INFO, _("Broadcasting packet of %d bytes from %s (%s)"),
+       ifdebug(TRAFFIC) logger(LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
                           packet->len, from->name, from->hostname);
  
        if(from != myself) {
@@@ -507,16 -513,13 +489,13 @@@ static node_t *try_harder(const sockadd
        return n;
  }
  
- void handle_incoming_vpn_data(int sock, short events, void *data)
- {
 -void handle_incoming_vpn_data(int sock) {
++void handle_incoming_vpn_data(int sock, short events, void *data) {
        vpn_packet_t pkt;
        char *hostname;
        sockaddr_t from;
 -      socklen_t fromlen = sizeof(from);
 +      socklen_t fromlen = sizeof from;
        node_t *n;
  
-       cp();
        pkt.len = recvfrom(sock, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
  
        if(pkt.len < 0) {
diff --cc src/net_setup.c
@@@ -47,61 -48,118 +46,57 @@@ static struct event device_ev
  bool read_rsa_public_key(connection_t *c) {
        FILE *fp;
        char *fname;
 -      char *key;
 -
 -      if(!c->rsa_key) {
 -              c->rsa_key = RSA_new();
 -//            RSA_blinding_on(c->rsa_key, NULL);
 -      }
 +      char *n;
 +      bool result;
  
-       cp();
        /* First, check for simple PublicKey statement */
  
 -      if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &key)) {
 -              BN_hex2bn(&c->rsa_key->n, key);
 -              BN_hex2bn(&c->rsa_key->e, "FFFF");
 -              free(key);
 -              return true;
 +      if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &n)) {
 +              result = rsa_set_hex_public_key(&c->rsa, n, "FFFF");
 +              free(n);
 +              return result;
        }
  
        /* Else, check for PublicKeyFile statement and read it */
  
 -      if(get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname)) {
 -              fp = fopen(fname, "r");
 -
 -              if(!fp) {
 -                      logger(LOG_ERR, "Error reading RSA public key file `%s': %s",
 -                                 fname, strerror(errno));
 -                      free(fname);
 -                      return false;
 -              }
 -
 -              free(fname);
 -              c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL);
 -              fclose(fp);
 -
 -              if(c->rsa_key)
 -                      return true;            /* Woohoo. */
 -
 -              /* If it fails, try PEM_read_RSA_PUBKEY. */
 -              fp = fopen(fname, "r");
 +      if(!get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname))
 +              xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
  
 -              if(!fp) {
 -                      logger(LOG_ERR, "Error reading RSA public key file `%s': %s",
 -                                 fname, strerror(errno));
 -                      free(fname);
 -                      return false;
 -              }
 -
 -              free(fname);
 -              c->rsa_key = PEM_read_RSA_PUBKEY(fp, &c->rsa_key, NULL, NULL);
 -              fclose(fp);
 -
 -              if(c->rsa_key) {
 -//                            RSA_blinding_on(c->rsa_key, NULL);
 -                      return true;
 -              }
 +      fp = fopen(fname, "r");
  
 -              logger(LOG_ERR, "Reading RSA public key file `%s' failed: %s",
 +      if(!fp) {
-               logger(LOG_ERR, _("Error reading RSA public key file `%s': %s"),
++              logger(LOG_ERR, "Error reading RSA public key file `%s': %s",
                           fname, strerror(errno));
 +              free(fname);
                return false;
        }
  
 -      /* Else, check if a harnessed public key is in the config file */
 -
 -      xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
 -      fp = fopen(fname, "r");
 -
 -      if(fp) {
 -              c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL);
 -              fclose(fp);
 -      }
 -
 -      free(fname);
 -
 -      if(c->rsa_key)
 -              return true;
 -
 -      /* Try again with PEM_read_RSA_PUBKEY. */
 -
 -      xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
 -      fp = fopen(fname, "r");
 -
 -      if(fp) {
 -              c->rsa_key = PEM_read_RSA_PUBKEY(fp, &c->rsa_key, NULL, NULL);
 -//            RSA_blinding_on(c->rsa_key, NULL);
 -              fclose(fp);
 -      }
 +      result = rsa_read_pem_public_key(&c->rsa, fp);
 +      fclose(fp);
  
-               logger(LOG_ERR, _("Reading RSA public key file `%s' failed: %s"), fname, strerror(errno));
 +      if(!result) 
++              logger(LOG_ERR, "Reading RSA public key file `%s' failed: %s", fname, strerror(errno));
        free(fname);
 -
 -      if(c->rsa_key)
 -              return true;
 -
 -      logger(LOG_ERR, "No public key for %s specified!", c->name);
 -
 -      return false;
 +      return result;
  }
  
 -bool read_rsa_private_key(void) {
 +bool read_rsa_private_key() {
        FILE *fp;
 -      char *fname, *key, *pubkey;
 -      struct stat s;
 +      char *fname;
 +      char *n, *d;
 +      bool result;
 +
-       cp();
 +      /* First, check for simple PrivateKey statement */
  
 -      if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) {
 -              if(!get_config_string(lookup_config(myself->connection->config_tree, "PublicKey"), &pubkey)) {
 +      if(get_config_string(lookup_config(config_tree, "PrivateKey"), &d)) {
 +              if(!get_config_string(lookup_config(myself->connection->config_tree, "PublicKey"), &n)) {
-                       logger(LOG_ERR, _("PrivateKey used but no PublicKey found!"));
+                       logger(LOG_ERR, "PrivateKey used but no PublicKey found!");
 +                      free(d);
                        return false;
                }
 -              myself->connection->rsa_key = RSA_new();
 -//            RSA_blinding_on(myself->connection->rsa_key, NULL);
 -              BN_hex2bn(&myself->connection->rsa_key->d, key);
 -              BN_hex2bn(&myself->connection->rsa_key->n, pubkey);
 -              BN_hex2bn(&myself->connection->rsa_key->e, "FFFF");
 -              free(key);
 -              free(pubkey);
 +              result = rsa_set_hex_private_key(&myself->connection->rsa, n, "FFFF", d);
 +              free(n);
 +              free(d);
                return true;
        }
  
        }
  
  #if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN)
 +      struct stat s;
 +
        if(fstat(fileno(fp), &s)) {
-               logger(LOG_ERR, _("Could not stat RSA private key file `%s': %s'"), fname, strerror(errno));
 -              logger(LOG_ERR, "Could not stat RSA private key file `%s': %s'",
 -                              fname, strerror(errno));
++              logger(LOG_ERR, "Could not stat RSA private key file `%s': %s'", fname, strerror(errno));
                free(fname);
                return false;
        }
  
        if(s.st_mode & ~0100700)
-               logger(LOG_WARNING, _("Warning: insecure file permissions for RSA private key file `%s'!"), fname);
+               logger(LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname);
  #endif
  
 -      myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
 +      result = rsa_read_pem_private_key(&myself->connection->rsa, fp);
        fclose(fp);
  
 -      if(!myself->connection->rsa_key) {
 -              logger(LOG_ERR, "Reading RSA private key file `%s' failed: %s",
 -                         fname, strerror(errno));
 -              free(fname);
 -              return false;
 +      if(!result) 
-               logger(LOG_ERR, _("Reading RSA private key file `%s' failed: %s"), fname, strerror(errno));
++              logger(LOG_ERR, "Reading RSA private key file `%s' failed: %s", fname, strerror(errno));
 +      free(fname);
 +      return result;
 +}
 +
 +static struct event keyexpire_event;
 +
 +static void keyexpire_handler(int fd, short events, void *data) {
 +      regenerate_key();
 +}
 +
 +void regenerate_key() {
 +      if(timeout_initialized(&keyexpire_event)) {
-               ifdebug(STATUS) logger(LOG_INFO, _("Expiring symmetric keys"));
++              ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys");
 +              event_del(&keyexpire_event);
 +              send_key_changed(broadcast, myself);
 +      } else {
 +              timeout_set(&keyexpire_event, keyexpire_handler, NULL);
        }
  
 -      free(fname);
 -      return true;
 +      event_add(&keyexpire_event, &(struct timeval){keylifetime, 0});
  }
  
  /*
@@@ -299,36 -339,65 +292,36 @@@ bool setup_myself(void) 
  
        /* Generate packet encryption key */
  
 -      if(get_config_string
 -         (lookup_config(myself->connection->config_tree, "Cipher"), &cipher)) {
 -              if(!strcasecmp(cipher, "none")) {
 -                      myself->incipher = NULL;
 -              } else {
 -                      myself->incipher = EVP_get_cipherbyname(cipher);
 -
 -                      if(!myself->incipher) {
 -                              logger(LOG_ERR, "Unrecognized cipher type!");
 -                              return false;
 -                      }
 -              }
 -      } else
 -              myself->incipher = EVP_aes_256_cbc();
 -
 -      if(myself->incipher)
 -              myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len;
 -      else
 -              myself->inkeylength = 1;
 +      if(!get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher))
 +              cipher = xstrdup("aes256");
  
 -      myself->connection->outcipher = EVP_aes_256_ofb();
 +      if(!cipher_open_by_name(&myself->incipher, cipher)) {
-               logger(LOG_ERR, _("Unrecognized cipher type!"));
++              logger(LOG_ERR, "Unrecognized cipher type!");
 +              return false;
 +      }
  
        if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
                keylifetime = 3600;
  
 -      keyexpires = now + keylifetime;
 -      
 +      regenerate_key();
 +
        /* Check if we want to use message authentication codes... */
  
 -      if(get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest)) {
 -              if(!strcasecmp(digest, "none")) {
 -                      myself->indigest = NULL;
 -              } else {
 -                      myself->indigest = EVP_get_digestbyname(digest);
 +      if(!get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest))
 +              digest = xstrdup("sha256");
  
 -                      if(!myself->indigest) {
 -                              logger(LOG_ERR, "Unrecognized digest type!");
 -                              return false;
 -                      }
 -              }
 -      } else
 -              myself->indigest = EVP_sha256();
 -
 -      myself->connection->outdigest = EVP_sha256();
 -
 -      if(get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &myself->inmaclength)) {
 -              if(myself->indigest) {
 -                      if(myself->inmaclength > myself->indigest->md_size) {
 -                              logger(LOG_ERR, "MAC length exceeds size of digest!");
 -                              return false;
 -                      } else if(myself->inmaclength < 0) {
 -                              logger(LOG_ERR, "Bogus MAC length!");
 -                              return false;
 -                      }
 -              }
 -      } else
 -              myself->inmaclength = 4;
 +      int maclength = 4;
 +      get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &maclength);
 +
 +      if(maclength < 0) {
-               logger(LOG_ERR, _("Bogus MAC length!"));
++              logger(LOG_ERR, "Bogus MAC length!");
 +              return false;
 +      }
  
 -      myself->connection->outmaclength = 0;
 +      if(!digest_open_by_name(&myself->indigest, digest, maclength)) {
-               logger(LOG_ERR, _("Unrecognized digest type!"));
++              logger(LOG_ERR, "Unrecognized digest type!");
 +              return false;
 +      }
  
        /* Compression */
  
        if(!setup_device())
                return false;
  
-               logger(LOG_ERR, _("event_add failed: %s"), strerror(errno));
 +      event_set(&device_ev, device_fd, EV_READ|EV_PERSIST, handle_device_data, NULL);
 +
 +      if (event_add(&device_ev, NULL) < 0) {
++              logger(LOG_ERR, "event_add failed: %s", strerror(errno));
 +              close_device();
 +              return false;
 +      }
 +
        /* Run tinc-up script to further initialize the tap interface */
        xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
        xasprintf(&envp[1], "DEVICE=%s", device ? : "");
                listen_socket[listen_sockets].udp =
                        setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
  
 -              if(listen_socket[listen_sockets].udp < 0)
 +              if(listen_socket[listen_sockets].udp < 0) {
 +                      close(listen_socket[listen_sockets].tcp);
                        continue;
-                       logger(LOG_EMERG, _("event_add failed: %s"), strerror(errno));
 +              }
 +
 +              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(LOG_EMERG, _("event_add failed: %s"), strerror(errno));
++                      logger(LOG_EMERG, "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, NULL);
 +              if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
++                      logger(LOG_EMERG, "event_add failed: %s", strerror(errno));
 +                      abort();
 +              }
  
                ifdebug(CONNECTIONS) {
                        hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
  
                memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
                listen_sockets++;
-                       logger(LOG_WARNING, _("Maximum of %d listening sockets reached"), MAXSOCKETS);
 +
 +              if(listen_sockets >= MAXSOCKETS) {
++                      logger(LOG_WARNING, "Maximum of %d listening sockets reached", MAXSOCKETS);
 +                      break;
 +              }
        }
  
        freeaddrinfo(ai);
  /*
    initialize network
  */
- bool setup_network(void)
- {
-       cp();
+ bool setup_network(void) {
 -      now = time(NULL);
 -
 -      init_events();
        init_connections();
        init_subnets();
        init_nodes();
@@@ -200,12 -198,12 +197,12 @@@ int setup_listen_socket(const sockaddr_
  #if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
                struct ifreq ifr;
  
 -              memset(&ifr, 0, sizeof(ifr));
 +              memset(&ifr, 0, sizeof ifr);
                strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
  
 -              if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) {
 +              if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof ifr)) {
                        closesocket(nfd);
-                       logger(LOG_ERR, _("Can't bind to interface %s: %s"), iface,
+                       logger(LOG_ERR, "Can't bind to interface %s: %s", iface,
                                   strerror(errno));
                        return -1;
                }
@@@ -309,23 -305,22 +304,21 @@@ int setup_vpn_in_socket(const sockaddr_
        return nfd;
  } /* int setup_vpn_in_socket */
  
 -void retry_outgoing(outgoing_t *outgoing) {
 -      event_t *event;
 +static void retry_outgoing_handler(int fd, short events, void *data) {
 +      setup_outgoing_connection(data);
 +}
  
-       cp();
 +void retry_outgoing(outgoing_t *outgoing) {
        outgoing->timeout += 5;
  
        if(outgoing->timeout > maxtimeout)
                outgoing->timeout = maxtimeout;
  
 -      event = new_event();
 -      event->handler = (event_handler_t) setup_outgoing_connection;
 -      event->time = now + outgoing->timeout;
 -      event->data = outgoing;
 -      event_add(event);
 +      timeout_set(&outgoing->ev, retry_outgoing_handler, outgoing);
 +      event_add(&outgoing->ev, &(struct timeval){outgoing->timeout, 0});
  
        ifdebug(CONNECTIONS) logger(LOG_NOTICE,
-                          _("Trying to re-establish outgoing connection in %d seconds"),
+                          "Trying to re-establish outgoing connection in %d seconds",
                           outgoing->timeout);
  }
  
@@@ -349,13 -341,10 +340,11 @@@ void do_outgoing_connection(connection_
  begin:
        if(!c->outgoing->ai) {
                if(!c->outgoing->cfg) {
-                       ifdebug(CONNECTIONS) logger(LOG_ERR, _("Could not set up a meta connection to %s"),
+                       ifdebug(CONNECTIONS) logger(LOG_ERR, "Could not set up a meta connection to %s",
                                           c->name);
 -                      c->status.remove = true;
                        retry_outgoing(c->outgoing);
 +                      c->outgoing = NULL;
 +                      connection_del(c);
                        return;
                }
  
        return;
  }
  
-       logger(LOG_EMERG, _("handle_meta_read() called"));
 +void handle_meta_read(struct bufferevent *event, void *data) {
-       ifdebug(META) logger(LOG_DEBUG, _("handle_meta_write() called"));
++      logger(LOG_EMERG, "handle_meta_read() called");
 +      abort();
 +}
 +
 +void handle_meta_write(struct bufferevent *event, void *data) {
-       logger(LOG_EMERG, _("handle_meta_connection_error() called: %d: %s"), what, strerror(errno));
++      ifdebug(META) logger(LOG_DEBUG, "handle_meta_write() called");
 +}
 +
 +void handle_meta_connection_error(struct bufferevent *event, short what, void *data) {
 +      connection_t *c = data;
++      logger(LOG_EMERG, "handle_meta_connection_error() called: %d: %s", what, strerror(errno));
 +      terminate_connection(c, c->status.active);
 +}
 +
  void setup_outgoing_connection(outgoing_t *outgoing) {
        connection_t *c;
        node_t *n;
        connection_add(c);
  
        do_outgoing_connection(c);
-               logger(LOG_EMERG, _("bufferevent_new() failed: %s"), strerror(errno));
 +
 +      event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c);
 +      event_add(&c->inevent, NULL);
 +      c->buffer = bufferevent_new(c->socket, handle_meta_read, handle_meta_write, handle_meta_connection_error, c);
 +      if(!c->buffer) {
++              logger(LOG_EMERG, "bufferevent_new() failed: %s", strerror(errno));
 +              abort();
 +      }
 +      bufferevent_disable(c->buffer, EV_READ);
  }
  
  /*
@@@ -512,15 -475,14 +499,13 @@@ void handle_new_meta_connection(int soc
        connection_t *c;
        sockaddr_t sa;
        int fd;
 -      socklen_t len = sizeof(sa);
 +      socklen_t len = sizeof sa;
  
-       cp();
        fd = accept(sock, &sa.sa, &len);
  
        if(fd < 0) {
-               logger(LOG_ERR, _("Accepting a new connection failed: %s"), strerror(errno));
 -              logger(LOG_ERR, "Accepting a new connection failed: %s",
 -                         strerror(errno));
 -              return false;
++              logger(LOG_ERR, "Accepting a new connection failed: %s", strerror(errno));
 +              return;
        }
  
        sockaddrunmap(&sa);
        c->address = sa;
        c->hostname = sockaddr2hostname(&sa);
        c->socket = fd;
 -      c->last_ping_time = now;
 +      c->last_ping_time = time(NULL);
  
-       ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Connection from %s"), c->hostname);
+       ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection from %s", c->hostname);
  
-               logger(LOG_EMERG, _("bufferevent_new() failed: %s"), strerror(errno));
 +      event_set(&c->inevent, c->socket, EV_READ | EV_PERSIST, handle_meta_connection_data, c);
 +      event_add(&c->inevent, NULL);
 +      c->buffer = bufferevent_new(c->socket, NULL, handle_meta_write, handle_meta_connection_error, c);
 +      if(!c->buffer) {
++              logger(LOG_EMERG, "bufferevent_new() failed: %s", strerror(errno));
 +              abort();
 +      }
 +      bufferevent_disable(c->buffer, EV_READ);
 +              
        configure_tcp(c);
  
        connection_add(c);
@@@ -572,10 -526,8 +556,8 @@@ void try_outgoing_connections(void) 
        char *name;
        outgoing_t *outgoing;
        connection_t *c;
 -      avl_node_t *node;
 +      splay_node_t *node;
        
-       cp();
        if(outgoing_list) {
                for(node = connection_tree->head; node; node = node->next) {
                        c = node->data;
diff --cc src/netutl.c
@@@ -96,12 -88,11 +88,11 @@@ void sockaddr2str(const sockaddr_t *sa
                return;
        }
  
 -      err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
 +      err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port, NI_NUMERICHOST | NI_NUMERICSERV);
  
        if(err) {
-               logger(LOG_ERR, _("Error while translating addresses: %s"),
+               logger(LOG_ERR, "Error while translating addresses: %s",
                           gai_strerror(err));
-               cp_trace();
                raise(SIGFPE);
                exit(0);
        }
@@@ -128,10 -117,10 +117,10 @@@ char *sockaddr2hostname(const sockaddr_
                return str;
        }
  
 -      err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port),
 +      err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof address, port, sizeof port,
                                        hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV));
        if(err) {
-               logger(LOG_ERR, _("Error while looking up hostname: %s"),
+               logger(LOG_ERR, "Error while looking up hostname: %s",
                           gai_strerror(err));
        }
  
@@@ -210,12 -192,11 +192,11 @@@ int sockaddrcmp(const sockaddr_t *a, co
                        if(result)
                                return result;
  
 -                      return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof(a->in6.sin6_port));
 +                      return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof a->in6.sin6_port);
  
                default:
-                       logger(LOG_ERR, _("sockaddrcmp() was called with unknown address family %d, exitting!"),
+                       logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exitting!",
                                   a->sa.sa_family);
-                       cp_trace();
                        raise(SIGFPE);
                        exit(0);
        }
diff --cc src/node.c
@@@ -40,39 -38,26 +38,31 @@@ static int node_compare(const node_t *a
  }
  
  static int node_udp_compare(const node_t *a, const node_t *b) {
 -       return sockaddrcmp(&a->address, &b->address);
 +      int result;
 +
-       cp();
 +      result = sockaddrcmp(&a->address, &b->address);
 +
 +      if(result)
 +              return result;
 +
 +      return (a->name && b->name) ? strcmp(a->name, b->name) : 0;
  }
  
  void init_nodes(void) {
-       cp();
 -      node_tree = avl_alloc_tree((avl_compare_t) node_compare, (avl_action_t) free_node);
 -      node_udp_tree = avl_alloc_tree((avl_compare_t) node_udp_compare, NULL);
 +      node_tree = splay_alloc_tree((splay_compare_t) node_compare, (splay_action_t) free_node);
 +      node_udp_tree = splay_alloc_tree((splay_compare_t) node_udp_compare, NULL);
  }
  
  void exit_nodes(void) {
-       cp();
 -      avl_delete_tree(node_udp_tree);
 -      avl_delete_tree(node_tree);
 +      splay_delete_tree(node_udp_tree);
 +      splay_delete_tree(node_tree);
  }
  
  node_t *new_node(void) {
 -      node_t *n = xmalloc_and_zero(sizeof(*n));
 +      node_t *n = xmalloc_and_zero(sizeof *n);
  
-       cp();
        n->subnet_tree = new_subnet_tree();
        n->edge_tree = new_edge_tree();
 -      EVP_CIPHER_CTX_init(&n->inctx);
 -      EVP_CIPHER_CTX_init(&n->outctx);
        n->mtu = MTU;
        n->maxmtu = MTU;
  
  }
  
  void free_node(node_t *n) {
-       cp();
 -      if(n->inkey)
 -              free(n->inkey);
 -
 -      if(n->outkey)
 -              free(n->outkey);
--
        if(n->subnet_tree)
                free_subnet_tree(n->subnet_tree);
  
  }
  
  void node_add(node_t *n) {
-       cp();
 -      avl_insert(node_tree, n);
 +      splay_insert(node_tree, n);
  }
  
  void node_del(node_t *n) {
  node_t *lookup_node(char *name) {
        node_t n = {0};
  
-       cp();
-       
        n.name = name;
  
 -      return avl_search(node_tree, &n);
 +      return splay_search(node_tree, &n);
  }
  
  node_t *lookup_node_udp(const sockaddr_t *sa) {
        n.address = *sa;
        n.name = NULL;
  
 -      return avl_search(node_udp_tree, &n);
 +      return splay_search(node_udp_tree, &n);
  }
  
- void update_node_udp(node_t *n, const sockaddr_t *sa)
- {
+ void update_node_udp(node_t *n, const sockaddr_t *sa) {
 -      avl_delete(node_udp_tree, n);
 +      splay_delete(node_udp_tree, n);
  
        if(n->hostname)
                free(n->hostname);
        }
  }
  
 -void dump_nodes(void) {
 -      avl_node_t *node;
 +int dump_nodes(struct evbuffer *out) {
 +      splay_node_t *node;
        node_t *n;
  
-       cp();
 -      logger(LOG_DEBUG, "Nodes:");
--
        for(node = node_tree->head; node; node = node->next) {
                n = node->data;
-               if(evbuffer_add_printf(out, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s distance %d pmtu %d (min %d max %d)\n"),
 -              logger(LOG_DEBUG, " %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s pmtu %d (min %d max %d)",
 -                         n->name, n->hostname, n->outcipher ? n->outcipher->nid : 0,
 -                         n->outdigest ? n->outdigest->type : 0, n->outmaclength, n->outcompression,
++              if(evbuffer_add_printf(out, " %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s distance %d pmtu %d (min %d max %d)\n",
 +                         n->name, n->hostname, cipher_get_nid(&n->outcipher),
 +                         digest_get_nid(&n->outdigest), digest_length(&n->outdigest), n->outcompression,
                           n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-",
 -                         n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu);
 +                         n->via ? n->via->name : "-", n->distance, n->mtu, n->minmtu, n->maxmtu) == -1)
 +                      return errno;
        }
  
 -      logger(LOG_DEBUG, "End of nodes.");
 +      return 0;
  }
diff --cc src/node.h
Simple merge
      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., 675 Mass Ave, Cambridge, MA 02139, USA.
-     $Id$
+     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__
 +#ifndef __TINC_RSAGEN_H__
 +#define __TINC_RSAGEN_H__
  
 -#include "avl_tree.h"
 +#include "rsa.h"
  
 -extern avl_tree_t *event_tree;
 +extern bool rsa_generate(rsa_t *rsa, size_t bits, unsigned long exponent);
 +extern bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp);
 +extern bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp);
  
 -typedef void (*event_handler_t)(void *);
 -
 -typedef struct {
 -      time_t time;
 -      int id;
 -      event_handler_t handler;
 -      void *data;
 -} event_t;
 -
 -extern void init_events(void);
 -extern void exit_events(void);
 -extern void expire_events(void);
 -extern event_t *new_event(void) __attribute__ ((__malloc__));
 -extern void free_event(event_t *);
 -extern void event_add(event_t *);
 -extern void event_del(event_t *);
 -extern event_t *get_expired_event(void);
 -
 -#endif                                                        /* __TINC_EVENT_H__ */
 +#endif
diff --cc src/process.c
@@@ -44,9 -44,11 +42,8 @@@ extern bool use_logfile
  
  sigset_t emptysigset;
  
 -static int saved_debug_level = -1;
 -
  static void memory_full(int size) {
-       logger(LOG_ERR, _("Memory exhausted (couldn't allocate %d bytes), exitting."), size);
-       cp_trace();
+       logger(LOG_ERR, "Memory exhausted (couldn't allocate %d bytes), exitting.", size);
        exit(1);
  }
  
@@@ -223,15 -233,86 +220,13 @@@ bool init_service(void) 
  }
  #endif
  
 -#ifndef HAVE_MINGW
 -/*
 -  check for an existing tinc for this net, and write pid to pidfile
 -*/
 -static bool write_pidfile(void) {
 -      pid_t pid;
 -
 -      pid = check_pid(pidfilename);
 -
 -      if(pid) {
 -              if(netname)
 -                      fprintf(stderr, "A tincd is already running for net `%s' with pid %ld.\n",
 -                                      netname, (long)pid);
 -              else
 -                      fprintf(stderr, "A tincd is already running with pid %ld.\n", (long)pid);
 -              return false;
 -      }
 -
 -      /* if it's locked, write-protected, or whatever */
 -      if(!write_pid(pidfilename)) {
 -              fprintf(stderr, "Could write pid file %s: %s\n", pidfilename, strerror(errno));
 -              return false;
 -      }
 -
 -      return true;
 -}
 -#endif
 -
 -/*
 -  kill older tincd for this net
 -*/
 -bool kill_other(int signal) {
 -#ifndef HAVE_MINGW
 -      pid_t pid;
 -
 -      pid = read_pid(pidfilename);
 -
 -      if(!pid) {
 -              if(netname)
 -                      fprintf(stderr, "No other tincd is running for net `%s'.\n",
 -                                      netname);
 -              else
 -                      fprintf(stderr, "No other tincd is running.\n");
 -              return false;
 -      }
 -
 -      errno = 0;                                      /* No error, sometimes errno is only changed on error */
 -
 -      /* ESRCH is returned when no process with that pid is found */
 -      if(kill(pid, signal) && errno == ESRCH) {
 -              if(netname)
 -                      fprintf(stderr, "The tincd for net `%s' is no longer running. ",
 -                                      netname);
 -              else
 -                      fprintf(stderr, "The tincd is no longer running. ");
 -
 -              fprintf(stderr, "Removing stale lock file.\n");
 -              remove_pid(pidfilename);
 -      }
 -
 -      return true;
 -#else
 -      return remove_service();
 -#endif
 -}
 -
  /*
 -  Detach from current terminal, write pidfile, kill parent
 +  Detach from current terminal
  */
  bool detach(void) {
-       cp();
        setup_signals();
  
 -      /* First check if we can open a fresh new pidfile */
 -
  #ifndef HAVE_MINGW
 -      if(!write_pidfile())
 -              return false;
 -
 -      /* If we succeeded in doing that, detach */
 -
        closelogger();
  #endif
  
@@@ -342,10 -428,25 +335,9 @@@ bool execute_script(const char *name, c
  */
  
  #ifndef HAVE_MINGW
 -static RETSIGTYPE sigterm_handler(int a) {
 -      logger(LOG_NOTICE, "Got %s signal", "TERM");
 -      if(running)
 -              running = false;
 -      else
 -              exit(1);
 -}
 -
 -static RETSIGTYPE sigquit_handler(int a) {
 -      logger(LOG_NOTICE, "Got %s signal", "QUIT");
 -      if(running)
 -              running = false;
 -      else
 -              exit(1);
 -}
 -
  static RETSIGTYPE fatal_signal_square(int a) {
-       logger(LOG_ERR, _("Got another fatal signal %d (%s): not restarting."), a,
+       logger(LOG_ERR, "Got another fatal signal %d (%s): not restarting.", a,
                   strsignal(a));
-       cp_trace();
        exit(1);
  }
  
@@@ -364,17 -464,58 +355,16 @@@ static RETSIGTYPE fatal_signal_handler(
  
                close_network_connections();
                sleep(5);
 -              remove_pid(pidfilename);
 +              exit_control();
                execvp(g_argv[0], g_argv);
        } else {
-               logger(LOG_NOTICE, _("Not restarting."));
+               logger(LOG_NOTICE, "Not restarting.");
                exit(1);
        }
  }
  
 -static RETSIGTYPE sighup_handler(int a) {
 -      logger(LOG_NOTICE, "Got %s signal", "HUP");
 -      sighup = true;
 -}
 -
 -static RETSIGTYPE sigint_handler(int a) {
 -      logger(LOG_NOTICE, "Got %s signal", "INT");
 -
 -      if(saved_debug_level != -1) {
 -              logger(LOG_NOTICE, "Reverting to old debug level (%d)",
 -                      saved_debug_level);
 -              debug_level = saved_debug_level;
 -              saved_debug_level = -1;
 -      } else {
 -              logger(LOG_NOTICE,
 -                      "Temporarily setting debug level to 5.  Kill me with SIGINT again to go back to level %d.",
 -                      debug_level);
 -              saved_debug_level = debug_level;
 -              debug_level = 5;
 -      }
 -}
 -
 -static RETSIGTYPE sigalrm_handler(int a) {
 -      logger(LOG_NOTICE, "Got %s signal", "ALRM");
 -      sigalrm = true;
 -}
 -
 -static RETSIGTYPE sigusr1_handler(int a) {
 -      dump_connections();
 -}
 -
 -static RETSIGTYPE sigusr2_handler(int a) {
 -      dump_device_stats();
 -      dump_nodes();
 -      dump_edges();
 -      dump_subnets();
 -}
 -
 -static RETSIGTYPE sigwinch_handler(int a) {
 -      do_purge = true;
 -}
 -
  static RETSIGTYPE unexpected_signal_handler(int a) {
-       logger(LOG_WARNING, _("Got unexpected signal %d (%s)"), a, strsignal(a));
-       cp_trace();
+       logger(LOG_WARNING, "Got unexpected signal %d (%s)", a, strsignal(a));
  }
  
  static RETSIGTYPE ignore_signal_handler(int a) {
diff --cc src/process.h
Simple merge
diff --cc src/protocol.c
@@@ -68,11 -66,9 +66,9 @@@ bool check_id(const char *id) 
  
  bool send_request(connection_t *c, const char *format, ...) {
        va_list args;
 -      char buffer[MAXBUFSIZE];
 -      int len, request;
 +      char request[MAXBUFSIZE];
 +      int len;
  
-       cp();
        /* Use vsnprintf instead of vxasprintf: faster, no memory
           fragmentation, cleanup is automatic, and there is a limit on the
           input buffer anyway */
        }
  
        ifdebug(PROTOCOL) {
 -              sscanf(buffer, "%d", &request);
                ifdebug(META)
-                       logger(LOG_DEBUG, _("Sending %s to %s (%s): %s"),
+                       logger(LOG_DEBUG, "Sending %s to %s (%s): %s",
 -                                 request_name[request], c->name, c->hostname, buffer);
 +                                 request_name[atoi(request)], c->name, c->hostname, request);
                else
-                       logger(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[atoi(request)],
 -                      logger(LOG_DEBUG, "Sending %s to %s (%s)", request_name[request],
++                      logger(LOG_DEBUG, "Sending %s to %s (%s)", request_name[atoi(request)],
                                   c->name, c->hostname);
        }
  
 -      buffer[len++] = '\n';
 +      request[len++] = '\n';
  
        if(c == broadcast) {
 -              broadcast_meta(NULL, buffer, len);
 +              broadcast_meta(NULL, request, len);
                return true;
        } else
 -              return send_meta(c, buffer, len);
 +              return send_meta(c, request, len);
  }
  
 -void forward_request(connection_t *from) {
 -      int request;
 -
 +void forward_request(connection_t *from, char *request) {
-       cp();
        ifdebug(PROTOCOL) {
 -              sscanf(from->buffer, "%d", &request);
                ifdebug(META)
-                       logger(LOG_DEBUG, _("Forwarding %s from %s (%s): %s"),
+                       logger(LOG_DEBUG, "Forwarding %s from %s (%s): %s",
 -                                 request_name[request], from->name, from->hostname,
 -                                 from->buffer);
 +                                 request_name[atoi(request)], from->name, from->hostname, request);
                else
-                       logger(LOG_DEBUG, _("Forwarding %s from %s (%s)"),
+                       logger(LOG_DEBUG, "Forwarding %s from %s (%s)",
 -                                 request_name[request], from->name, from->hostname);
 +                                 request_name[atoi(request)], from->name, from->hostname);
        }
  
 -      from->buffer[from->reqlen - 1] = '\n';
 -
 -      broadcast_meta(from, from->buffer, from->reqlen);
 +      int len = strlen(request);
 +      request[len] = '\n';
 +      broadcast_meta(from, request, len);
  }
  
 -bool receive_request(connection_t *c) {
 -      int request;
 +bool receive_request(connection_t *c, char *request) {
 +      int reqno = atoi(request);
  
-       cp();
 -      if(sscanf(c->buffer, "%d", &request) == 1) {
 -              if((request < 0) || (request >= LAST) || !request_handlers[request]) {
 +      if(reqno || *request == '0') {
 +              if((reqno < 0) || (reqno >= LAST) || !request_handlers[reqno]) {
                        ifdebug(META)
-                               logger(LOG_DEBUG, _("Unknown request from %s (%s): %s"),
+                               logger(LOG_DEBUG, "Unknown request from %s (%s): %s",
 -                                         c->name, c->hostname, c->buffer);
 +                                         c->name, c->hostname, request);
                        else
-                               logger(LOG_ERR, _("Unknown request from %s (%s)"),
+                               logger(LOG_ERR, "Unknown request from %s (%s)",
                                           c->name, c->hostname);
  
                        return false;
                } else {
                        ifdebug(PROTOCOL) {
                                ifdebug(META)
-                                       logger(LOG_DEBUG, _("Got %s from %s (%s): %s"),
+                                       logger(LOG_DEBUG, "Got %s from %s (%s): %s",
 -                                                 request_name[request], c->name, c->hostname,
 -                                                 c->buffer);
 +                                                 request_name[reqno], c->name, c->hostname, request);
                                else
-                                       logger(LOG_DEBUG, _("Got %s from %s (%s)"),
+                                       logger(LOG_DEBUG, "Got %s from %s (%s)",
 -                                                 request_name[request], c->name, c->hostname);
 +                                                 request_name[reqno], c->name, c->hostname);
                        }
                }
  
 -              if((c->allow_request != ALL) && (c->allow_request != request)) {
 +              if((c->allow_request != ALL) && (c->allow_request != reqno)) {
-                       logger(LOG_ERR, _("Unauthorized request from %s (%s)"), c->name,
+                       logger(LOG_ERR, "Unauthorized request from %s (%s)", c->name,
                                   c->hostname);
                        return false;
                }
  
 -              if(!request_handlers[request](c)) {
 +              if(!request_handlers[reqno](c, request)) {
                        /* Something went wrong. Probably scriptkiddies. Terminate. */
  
-                       logger(LOG_ERR, _("Error while processing %s from %s (%s)"),
+                       logger(LOG_ERR, "Error while processing %s from %s (%s)",
 -                                 request_name[request], c->name, c->hostname);
 +                                 request_name[reqno], c->name, c->hostname);
                        return false;
                }
        } else {
@@@ -188,31 -190,25 +178,27 @@@ static struct event past_request_event
  bool seen_request(char *request) {
        past_request_t *new, p = {0};
  
-       cp();
        p.request = request;
  
 -      if(avl_search(past_request_tree, &p)) {
 +      if(splay_search(past_request_tree, &p)) {
-               ifdebug(SCARY_THINGS) logger(LOG_DEBUG, _("Already seen request"));
+               ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Already seen request");
                return true;
        } else {
 -              new = xmalloc(sizeof(*new));
 +              new = xmalloc(sizeof *new);
                new->request = xstrdup(request);
 -              new->firstseen = now;
 -              avl_insert(past_request_tree, new);
 +              new->firstseen = time(NULL);
 +              splay_insert(past_request_tree, new);
 +              event_add(&past_request_event, &(struct timeval){10, 0});
                return false;
        }
  }
  
 -void age_past_requests(void) {
 -      avl_node_t *node, *next;
 +void age_past_requests(int fd, short events, void *data) {
 +      splay_node_t *node, *next;
        past_request_t *p;
        int left = 0, deleted = 0;
 +      time_t now = time(NULL);
  
-       cp();
        for(node = past_request_tree->head; node; node = next) {
                next = node->next;
                p = node->data;
        }
  
        if(left || deleted)
-               ifdebug(SCARY_THINGS) logger(LOG_DEBUG, _("Aging past requests: deleted %d, left %d"),
+               ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Aging past requests: deleted %d, left %d",
                           deleted, left);
-       cp();
 +
 +      if(left)
 +              event_add(&past_request_event, &(struct timeval){10, 0});
 +}
 +
 +void init_requests(void) {
-       cp();
 +      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);
 +
 +      event_del(&past_request_event);
  }
diff --cc src/protocol.h
Simple merge
  #include "xalloc.h"
  
  bool send_id(connection_t *c) {
-       cp();
 +      gettimeofday(&c->start, NULL);
 +
        return send_request(c, "%d %s %d", ID, myself->connection->name,
                                                myself->connection->protocol_version);
  }
  
 -bool id_h(connection_t *c) {
 +bool id_h(connection_t *c, char *request) {
        char name[MAX_STRING_SIZE];
  
-       cp();
 -      if(sscanf(c->buffer, "%*d " MAX_STRING " %d", name, &c->protocol_version) != 2) {
 +      if(sscanf(request, "%*d " MAX_STRING " %d", name, &c->protocol_version) != 2) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ID", c->name,
+               logger(LOG_ERR, "Got bad %s from %s (%s)", "ID", c->name,
                           c->hostname);
                return false;
        }
  }
  
  bool send_metakey(connection_t *c) {
 -      char *buffer;
 -      int len;
 -      bool x;
 -
 -      len = RSA_size(c->rsa_key);
 +      size_t len = rsa_size(&c->rsa);
 +      char key[len];
 +      char enckey[len];
 +      char hexkey[2 * len + 1];
  
-       cp();
 -      /* Allocate buffers for the meta key */
--
 -      buffer = alloca(2 * len + 1);
 +      if(!cipher_open_blowfish_ofb(&c->outcipher))
 +              return false;
        
 -      c->outkey = xrealloc(c->outkey, len);
 -
 -      if(!c->outctx)
 -              c->outctx = xmalloc_and_zero(sizeof(*c->outctx));
 +      if(!digest_open_sha1(&c->outdigest, -1))
 +              return false;
  
 -      /* Copy random data to the buffer */
 +      /* Create a random key */
  
 -      RAND_pseudo_bytes((unsigned char *)c->outkey, len);
 +      randomize(key, len);
  
        /* The message we send must be smaller than the modulus of the RSA key.
           By definition, for a key of k bits, the following formula holds:
           This can be done by setting the most significant bit to zero.
         */
  
 -      c->outkey[0] &= 0x7F;
 +      key[0] &= 0x7F;
 +
 +      cipher_set_key_from_rsa(&c->outcipher, key, len, true);
  
        ifdebug(SCARY_THINGS) {
 -              bin2hex(c->outkey, buffer, len);
 -              buffer[len * 2] = '\0';
 -              logger(LOG_DEBUG, "Generated random meta key (unencrypted): %s",
 -                         buffer);
 +              bin2hex(key, hexkey, len);
 +              hexkey[len * 2] = '\0';
-               logger(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), hexkey);
++              logger(LOG_DEBUG, "Generated random meta key (unencrypted): %s", hexkey);
        }
  
        /* Encrypt the random data
           with a length equal to that of the modulus of the RSA key.
         */
  
 -      if(RSA_public_encrypt(len, (unsigned char *)c->outkey, (unsigned char *)buffer, c->rsa_key, RSA_NO_PADDING) != len) {
 -              logger(LOG_ERR, "Error during encryption of meta key for %s (%s)",
 -                         c->name, c->hostname);
 +      if(!rsa_public_encrypt(&c->rsa, key, len, enckey)) {
-               logger(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname);
++              logger(LOG_ERR, "Error during encryption of meta key for %s (%s)", c->name, c->hostname);
                return false;
        }
  
  
        /* Send the meta key */
  
 -      x = send_request(c, "%d %d %d %d %d %s", METAKEY,
 -                                       c->outcipher ? c->outcipher->nid : 0,
 -                                       c->outdigest ? c->outdigest->type : 0, c->outmaclength,
 -                                       c->outcompression, buffer);
 -
 -      /* Further outgoing requests are encrypted with the key we just generated */
 -
 -      if(c->outcipher) {
 -              if(!EVP_EncryptInit(c->outctx, c->outcipher,
 -                                      (unsigned char *)c->outkey + len - c->outcipher->key_len,
 -                                      (unsigned char *)c->outkey + len - c->outcipher->key_len -
 -                                      c->outcipher->iv_len)) {
 -                      logger(LOG_ERR, "Error during initialisation of cipher for %s (%s): %s",
 -                                      c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
 -                      return false;
 -              }
 -
 -              c->status.encryptout = true;
 -      }
 -
 -      return x;
 +      bool result = send_request(c, "%d %d %d %d %d %s", METAKEY,
 +                       cipher_get_nid(&c->outcipher),
 +                       digest_get_nid(&c->outdigest), c->outmaclength,
 +                       c->outcompression, hexkey);
 +      
 +      c->status.encryptout = true;
 +      return result;
  }
  
 -bool metakey_h(connection_t *c) {
 -      char buffer[MAX_STRING_SIZE];
 +bool metakey_h(connection_t *c, char *request) {
 +      char hexkey[MAX_STRING_SIZE];
        int cipher, digest, maclength, compression;
 -      int len;
 +      size_t len = rsa_size(&myself->connection->rsa);
 +      char enckey[len];
 +      char key[len];
  
-       cp();
 -      if(sscanf(c->buffer, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, buffer) != 5) {
 -              logger(LOG_ERR, "Got bad %s from %s (%s)", "METAKEY", c->name,
 -                         c->hostname);
 +      if(sscanf(request, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, hexkey) != 5) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "METAKEY", c->name, c->hostname);
++              logger(LOG_ERR, "Got bad %s from %s (%s)", "METAKEY", c->name, c->hostname);
                return false;
        }
  
 -      len = RSA_size(myself->connection->rsa_key);
 -
        /* Check if the length of the meta key is all right */
  
 -      if(strlen(buffer) != len * 2) {
 +      if(strlen(hexkey) != len * 2) {
-               logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong keylength");
+               logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong keylength");
                return false;
        }
  
  
        /* Decrypt the meta key */
  
 -      if(RSA_private_decrypt(len, (unsigned char *)buffer, (unsigned char *)c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) {  /* See challenge() */
 -              logger(LOG_ERR, "Error during decryption of meta key for %s (%s)",
 -                         c->name, c->hostname);
 +      if(!rsa_private_decrypt(&myself->connection->rsa, enckey, len, key)) {
-               logger(LOG_ERR, _("Error during decryption of meta key for %s (%s)"), c->name, c->hostname);
++              logger(LOG_ERR, "Error during decryption of meta key for %s (%s)", c->name, c->hostname);
                return false;
        }
  
        ifdebug(SCARY_THINGS) {
 -              bin2hex(c->inkey, buffer, len);
 -              buffer[len * 2] = '\0';
 -              logger(LOG_DEBUG, "Received random meta key (unencrypted): %s", buffer);
 +              bin2hex(key, hexkey, len);
 +              hexkey[len * 2] = '\0';
-               logger(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), hexkey);
++              logger(LOG_DEBUG, "Received random meta key (unencrypted): %s", hexkey);
        }
  
 -      /* All incoming requests will now be encrypted. */
 -
        /* Check and lookup cipher and digest algorithms */
  
 -      if(cipher) {
 -              c->incipher = EVP_get_cipherbynid(cipher);
 -              
 -              if(!c->incipher) {
 -                      logger(LOG_ERR, "%s (%s) uses unknown cipher!", c->name, c->hostname);
 -                      return false;
 -              }
 -
 -              if(!EVP_DecryptInit(c->inctx, c->incipher,
 -                                      (unsigned char *)c->inkey + len - c->incipher->key_len,
 -                                      (unsigned char *)c->inkey + len - c->incipher->key_len -
 -                                      c->incipher->iv_len)) {
 -                      logger(LOG_ERR, "Error during initialisation of cipher from %s (%s): %s",
 -                                      c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
 -                      return false;
 -              }
 -
 -              c->status.decryptin = true;
 -      } else {
 -              c->incipher = NULL;
 +      if(!cipher_open_by_nid(&c->incipher, cipher) || !cipher_set_key_from_rsa(&c->incipher, key, len, false)) {
-               logger(LOG_ERR, _("Error during initialisation of cipher from %s (%s)"), c->name, c->hostname);
++              logger(LOG_ERR, "Error during initialisation of cipher from %s (%s)", c->name, c->hostname);
 +              return false;
        }
  
 -      c->inmaclength = maclength;
 -
 -      if(digest) {
 -              c->indigest = EVP_get_digestbynid(digest);
 -
 -              if(!c->indigest) {
 -                      logger(LOG_ERR, "Node %s (%s) uses unknown digest!", c->name, c->hostname);
 -                      return false;
 -              }
 -
 -              if(c->inmaclength > c->indigest->md_size || c->inmaclength < 0) {
 -                      logger(LOG_ERR, "%s (%s) uses bogus MAC length!", c->name, c->hostname);
 -                      return false;
 -              }
 -      } else {
 -              c->indigest = NULL;
 +      if(!digest_open_by_nid(&c->indigest, digest, -1)) {
-               logger(LOG_ERR, _("Error during initialisation of digest from %s (%s)"), c->name, c->hostname);
++              logger(LOG_ERR, "Error during initialisation of digest from %s (%s)", c->name, c->hostname);
 +              return false;
        }
  
 -      c->incompression = compression;
 +      c->status.decryptin = true;
  
        c->allow_request = CHALLENGE;
  
  }
  
  bool send_challenge(connection_t *c) {
 -      char *buffer;
 -      int len;
 +      size_t len = rsa_size(&c->rsa);
 +      char buffer[len * 2 + 1];
  
-       cp();
 -      /* CHECKME: what is most reasonable value for len? */
 -
 -      len = RSA_size(c->rsa_key);
 -
 -      /* Allocate buffers for the challenge */
 -
 -      buffer = alloca(2 * len + 1);
--
 -      c->hischallenge = xrealloc(c->hischallenge, len);
 +      if(!c->hischallenge)
 +              c->hischallenge = xrealloc(c->hischallenge, len);
  
        /* Copy random data to the buffer */
  
        return send_request(c, "%d %s", CHALLENGE, buffer);
  }
  
 -bool challenge_h(connection_t *c) {
 +bool challenge_h(connection_t *c, char *request) {
        char buffer[MAX_STRING_SIZE];
 -      int len;
 +      size_t len = rsa_size(&myself->connection->rsa);
 +      size_t digestlen = digest_length(&c->outdigest);
 +      char digest[digestlen];
  
-       cp();
 -      if(sscanf(c->buffer, "%*d " MAX_STRING, buffer) != 1) {
 -              logger(LOG_ERR, "Got bad %s from %s (%s)", "CHALLENGE", c->name,
 -                         c->hostname);
 +      if(sscanf(request, "%*d " MAX_STRING, buffer) != 1) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "CHALLENGE", c->name, c->hostname);
++              logger(LOG_ERR, "Got bad %s from %s (%s)", "CHALLENGE", c->name, c->hostname);
                return false;
        }
  
        /* Check if the length of the challenge is all right */
  
        if(strlen(buffer) != len * 2) {
-               logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong challenge length");
 -              logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name,
 -                         c->hostname, "wrong challenge length");
++              logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, "wrong challenge length");
                return false;
        }
  
  
        c->allow_request = CHAL_REPLY;
  
-       cp();
 -      /* Rest is done by send_chal_reply() */
 -
 -      return send_chal_reply(c);
 -}
 -
 -bool send_chal_reply(connection_t *c) {
 -      char hash[EVP_MAX_MD_SIZE * 2 + 1];
 -      EVP_MD_CTX ctx;
--
        /* Calculate the hash from the challenge we received */
  
 -      if(!EVP_DigestInit(&ctx, c->indigest)
 -                      || !EVP_DigestUpdate(&ctx, c->mychallenge, RSA_size(myself->connection->rsa_key))
 -                      || !EVP_DigestFinal(&ctx, (unsigned char *)hash, NULL)) {
 -              logger(LOG_ERR, "Error during calculation of response for %s (%s): %s",
 -                      c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
 -              return false;
 -      }
 +      digest_create(&c->indigest, buffer, len, digest);
  
        /* Convert the hash to a hexadecimal formatted string */
  
  
        /* Send the reply */
  
 -      return send_request(c, "%d %s", CHAL_REPLY, hash);
 +      return send_request(c, "%d %s", CHAL_REPLY, buffer);
  }
  
 -bool chal_reply_h(connection_t *c) {
 +bool chal_reply_h(connection_t *c, char *request) {
        char hishash[MAX_STRING_SIZE];
 -      char myhash[EVP_MAX_MD_SIZE];
 -      EVP_MD_CTX ctx;
  
-       cp();
 -      if(sscanf(c->buffer, "%*d " MAX_STRING, hishash) != 1) {
 +      if(sscanf(request, "%*d " MAX_STRING, hishash) != 1) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "CHAL_REPLY", c->name,
+               logger(LOG_ERR, "Got bad %s from %s (%s)", "CHAL_REPLY", c->name,
                           c->hostname);
                return false;
        }
  
        /* Check if the length of the hash is all right */
  
 -      if(strlen(hishash) != c->outdigest->md_size * 2) {
 -              logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name,
 -                         c->hostname, "wrong challenge reply length");
 +      if(strlen(hishash) != digest_length(&c->outdigest) * 2) {
-               logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply length"));
++              logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, _("wrong challenge reply length"));
                return false;
        }
  
        /* Convert the hash to binary format */
  
 -      hex2bin(hishash, hishash, c->outdigest->md_size);
 +      hex2bin(hishash, hishash, digest_length(&c->outdigest));
  
 -      /* Calculate the hash from the challenge we sent */
 -
 -      if(!EVP_DigestInit(&ctx, c->outdigest)
 -                      || !EVP_DigestUpdate(&ctx, c->hischallenge, RSA_size(c->rsa_key))
 -                      || !EVP_DigestFinal(&ctx, (unsigned char *)myhash, NULL)) {
 -              logger(LOG_ERR, "Error during calculation of response from %s (%s): %s",
 -                      c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
 -              return false;
 -      }
 -
 -      /* Verify the incoming hash with the calculated hash */
 -
 -      if(memcmp(hishash, myhash, c->outdigest->md_size)) {
 -              logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name,
 -                         c->hostname, "wrong challenge reply");
 -
 -              ifdebug(SCARY_THINGS) {
 -                      bin2hex(myhash, hishash, SHA_DIGEST_LENGTH);
 -                      hishash[SHA_DIGEST_LENGTH * 2] = '\0';
 -                      logger(LOG_DEBUG, "Expected challenge reply: %s", hishash);
 -              }
 +      /* Verify the hash */
  
-               logger(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply"));
 +      if(!digest_verify(&c->outdigest, c->hischallenge, rsa_size(&c->rsa), hishash)) {
++              logger(LOG_ERR, "Possible intruder %s (%s): %s", c->name, c->hostname, _("wrong challenge reply"));
                return false;
        }
  
@@@ -410,10 -497,8 +390,8 @@@ bool ack_h(connection_t *c, char *reque
        long int options;
        node_t *n;
  
-       cp();
 -      if(sscanf(c->buffer, "%*d " MAX_STRING " %d %lx", hisport, &weight, &options) != 3) {
 +      if(sscanf(request, "%*d " MAX_STRING " %d %lx", hisport, &weight, &options) != 3) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ACK", c->name,
+               logger(LOG_ERR, "Got bad %s from %s (%s)", "ACK", c->name,
                           c->hostname);
                return false;
        }
        } else {
                if(n->connection) {
                        /* Oh dear, we already have a connection to this node. */
-                       ifdebug(CONNECTIONS) logger(LOG_DEBUG, _("Established a second connection with %s (%s), closing old connection"), n->connection->name, n->connection->hostname);
 -                      ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Established a second connection with %s (%s), closing old connection",
 -                                         n->name, n->hostname);
++                      ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Established a second connection with %s (%s), closing old connection", n->connection->name, n->connection->hostname);
 +
 +                      if(n->connection->outgoing) {
 +                              if(c->outgoing)
-                                       logger(LOG_WARNING, _("Two outgoing connections to the same node!"));
++                                      logger(LOG_WARNING, "Two outgoing connections to the same node!");
 +                              else
 +                                      c->outgoing = n->connection->outgoing;
 +
 +                              n->connection->outgoing = NULL;
 +                      }
 +
                        terminate_connection(n->connection, false);
                        /* Run graph algorithm to purge key and make sure up/down scripts are rerun with new IP addresses and stuff */
                        graph();
@@@ -64,11 -61,9 +61,9 @@@ bool add_edge_h(connection_t *c, char *
        long int options;
        int weight;
  
-       cp();
 -      if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d",
 +      if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d",
                          from_name, to_name, to_address, to_port, &options, &weight) != 6) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_EDGE", c->name,
+               logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name,
                           c->hostname);
                return false;
        }
@@@ -185,10 -178,8 +178,8 @@@ bool del_edge_h(connection_t *c, char *
        char to_name[MAX_STRING_SIZE];
        node_t *from, *to;
  
-       cp();
 -      if(sscanf(c->buffer, "%*d %*x "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) {
 +      if(sscanf(request, "%*d %*x "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_EDGE", c->name,
+               logger(LOG_ERR, "Got bad %s from %s (%s)", "DEL_EDGE", c->name,
                           c->hostname);
                return false;
        }
  #include "utils.h"
  #include "xalloc.h"
  
 -bool mykeyused = false;
 +static bool mykeyused = false;
  
  bool send_key_changed() {
-       cp();
        /* Only send this message if some other daemon requested our key previously.
           This reduces unnecessary key_changed broadcasts.
         */
@@@ -53,10 -51,8 +49,8 @@@ bool key_changed_h(connection_t *c, cha
        char name[MAX_STRING_SIZE];
        node_t *n;
  
-       cp();
 -      if(sscanf(c->buffer, "%*d %*x " MAX_STRING, name) != 1) {
 +      if(sscanf(request, "%*d %*x " MAX_STRING, name) != 1) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "KEY_CHANGED",
+               logger(LOG_ERR, "Got bad %s from %s (%s)", "KEY_CHANGED",
                           c->name, c->hostname);
                return false;
        }
@@@ -94,10 -88,8 +86,8 @@@ bool req_key_h(connection_t *c, char *r
        char to_name[MAX_STRING_SIZE];
        node_t *from, *to;
  
-       cp();
 -      if(sscanf(c->buffer, "%*d " MAX_STRING " " MAX_STRING, from_name, to_name) != 2) {
 +      if(sscanf(request, "%*d " MAX_STRING " " MAX_STRING, from_name, to_name) != 2) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "REQ_KEY", c->name,
+               logger(LOG_ERR, "Got bad %s from %s (%s)", "REQ_KEY", c->name,
                           c->hostname);
                return false;
        }
  }
  
  bool send_ans_key(node_t *to) {
 -      char *key;
 +      size_t keylen = cipher_keylength(&myself->incipher);
 +      char key[keylen * 2 + 1];
  
-       cp();
 -      // Set key parameters
 -      to->incipher = myself->incipher;
 -      to->inkeylength = myself->inkeylength;
 -      to->indigest = myself->indigest;
 -      to->inmaclength = myself->inmaclength;
 +      cipher_open_by_nid(&to->incipher, cipher_get_nid(&myself->incipher));
 +      digest_open_by_nid(&to->indigest, digest_get_nid(&myself->indigest), digest_length(&myself->indigest));
        to->incompression = myself->incompression;
  
 -      // Allocate memory for key
 -      to->inkey = xrealloc(to->inkey, to->inkeylength);
 +      randomize(key, keylen);
 +      cipher_set_key(&to->incipher, key, true);
  
 -      // Create a new key
 -      RAND_pseudo_bytes((unsigned char *)to->inkey, to->inkeylength);
 -      if(to->incipher)
 -              EVP_DecryptInit_ex(&to->inctx, to->incipher, NULL, (unsigned char *)to->inkey, (unsigned char *)to->inkey + to->incipher->key_len);
 +      bin2hex(key, key, keylen);
 +      key[keylen * 2] = '\0';
  
        // Reset sequence number and late packet window
        mykeyused = true;
@@@ -175,12 -172,10 +163,10 @@@ bool ans_key_h(connection_t *c, char *r
        int cipher, digest, maclength, compression;
        node_t *from, *to;
  
-       cp();
 -      if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d",
 +      if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d",
                from_name, to_name, key, &cipher, &digest, &maclength,
                &compression) != 7) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ANS_KEY", c->name,
+               logger(LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name,
                           c->hostname);
                return false;
        }
                        return false;
  
                if(!to->status.reachable) {
-                       logger(LOG_WARNING, _("Got %s from %s (%s) destination %s which is not reachable"),
+                       logger(LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
 -                              "ANS_KEY", c->name, c->hostname, to_name);
 +                                 "ANS_KEY", c->name, c->hostname, to_name);
                        return true;
                }
  
 -              return send_request(to->nexthop->connection, "%s", c->buffer);
 +              return send_request(to->nexthop->connection, "%s", request);
        }
  
 -      /* Update our copy of the origin's packet key */
 -      from->outkey = xrealloc(from->outkey, strlen(key) / 2);
 -
 -      from->outkey = xstrdup(key);
 -      from->outkeylength = strlen(key) / 2;
 -      hex2bin(key, from->outkey, from->outkeylength);
 -
 -      from->status.waitingforkey = false;
        /* Check and lookup cipher and digest algorithms */
  
 -      if(cipher) {
 -              from->outcipher = EVP_get_cipherbynid(cipher);
 -
 -              if(!from->outcipher) {
 -                      logger(LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name,
 -                                 from->hostname);
 -                      return false;
 -              }
 -
 -              if(from->outkeylength != from->outcipher->key_len + from->outcipher->iv_len) {
 -                      logger(LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name,
 -                                 from->hostname);
 -                      return false;
 -              }
 -      } else {
 -              from->outcipher = NULL;
 +      if(!cipher_open_by_nid(&from->outcipher, cipher)) {
-               logger(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name, from->hostname);
++              logger(LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name, from->hostname);
 +              return false;
        }
  
 -      from->outmaclength = maclength;
 -
 -      if(digest) {
 -              from->outdigest = EVP_get_digestbynid(digest);
 +      if(strlen(key) / 2 != cipher_keylength(&from->outcipher)) {
-               logger(LOG_ERR, _("Node %s (%s) uses wrong keylength!"), from->name, from->hostname);
++              logger(LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name, from->hostname);
 +              return false;
 +      }
  
 -              if(!from->outdigest) {
 -                      logger(LOG_ERR, "Node %s (%s) uses unknown digest!", from->name,
 -                                 from->hostname);
 -                      return false;
 -              }
 +      if(!digest_open_by_nid(&from->outdigest, digest, maclength)) {
-               logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name, from->hostname);
++              logger(LOG_ERR, "Node %s (%s) uses unknown digest!", from->name, from->hostname);
 +              return false;
 +      }
  
 -              if(from->outmaclength > from->outdigest->md_size || from->outmaclength < 0) {
 -                      logger(LOG_ERR, "Node %s (%s) uses bogus MAC length!",
 -                                 from->name, from->hostname);
 -                      return false;
 -              }
 -      } else {
 -              from->outdigest = NULL;
 +      if(maclength != digest_length(&from->outdigest)) {
-               logger(LOG_ERR, _("Node %s (%s) uses bogus MAC length!"), from->name, from->hostname);
++              logger(LOG_ERR, "Node %s (%s) uses bogus MAC length!", from->name, from->hostname);
 +              return false;
        }
  
        if(compression < 0 || compression > 11) {
@@@ -45,15 -40,12 +40,12 @@@ bool send_status(connection_t *c, int s
        return send_request(c, "%d %d %s", STATUS, statusno, statusstring);
  }
  
- bool status_h(connection_t *c, char *request)
- {
 -bool status_h(connection_t *c) {
++bool status_h(connection_t *c, char *request) {
        int statusno;
        char statusstring[MAX_STRING_SIZE];
  
-       cp();
 -      if(sscanf(c->buffer, "%*d %d " MAX_STRING, &statusno, statusstring) != 2) {
 +      if(sscanf(request, "%*d %d " MAX_STRING, &statusno, statusstring) != 2) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "STATUS",
+               logger(LOG_ERR, "Got bad %s from %s (%s)", "STATUS",
                           c->name, c->hostname);
                return false;
        }
@@@ -74,53 -63,42 +63,38 @@@ bool send_error(connection_t *c, int er
        return send_request(c, "%d %d %s", ERROR, err, errstring);
  }
  
- bool error_h(connection_t *c, char *request)
- {
 -bool error_h(connection_t *c) {
++bool error_h(connection_t *c, char *request) {
        int err;
        char errorstring[MAX_STRING_SIZE];
  
-       cp();
 -      if(sscanf(c->buffer, "%*d %d " MAX_STRING, &err, errorstring) != 2) {
 +      if(sscanf(request, "%*d %d " MAX_STRING, &err, errorstring) != 2) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ERROR",
+               logger(LOG_ERR, "Got bad %s from %s (%s)", "ERROR",
                           c->name, c->hostname);
                return false;
        }
  
-       ifdebug(ERROR) logger(LOG_NOTICE, _("Error message from %s (%s): %d: %s"),
+       ifdebug(ERROR) logger(LOG_NOTICE, "Error message from %s (%s): %d: %s",
                           c->name, c->hostname, err, errorstring);
  
 -      terminate_connection(c, c->status.active);
 -
 -      return true;
 +      return false;
  }
  
- bool send_termreq(connection_t *c)
- {
-       cp();
+ bool send_termreq(connection_t *c) {
        return send_request(c, "%d", TERMREQ);
  }
  
- bool termreq_h(connection_t *c, char *request)
- {
-       cp();
 -bool termreq_h(connection_t *c) {
 -      terminate_connection(c, c->status.active);
--
 -      return true;
++bool termreq_h(connection_t *c, char *request) {
 +      return false;
  }
  
- bool send_ping(connection_t *c)
- {
-       cp();
+ bool send_ping(connection_t *c) {
        c->status.pinged = true;
 -      c->last_ping_time = now;
 +      c->last_ping_time = time(NULL);
  
        return send_request(c, "%d", PING);
  }
  
- bool ping_h(connection_t *c, char *request)
- {
-       cp();
 -bool ping_h(connection_t *c) {
++bool ping_h(connection_t *c, char *request) {
        return send_pong(c);
  }
  
@@@ -131,10 -106,7 +102,7 @@@ bool send_pong(connection_t *c) 
        return send_request(c, "%d", PONG);
  }
  
- bool pong_h(connection_t *c, char *request)
- {
-       cp();
 -bool pong_h(connection_t *c) {
++bool pong_h(connection_t *c, char *request) {
        c->status.pinged = false;
  
        /* Succesful connection, reset timeout if this is an outgoing connection. */
@@@ -163,14 -132,11 +128,11 @@@ bool send_tcppacket(connection_t *c, vp
        return send_meta(c, (char *)packet->data, packet->len);
  }
  
- bool tcppacket_h(connection_t *c, char *request)
- {
 -bool tcppacket_h(connection_t *c) {
++bool tcppacket_h(connection_t *c, char *request) {
        short int len;
  
-       cp();
 -      if(sscanf(c->buffer, "%*d %hd", &len) != 1) {
 +      if(sscanf(request, "%*d %hd", &len) != 1) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "PACKET", c->name,
+               logger(LOG_ERR, "Got bad %s from %s (%s)", "PACKET", c->name,
                           c->hostname);
                return false;
        }
@@@ -45,17 -41,14 +41,14 @@@ bool send_add_subnet(connection_t *c, c
        return send_request(c, "%d %x %s %s", ADD_SUBNET, rand(), subnet->owner->name, netstr);
  }
  
- bool add_subnet_h(connection_t *c, char *request)
- {
 -bool add_subnet_h(connection_t *c) {
++bool add_subnet_h(connection_t *c, char *request) {
        char subnetstr[MAX_STRING_SIZE];
        char name[MAX_STRING_SIZE];
        node_t *owner;
        subnet_t s = {0}, *new;
  
-       cp();
 -      if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
 +      if(sscanf(request, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_SUBNET", c->name,
+               logger(LOG_ERR, "Got bad %s from %s (%s)", "ADD_SUBNET", c->name,
                           c->hostname);
                return false;
        }
@@@ -164,17 -154,14 +154,14 @@@ bool send_del_subnet(connection_t *c, c
        return send_request(c, "%d %x %s %s", DEL_SUBNET, rand(), s->owner->name, netstr);
  }
  
- bool del_subnet_h(connection_t *c, char *request)
- {
 -bool del_subnet_h(connection_t *c) {
++bool del_subnet_h(connection_t *c, char *request) {
        char subnetstr[MAX_STRING_SIZE];
        char name[MAX_STRING_SIZE];
        node_t *owner;
        subnet_t s = {0}, *find;
  
-       cp();
 -      if(sscanf(c->buffer, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
 +      if(sscanf(request, "%*d %*x " MAX_STRING " " MAX_STRING, name, subnetstr) != 2) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_SUBNET", c->name,
+               logger(LOG_ERR, "Got bad %s from %s (%s)", "DEL_SUBNET", c->name,
                           c->hostname);
                return false;
        }
@@@ -74,8 -70,8 +70,8 @@@ bool setup_device(void) 
        sa.sll_protocol = htons(ETH_P_ALL);
        sa.sll_ifindex = ifr.ifr_ifindex;
  
 -      if(bind(device_fd, (struct sockaddr *) &sa, (socklen_t) sizeof(sa))) {
 +      if(bind(device_fd, (struct sockaddr *) &sa, (socklen_t) sizeof sa)) {
-               logger(LOG_ERR, _("Could not bind %s to %s: %s"), device, iface, strerror(errno));
+               logger(LOG_ERR, "Could not bind %s to %s: %s", device, iface, strerror(errno));
                return false;
        }
  
@@@ -94,12 -88,10 +88,10 @@@ void close_device(void) 
  }
  
  bool read_packet(vpn_packet_t *packet) {
 -      int lenin;
 +      int inlen;
  
-       cp();
 -      if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
 +      if((inlen = read(device_fd, packet->data, MTU)) <= 0) {
-               logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
+               logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
                           device, strerror(errno));
                return false;
        }
diff --cc src/route.c
@@@ -51,12 -49,9 +49,11 @@@ static const size_t icmp6_size = sizeof
  static const size_t ns_size = sizeof(struct nd_neighbor_solicit);
  static const size_t opt_size = sizeof(struct nd_opt_hdr);
  
 +static struct event age_subnets_event;
 +
  /* RFC 1071 */
  
- static uint16_t inet_checksum(void *data, int len, uint16_t prevsum)
- {
+ static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) {
        uint16_t *p = data;
        uint32_t checksum = prevsum ^ 0xFFFF;
  
@@@ -105,51 -99,11 +102,46 @@@ static void swap_mac_addresses(vpn_pack
        memcpy(&packet->data[6], &tmp, sizeof tmp);
  }
        
- static void age_subnets(int fd, short events, void *data)
- {
 -static void learn_mac(mac_t *address) {
++static void age_subnets(int fd, short events, void *data) {
 +      subnet_t *s;
 +      connection_t *c;
 +      splay_node_t *node, *next, *node2;
 +      bool left = false;
 +      time_t now = time(NULL);
 +
-       cp();
 +      for(node = myself->subnet_tree->head; node; node = next) {
 +              next = node->next;
 +              s = node->data;
 +              if(s->expires && s->expires < now) {
 +                      ifdebug(TRAFFIC) {
 +                              char netstr[MAXNETSTR];
 +                              if(net2str(netstr, sizeof netstr, s))
-                                       logger(LOG_INFO, _("Subnet %s expired"), netstr);
++                                      logger(LOG_INFO, "Subnet %s expired", netstr);
 +                      }
 +
 +                      for(node2 = connection_tree->head; node2; node2 = node2->next) {
 +                              c = node2->data;
 +                              if(c->status.active)
 +                                      send_del_subnet(c, s);
 +                      }
 +
 +                      subnet_del(myself, s);
 +              } else {
 +                      if(s->expires)
 +                              left = true;
 +              }
 +      }
 +
 +      if(left)
 +              event_add(&age_subnets_event, &(struct timeval){10, 0});
 +}
 +
 +static void learn_mac(mac_t *address)
 +{
        subnet_t *subnet;
 -      avl_node_t *node;
 +      splay_node_t *node;
        connection_t *c;
  
-       cp();
        subnet = lookup_subnet_mac(address);
  
        /* If we don't know this MAC address yet, store it */
@@@ -700,8 -650,8 +666,8 @@@ static void route_arp(node_t *source, v
        /* Check if this is a valid ARP request */
  
        if(ntohs(arp.arp_hrd) != ARPHRD_ETHER || ntohs(arp.arp_pro) != ETH_P_IP ||
 -         arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof(addr) || ntohs(arp.arp_op) != ARPOP_REQUEST) {
 +         arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof addr || ntohs(arp.arp_op) != ARPOP_REQUEST) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: received unknown type ARP request"));
+               ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: received unknown type ARP request");
                return;
        }
  
diff --cc src/route.h
Simple merge
@@@ -118,12 -112,10 +112,10 @@@ void close_device(void) 
  }
  
  bool read_packet(vpn_packet_t *packet) {
 -      int lenin;
 +      int inlen;
  
-       cp();
 -      if((lenin = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
 +      if((inlen = read(device_fd, packet->data + 14, MTU - 14)) <= 0) {
-               logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
+               logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
                           device, strerror(errno));
                return false;
        }
diff --cc src/subnet.c
@@@ -56,11 -54,10 +54,10 @@@ void subnet_cache_flush() 
  
  /* Subnet comparison */
  
- static int subnet_compare_mac(const subnet_t *a, const subnet_t *b)
- {
+ static int subnet_compare_mac(const subnet_t *a, const subnet_t *b) {
        int result;
  
 -      result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t));
 +      result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof a->net.mac.address);
  
        if(result)
                return result;
@@@ -145,34 -138,22 +138,22 @@@ int subnet_compare(const subnet_t *a, c
  
  /* Initialising trees */
  
- void init_subnets(void)
- {
-       cp();
+ void init_subnets(void) {
 -      subnet_tree = avl_alloc_tree((avl_compare_t) subnet_compare, (avl_action_t) free_subnet);
 +      subnet_tree = splay_alloc_tree((splay_compare_t) subnet_compare, (splay_action_t) free_subnet);
  
        subnet_cache_flush();
  }
  
- void exit_subnets(void)
- {
-       cp();
+ void exit_subnets(void) {
 -      avl_delete_tree(subnet_tree);
 +      splay_delete_tree(subnet_tree);
  }
  
- splay_tree_t *new_subnet_tree(void)
- {
-       cp();
 -avl_tree_t *new_subnet_tree(void) {
 -      return avl_alloc_tree((avl_compare_t) subnet_compare, NULL);
++splay_tree_t *new_subnet_tree(void) {
 +      return splay_alloc_tree((splay_compare_t) subnet_compare, NULL);
  }
  
- void free_subnet_tree(splay_tree_t *subnet_tree)
- {
-       cp();
 -void free_subnet_tree(avl_tree_t *subnet_tree) {
 -      avl_delete_tree(subnet_tree);
++void free_subnet_tree(splay_tree_t *subnet_tree) {
 +      splay_delete_tree(subnet_tree);
  }
  
  /* Allocating and freeing space for subnets */
@@@ -193,24 -168,18 +168,18 @@@ void free_subnet(subnet_t *subnet) 
  
  /* Adding and removing subnets */
  
- void subnet_add(node_t *n, subnet_t *subnet)
- {
-       cp();
+ void subnet_add(node_t *n, subnet_t *subnet) {
        subnet->owner = n;
  
 -      avl_insert(subnet_tree, subnet);
 -      avl_insert(n->subnet_tree, subnet);
 +      splay_insert(subnet_tree, subnet);
 +      splay_insert(n->subnet_tree, subnet);
  
        subnet_cache_flush();
  }
  
- void subnet_del(node_t *n, subnet_t *subnet)
- {
-       cp();
+ void subnet_del(node_t *n, subnet_t *subnet) {
 -      avl_delete(n->subnet_tree, subnet);
 -      avl_delete(subnet_tree, subnet);
 +      splay_delete(n->subnet_tree, subnet);
 +      splay_delete(subnet_tree, subnet);
  
        subnet_cache_flush();
  }
@@@ -357,19 -319,13 +319,13 @@@ bool net2str(char *netstr, int len, con
  
  /* Subnet lookup routines */
  
- subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet)
- {
-       cp();
+ subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet) {
 -      return avl_search(owner->subnet_tree, subnet);
 +      return splay_search(owner->subnet_tree, subnet);
  }
  
- subnet_t *lookup_subnet_mac(const mac_t *address)
- {
+ subnet_t *lookup_subnet_mac(const mac_t *address) {
        subnet_t *p, subnet = {0};
  
-       cp();
        subnet.type = SUBNET_MAC;
        subnet.net.mac.address = *address;
        subnet.owner = NULL;
        return p;
  }
  
- subnet_t *lookup_subnet_ipv4(const ipv4_t *address)
- {
+ subnet_t *lookup_subnet_ipv4(const ipv4_t *address) {
        subnet_t *p, *r = NULL, subnet = {0};
 -      avl_node_t *n;
 +      splay_node_t *n;
        int i;
  
-       cp();
        // Check if this address is cached
  
        for(i = 0; i < 2; i++) {
        return r;
  }
  
- subnet_t *lookup_subnet_ipv6(const ipv6_t *address)
- {
+ subnet_t *lookup_subnet_ipv6(const ipv6_t *address) {
        subnet_t *p, *r = NULL, subnet = {0};
 -      avl_node_t *n;
 +      splay_node_t *n;
        int i;
  
-       cp();
        // Check if this address is cached
  
        for(i = 0; i < 2; i++) {
@@@ -540,22 -490,19 +490,19 @@@ void subnet_update(node_t *owner, subne
                free(envp[i]);
  }
  
- int dump_subnets(struct evbuffer *out)
- {
 -void dump_subnets(void) {
++int dump_subnets(struct evbuffer *out) {
        char netstr[MAXNETSTR];
        subnet_t *subnet;
 -      avl_node_t *node;
 -
 -      logger(LOG_DEBUG, "Subnet list:");
 +      splay_node_t *node;
  
-       cp();
        for(node = subnet_tree->head; node; node = node->next) {
                subnet = node->data;
                if(!net2str(netstr, sizeof netstr, subnet))
                        continue;
-               if(evbuffer_add_printf(out, _(" %s owner %s\n"),
 -              logger(LOG_DEBUG, " %s owner %s", netstr, subnet->owner->name);
++              if(evbuffer_add_printf(out, " %s owner %s\n",
 +                                                         netstr, subnet->owner->name) == -1)
 +                      return errno;
        }
  
 -      logger(LOG_DEBUG, "End of subnet list.");
 +      return 0;
  }
diff --cc src/subnet.h
Simple merge
diff --cc src/tincd.c
@@@ -105,25 -118,26 +105,24 @@@ static struct WSAData wsa_state
  CRITICAL_SECTION mutex;
  #endif
  
- static void usage(bool status)
- {
+ static void usage(bool status) {
        if(status)
-               fprintf(stderr, _("Try `%s --help\' for more information.\n"),
+               fprintf(stderr, "Try `%s --help\' for more information.\n",
                                program_name);
        else {
-               printf(_("Usage: %s [option]...\n\n"), program_name);
-               printf(_(       "  -c, --config=DIR              Read configuration options from DIR.\n"
+               printf("Usage: %s [option]...\n\n", program_name);
 -              printf("  -c, --config=DIR           Read configuration options from DIR.\n"
 -                              "  -D, --no-detach            Don't fork and detach.\n"
 -                              "  -d, --debug[=LEVEL]        Increase debug level or set it to LEVEL.\n"
 -                              "  -k, --kill[=SIGNAL]        Attempt to kill a running tincd and exit.\n"
 -                              "  -n, --net=NETNAME          Connect to net NETNAME.\n"
 -                              "  -K, --generate-keys[=BITS] Generate public/private RSA keypair.\n"
 -                              "  -L, --mlock                Lock tinc into main memory.\n"
 -                              "      --logfile[=FILENAME]   Write log entries to a logfile.\n"
 -                              "      --pidfile=FILENAME     Write PID to FILENAME.\n"
 -                              "  -R, --chroot               chroot to NET dir at startup.\n"
 -                              "  -U, --user=USER            setuid to given USER at startup.\n"
 -                              "      --help                 Display this help and exit.\n"
 -                              "      --version              Output version information and exit.\n\n");
++              printf( "  -c, --config=DIR              Read configuration options from DIR.\n"
 +                              "  -D, --no-detach               Don't fork and detach.\n"
 +                              "  -d, --debug[=LEVEL]           Increase debug level or set it to LEVEL.\n"
 +                              "  -n, --net=NETNAME             Connect to net NETNAME.\n"
 +                              "  -L, --mlock                   Lock tinc into main memory.\n"
 +                              "      --logfile[=FILENAME]      Write log entries to a logfile.\n"
 +                              "      --controlsocket=FILENAME  Open control socket at FILENAME.\n"
 +                              "      --bypass-security         Disables meta protocol security, for debugging.\n"
 +                              "  -R, --chroot                  chroot to NET dir at startup.\n"
 +                              "  -U, --user=USER               setuid to given USER at startup.\n"                            "      --help                    Display this help and exit.\n"
-                               "      --version                 Output version information and exit.\n\n"));
-               printf(_("Report bugs to tinc@tinc-vpn.org.\n"));
++                              "      --version                 Output version information and exit.\n\n");
+               printf("Report bugs to tinc@tinc-vpn.org.\n");
        }
  }
  
@@@ -353,16 -514,11 +345,16 @@@ int main(int argc, char **argv) 
                return 0;
        }
  
 -      if(kill_tincd)
 -              return !kill_other(kill_tincd);
 -
        openlogger("tinc", use_logfile?LOGMODE_FILE:LOGMODE_STDERR);
  
-               logger(LOG_ERR, _("Error initializing libevent!"));
 +      if(!event_init()) {
++              logger(LOG_ERR, "Error initializing libevent!");
 +              return 1;
 +      }
 +
 +      if(!init_control())
 +              return 1;
 +
        g_argv = argv;
  
        init_configuration(&config_tree);
@@@ -454,13 -618,17 +445,13 @@@ int main2(int argc, char **argv) 
        close_network_connections();
  
  end:
-       logger(LOG_NOTICE, _("Terminating"));
+       logger(LOG_NOTICE, "Terminating");
  
  #ifndef HAVE_MINGW
 -      remove_pid(pidfilename);
 +      exit_control();
  #endif
  
 -      EVP_cleanup();
 -      ENGINE_cleanup();
 -      CRYPTO_cleanup_all_ex_data();
 -      ERR_remove_state(0);
 -      ERR_free_strings();
 +      crypto_exit();
  
        exit_configuration(&config_tree);
        free_names();
@@@ -175,10 -169,8 +169,8 @@@ void close_device(void) 
  }
  
  bool read_packet(vpn_packet_t *packet) {
 -      int lenin;
 +      int inlen;
  
-       cp();
        switch(state) {
                case 0: {
                        struct sockaddr sa;
                }
  
                case 1: {
 -                      if((lenin = read(request_fd, &request, sizeof request)) != sizeof request) {
 +                      if((inlen = read(request_fd, &request, sizeof request)) != sizeof request) {
-                               logger(LOG_ERR, _("Error while reading request from %s %s: %s"), device_info,
+                               logger(LOG_ERR, "Error while reading request from %s %s: %s", device_info,
                                           device, strerror(errno));
                                running = false;
                                return false;
                }
  
                case 2: {
 -                      if((lenin = read(data_fd, packet->data, MTU)) <= 0) {
 +                      if((inlen = read(data_fd, packet->data, MTU)) <= 0) {
-                               logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
+                               logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
                                           device, strerror(errno));
                                running = false;
                                return false;