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 --combined 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.
  
   * Fixed a memory leak that occured when connections were closed.
  
+  Thanks to Max Rijevski for his contributions to this version of tinc.
  Version 1.0.8                May 16 2007
  
   * Fixed some memory and resource leaks.
  
   * Made network sockets non-blocking under Windows.
  
+  Thanks to Scott Lamb and "dnk" for their contributions to this version of tinc.
  Version 1.0.7                Jan  5 2007
  
   * Fixed a bug that caused slow network speeds on Windows.
@@@ -54,6 -85,8 +91,8 @@@ version 1.0.5                Nov 14 200
  
   * Support LZO 2.0 and later.
  
+  Thanks to Scott Lamb for his contributions to this version of tinc.
  version 1.0.4                May  4 2005
  
   * Fix switch and hub modes.
diff --combined configure.in
@@@ -1,18 -1,16 +1,17 @@@
  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
  
- AM_GNU_GETTEXT([external])
- AM_GNU_GETTEXT_VERSION(0.14.1)
+ # Enable GNU extensions.
+ # Define this here, not in acconfig's @TOP@ section, since definitions
+ # in the latter don't make it into the configure-time tests.
+ AC_GNU_SOURCE
  AC_DEFINE([__USE_BSD], 1, [Enable BSD extensions])
  
  ALL_LINGUAS="nl"
@@@ -26,7 -24,7 +25,7 @@@ AC_PROG_RANLI
  
  dnl Check and set OS
  
#AC_CANONICAL_HOST
+ AC_CANONICAL_HOST
  
  case $host_os in
    *linux*)
@@@ -95,12 -93,14 +94,12 @@@ if test -d /sw/lib ; the
    LIBS="$LIBS -L/sw/lib"
  fi
  
 -dnl Checks for libraries.
 -
  dnl Checks for header files.
  dnl We do this in multiple stages, because unlike Linux all the other operating systems really suck and don't include their own dependencies.
  
  AC_HEADER_STDC
  AC_CHECK_HEADERS([stdbool.h syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/socket.h sys/time.h sys/uio.h sys/wait.h netdb.h arpa/inet.h])
 -AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h],
 +AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h time.h],
    [], [], [#include "have.h"]
  )
  AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h],
@@@ -128,7 -128,7 +127,7 @@@ dnl Checks for library functions
  AC_FUNC_MEMCMP
  AC_FUNC_ALLOCA
  AC_TYPE_SIGNAL
 -AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall putenv random select strdup strerror strsignal strtol system unsetenv vsyslog writev],
 +AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall putenv random select strdup strerror strsignal strtol system time unsetenv vsyslog writev],
    [], [], [#include "have.h"]
  )
  AC_FUNC_MALLOC
@@@ -151,35 -151,18 +150,29 @@@ AC_CACHE_SAV
  
  dnl These are defined in files in m4/
  
 -tinc_OPENSSL
 +AC_ARG_WITH(libgcrypt, AC_HELP_STRING([--with-libgcrypt], [enable use of libgcrypt instead of OpenSSL])], [])
 +
 +tinc_LIBEVENT
  tinc_ZLIB
  tinc_LZO
  
 +if test "$with_libgcrypt" = yes; then
 +      AM_PATH_LIBGCRYPT([1.4.0], [], [])
 +      ln -sf gcrypt/cipher.c gcrypt/cipher.h gcrypt/crypto.c gcrypt/crypto.h gcrypt/digest.c gcrypt/digest.h gcrypt/rsa.c gcrypt/rsa.h gcrypt/rsagen.c gcrypt/rsagen.h src/
 +else
 +      tinc_OPENSSL
 +      ln -sf openssl/cipher.c openssl/cipher.h openssl/crypto.c openssl/crypto.h openssl/digest.c openssl/digest.h openssl/rsa.c openssl/rsa.h openssl/rsagen.c openssl/rsagen.h src/
 +fi
 +      
 +
  dnl Check if support for jumbograms is requested 
  AC_ARG_ENABLE(jumbograms,
    AS_HELP_STRING([--enable-jumbograms], [enable support for jumbograms (packets up to 9000 bytes)]),
    [ AC_DEFINE(ENABLE_JUMBOGRAMS, 1, [Support for jumbograms (packets up to 9000 bytes)]) ]
  )
  
- dnl Check if checkpoint tracing has to be enabled
- AC_ARG_ENABLE(tracing,
-   AS_HELP_STRING([--enable-tracing], [enable checkpoint tracing (debugging only)]),
-   [ AC_DEFINE(ENABLE_TRACING, 1, [Checkpoint tracing]) ]
- )
  AC_SUBST(INCLUDES)
  
- AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile lib/Makefile po/Makefile.in m4/Makefile])
+ AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile lib/Makefile m4/Makefile])
  
  AC_OUTPUT
diff --combined doc/tinc.texi
@@@ -1,5 -1,4 +1,4 @@@
  \input texinfo   @c -*-texinfo-*-
- @c $Id$
  @c %**start of header
  @setfilename tinc.info
  @settitle tinc Manual
@@@ -20,8 -19,6 +19,6 @@@ Copyright @copyright{} 1998-2009 Ivo Ti
  Guus Sliepen <guus@@tinc-vpn.org> and
  Wessel Dankers <wsl@@tinc-vpn.org>.
  
- $Id$
  Permission is granted to make and distribute verbatim copies of this
  manual provided the copyright notice and this permission notice are
  preserved on all copies.
@@@ -47,8 -44,6 +44,6 @@@ Copyright @copyright{} 1998-2009 Ivo Ti
  Guus Sliepen <guus@@tinc-vpn.org> and
  Wessel Dankers <wsl@@tinc-vpn.org>.
  
- $Id$
  Permission is granted to make and distribute verbatim copies of this
  manual provided the copyright notice and this permission notice are
  preserved on all copies.
@@@ -71,7 -66,6 +66,7 @@@ permission notice identical to this one
  * Installation::
  * Configuration::
  * Running tinc::
 +* Controlling tinc::
  * Technical information::
  * Platform specific information::
  * About us::
@@@ -344,7 -338,6 +339,7 @@@ having them installed, configure will g
  * OpenSSL::
  * zlib::
  * lzo::
 +* libevent::
  @end menu
  
  
@@@ -457,27 -450,6 +452,27 @@@ make sure you build development and run
  default).
  
  
 +@c ==================================================================
 +@node       libevent
 +@subsection libevent
 +
 +@cindex libevent
 +For the main event loop, tinc uses the libevent library.
 +
 +If this library is not installed, you wil get an error when configuring
 +tinc for build.
 +
 +You can use your operating system's package manager to install this if
 +available.  Make sure you install the development AND runtime versions
 +of this package.
 +
 +If you have to install libevent manually, you can get the source code
 +from @url{http://monkey.org/~provos/libevent/}.  Instructions on how to configure,
 +build and install this package are included within the package.  Please
 +make sure you build development and runtime libraries (which is the
 +default).
 +
 +
  @c
  @c
  @c
@@@ -945,7 -917,7 +940,7 @@@ accidental eavesdropping if you are edi
  @cindex PrivateKeyFile
  @item PrivateKeyFile = <@var{path}> (@file{@value{sysconfdir}/tinc/@var{netname}/rsa_key.priv})
  This is the full path name of the RSA private key file that was
 -generated by @samp{tincd --generate-keys}.  It must be a full path, not a
 +generated by @samp{tincctl generate-keys}.  It must be a full path, not a
  relative directory.
  
  Note that there must be exactly one of PrivateKey
@@@ -1031,7 -1003,7 +1026,7 @@@ This is the RSA public key for this hos
  @cindex PublicKeyFile
  @item PublicKeyFile = <@var{path}> [obsolete]
  This is the full path name of the RSA public key file that was generated
 -by @samp{tincd --generate-keys}.  It must be a full path, not a relative
 +by @samp{tincctl generate-keys}.  It must be a full path, not a relative
  directory.
  
  @cindex PEM format
@@@ -1214,7 -1186,7 +1209,7 @@@ Now that you have already created the m
  you can easily create a public/private keypair by entering the following command:
  
  @example
 -tincd -n @var{netname} -K
 +tincctl -n @var{netname} generate-keys
  @end example
  
  Tinc will generate a public and a private key and ask you where to put them.
@@@ -1443,7 -1415,7 +1438,7 @@@ Address = 4.5.6.
  A, B, C and D all have generated a public/private keypair with the following command:
  
  @example
 -tincd -n company -K
 +tincctl -n company generate-keys
  @end example
  
  The private key is stored in @file{@value{sysconfdir}/tinc/company/rsa_key.priv},
@@@ -1509,12 -1481,20 +1504,12 @@@ This will also disable the automatic re
  Set debug level to @var{level}.  The higher the debug level, the more gets
  logged.  Everything goes via syslog.
  
 -@item -k, --kill[=@var{signal}]
 -Attempt to kill a running tincd (optionally with the specified @var{signal} instead of SIGTERM) and exit.
 -Use it in conjunction with the -n option to make sure you kill the right tinc daemon.
 -Under native Windows the optional argument is ignored,
 -the service will always be stopped and removed.
 -
  @item -n, --net=@var{netname}
  Use configuration for net @var{netname}. @xref{Multiple networks}.
  
 -@item -K, --generate-keys[=@var{bits}]
 -Generate public/private keypair of @var{bits} length. If @var{bits} is not specified,
 -1024 is the default. tinc will ask where you want to store the files,
 -but will default to the configuration directory (you can use the -c or -n option
 -in combination with -K). After that, tinc will quit.
 +@item --controlsocket=@var{filename}
 +Open control socket at @var{filename}. If unspecified, the default is
 +@file{@value{localstatedir}/run/tinc.@var{netname}.control}.
  
  @item -L, --mlock
  Lock tinc into main memory.
@@@ -1524,6 -1504,9 +1519,6 @@@ This will prevent sensitive data like s
  Write log entries to a file instead of to the system logging facility.
  If @var{file} is omitted, the default is @file{@value{localstatedir}/log/tinc.@var{netname}.log}.
  
 -@item --pidfile=@var{file}
 -Write PID to @var{file} instead of @file{@value{localstatedir}/run/tinc.@var{netname}.pid}.
 -
  @item --bypass-security
  Disables encryption and authentication.
  Only useful for debugging.
@@@ -1563,11 -1546,31 +1558,11 @@@ You can also send the following signal
  @c from the manpage
  @table @samp
  
 -@item ALRM
 -Forces tinc to try to connect to all uplinks immediately.
 -Usually tinc attempts to do this itself,
 -but increases the time it waits between the attempts each time it failed,
 -and if tinc didn't succeed to connect to an uplink the first time after it started,
 -it defaults to the maximum time of 15 minutes.
 -
  @item HUP
  Partially rereads configuration files.
  Connections to hosts whose host config file are removed are closed.
  New outgoing connections specified in @file{tinc.conf} will be made.
  
 -@item INT
 -Temporarily increases debug level to 5.
 -Send this signal again to revert to the original level.
 -
 -@item USR1
 -Dumps the connection list to syslog.
 -
 -@item USR2
 -Dumps virtual network device statistics, all known nodes, edges and subnets to syslog.
 -
 -@item WINCH
 -Purges all information remembered about unreachable nodes.
 -
  @end table
  
  @c ==================================================================
@@@ -1762,110 -1765,6 +1757,110 @@@ Be sure to include the following inform
  @item The output of any command that fails to work as it should (like ping or traceroute).
  @end itemize
  
 +@c ==================================================================
 +@node    Controlling tinc
 +@chapter Controlling tinc
 +
 +You can control and inspect a running @samp{tincd} through the @samp{tincctl}
 +command. A quick example:
 +
 +@example
 +tincctl -n @var{netname} reload
 +@end example
 +
 +@menu
 +* tincctl runtime options::
 +* tincctl commands::
 +@end menu
 +
 +
 +@c ==================================================================
 +@node    tincctl runtime options
 +@section tincctl runtime options
 +
 +@c from the manpage
 +@table @option
 +@item -c, --config=@var{path}
 +Read configuration options from the directory @var{path}.  The default is
 +@file{@value{sysconfdir}/tinc/@var{netname}/}.
 +
 +@item -n, --net=@var{netname}
 +Use configuration for net @var{netname}. @xref{Multiple networks}.
 +
 +@item --controlsocket=@var{filename}
 +Open control socket at @var{filename}. If unspecified, the default is
 +@file{@value{localstatedir}/run/tinc.@var{netname}.control}.
 +
 +@item --help
 +Display a short reminder of runtime options and commands, then terminate.
 +
 +@item --version
 +Output version information and exit.
 +
 +@end table
 +
 +
 +@c ==================================================================
 +@node    tincctl commands
 +@section tincctl commands
 +
 +@c from the manpage
 +@table @code
 +
 +@item start
 +Start @samp{tincd}.
 +
 +@item stop
 +Stop @samp{tincd}.
 +
 +@item restart
 +Restart @samp{tincd}.
 +
 +@item reload
 +Partially rereads configuration files. Connections to hosts whose host
 +config files are removed are closed. New outgoing connections specified
 +in @file{tinc.conf} will be made.
 +
 +@item pid
 +Shows the PID of the currently running @samp{tincd}.
 +
 +@item generate-keys [@var{bits}]
 +Generate public/private keypair of @var{bits} length. If @var{bits} is not specified,
 +1024 is the default. tinc will ask where you want to store the files,
 +but will default to the configuration directory (you can use the -c or -n
 +option).
 +
 +@item dump nodes
 +Dump a list of all known nodes in the VPN.
 +
 +@item dump edges
 +Dump a list of all known connections in the VPN.
 +
 +@item dump subnets
 +Dump a list of all known subnets in the VPN.
 +
 +@item dump connections
 +Dump a list of all meta connections with ourself.
 +
 +@item dump graph
 +Dump a graph of the VPN in dotty format.
 +
 +@item purge
 +Purges all information remembered about unreachable nodes.
 +
 +@item debug @var{level}
 +Sets debug level to @var{level}.
 +
 +@item retry
 +Forces tinc to try to connect to all uplinks immediately.
 +Usually tinc attempts to do this itself,
 +but increases the time it waits between the attempts each time it failed,
 +and if tinc didn't succeed to connect to an uplink the first time after it started,
 +it defaults to the maximum time of 15 minutes.
 +
 +@end table
 +
 +
  @c ==================================================================
  @node    Technical information
  @chapter Technical information
@@@ -2459,7 -2358,7 +2454,7 @@@ and join channel #tinc
  @section Authors
  
  @table @asis
- @item Ivo Timmermans (zarq) (@email{ivo@@tinc-vpn.org})
+ @item Ivo Timmermans (zarq)
  @item Guus Sliepen (guus) (@email{guus@@tinc-vpn.org})
  @end table
  
diff --combined doc/tincd.8.in
@@@ -1,4 -1,4 +1,4 @@@
- .Dd 2002-03-25
+ .Dd 2009-05-18
  .Dt TINCD 8
  .\" Manual page created by:
  .\" Ivo Timmermans
@@@ -8,13 -8,16 +8,13 @@@
  .Nd tinc VPN daemon
  .Sh SYNOPSIS
  .Nm
 -.Op Fl cdDkKnLRU
 +.Op Fl cdDKnLRU
  .Op Fl -config Ns = Ns Ar DIR
  .Op Fl -no-detach
  .Op Fl -debug Ns Op = Ns Ar LEVEL
 -.Op Fl -kill Ns Op = Ns Ar SIGNAL
  .Op Fl -net Ns = Ns Ar NETNAME
 -.Op Fl -generate-keys Ns Op = Ns Ar BITS
  .Op Fl -mlock
  .Op Fl -logfile Ns Op = Ns Ar FILE
 -.Op Fl -pidfile Ns = Ns Ar FILE
  .Op Fl -bypass-security
  .Op Fl -chroot
  .Op Fl -user Ns = Ns Ar USER
@@@ -50,9 -53,24 +50,9 @@@ If not mentioned otherwise, this will s
  Increase debug level or set it to
  .Ar LEVEL
  (see below).
 -.It Fl k, -kill Ns Op = Ns Ar SIGNAL
 -Attempt to kill a running
 -.Nm
 -(optionally with the specified
 -.Ar SIGNAL
 -instead of SIGTERM) and exit.
 -Under Windows (not Cygwin) the optional argument is ignored,
 -the service will always be stopped and removed.
  .It Fl n, -net Ns = Ns Ar NETNAME
  Connect to net
  .Ar NETNAME .
 -.It Fl K, -generate-keys Ns Op = Ns Ar BITS
 -Generate public/private RSA keypair and exit.
 -If
 -.Ar BITS
 -is omitted, the default length will be 1024 bits.
 -When saving keys to existing files, tinc will not delete the old keys,
 -you have to remove them manually.
  .It Fl L, -mlock
  Lock tinc into main memory.
  This will prevent sensitive data like shared private keys to be written to the system swap files/partitions.
@@@ -62,13 -80,12 +62,13 @@@ I
  .Ar FILE
  is omitted, the default is
  .Pa @localstatedir@/log/tinc. Ns Ar NETNAME Ns Pa .log.
 -.It Fl -pidfile Ns = Ns Ar FILE
 -Write PID to
 +.It Fl -controlsocket Ns = Ns Ar FILENAME
 +Open control socket at
 +.Ar FILENAME .
 +If
  .Ar FILE
 -instead of
 -.Pa @localstatedir@/run/tinc. Ns Ar NETNAME Ns Pa .pid.
 -Under Windows this option will be ignored.
 +is omitted, the default is
 +.Pa @localstatedir@/run/tinc. Ns Ar NETNAME Ns Pa .control.
  .It Fl -bypass-security
  Disables encryption and authentication of the meta protocol.
  Only useful for debugging.
@@@ -87,12 -104,33 +87,12 @@@ Output version information and exit
  .El
  .Sh SIGNALS
  .Bl -tag -width indent
 -.It ALRM
 -Forces
 -.Nm
 -to try to connect to all uplinks immediately.
 -Usually
 -.Nm
 -attempts to do this itself,
 -but increases the time it waits between the attempts each time it failed,
 -and if
 -.Nm
 -didn't succeed to connect to an uplink the first time after it started,
 -it defaults to the maximum time of 15 minutes.
  .It HUP
  Partially rereads configuration files.
  Connections to hosts whose host config file are removed are closed.
  New outgoing connections specified in
  .Pa tinc.conf
  will be made.
 -.It INT
 -Temporarily increases debug level to 5.
 -Send this signal again to revert to the original level.
 -.It USR1
 -Dumps the connection list to syslog.
 -.It USR2
 -Dumps virtual network device statistics, all known nodes, edges and subnets to syslog.
 -.It WINCH
 -Purges all information remembered about unreachable nodes.
  .El
  .Sh DEBUG LEVELS
  The tinc daemon can send a lot of messages to the syslog.
@@@ -139,7 -177,6 +139,7 @@@ If you find any bugs, report them to ti
  .Sh TODO
  A lot, especially security auditing.
  .Sh SEE ALSO
 +.Xr tincctl 8 ,
  .Xr tinc.conf 5 ,
  .Pa http://www.tinc-vpn.org/ ,
  .Pa http://www.cabal.org/ .
diff --combined have.h
--- 1/have.h
--- 2/have.h
+++ b/have.h
@@@ -1,7 -1,7 +1,7 @@@
  /*
      have.h -- include headers which are known to exist
      Copyright (C) 1998-2005 Ivo Timmermans
-                   2003-2006 Guus Sliepen <guus@tinc-vpn.org>
+                   2003-2009 Guus Sliepen <guus@tinc-vpn.org>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
@@@ -13,9 -13,9 +13,9 @@@
      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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+     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_HAVE_H__
  #include <sys/time.h>
  #endif
  
 +#ifdef HAVE_TIME_H
 +#include <time.h>
 +#endif
 +
  #ifdef HAVE_SYS_TYPES_H
  #include <sys/types.h>
  #endif
diff --combined lib/Makefile.am
@@@ -1,15 -1,14 +1,14 @@@
  ## Process this file with automake to produce Makefile.in
- # $Id$
  
  noinst_LIBRARIES = libvpn.a
  
  INCLUDES = @INCLUDES@ -I. -I$(top_builddir)
  
 -libvpn_a_SOURCES = xmalloc.c pidfile.c utils.c getopt.c getopt1.c list.c avl_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c
 +libvpn_a_SOURCES = xmalloc.c utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c
  
  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 --combined lib/avl_tree.c
@@@ -15,9 -15,9 +15,9 @@@
      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.
+     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.
  
      Original AVL tree library by Michael H. Buselli <cosine@cosine.org>.
  
@@@ -28,8 -28,6 +28,6 @@@
      Cleaned up and incorporated some of the ideas from the red-black tree
      library for inclusion into tinc (http://www.tinc-vpn.org/) by
      Guus Sliepen <guus@tinc-vpn.org>.
-     $Id$
  */
  
  #include "system.h"
@@@ -54,7 -52,8 +52,7 @@@
  #ifndef AVL_DEPTH
  static int lg(unsigned int u) __attribute__ ((__const__));
  
 -static int lg(unsigned int u)
 -{
 +static int lg(unsigned int u) {
        int r = 1;
  
        if(!u)
@@@ -89,7 -88,8 +87,7 @@@
  
  /* Internal helper functions */
  
 -static int avl_check_balance(const avl_node_t *node)
 -{
 +static int avl_check_balance(const avl_node_t *node) {
  #ifdef AVL_DEPTH
        int d;
  
  #endif
  }
  
 -static void avl_rebalance(avl_tree_t *tree, avl_node_t *node)
 -{
 +static void avl_rebalance(avl_tree_t *tree, avl_node_t *node) {
        avl_node_t *child;
        avl_node_t *gchild;
        avl_node_t *parent;
  
  /* (De)constructors */
  
 -avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete)
 -{
 +avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete) {
        avl_tree_t *tree;
  
        tree = xmalloc_and_zero(sizeof(avl_tree_t));
        return tree;
  }
  
 -void avl_free_tree(avl_tree_t *tree)
 -{
 +void avl_free_tree(avl_tree_t *tree) {
        free(tree);
  }
  
 -avl_node_t *avl_alloc_node(void)
 -{
 +avl_node_t *avl_alloc_node(void) {
        return xmalloc_and_zero(sizeof(avl_node_t));
  }
  
 -void avl_free_node(avl_tree_t *tree, avl_node_t *node)
 -{
 +void avl_free_node(avl_tree_t *tree, avl_node_t *node) {
        if(node->data && tree->delete)
                tree->delete(node->data);
  
  
  /* Searching */
  
 -void *avl_search(const avl_tree_t *tree, const void *data)
 -{
 +void *avl_search(const avl_tree_t *tree, const void *data) {
        avl_node_t *node;
  
        node = avl_search_node(tree, data);
        return node ? node->data : NULL;
  }
  
 -void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result)
 -{
 +void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result) {
        avl_node_t *node;
  
        node = avl_search_closest_node(tree, data, result);
        return node ? node->data : NULL;
  }
  
 -void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data)
 -{
 +void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data) {
        avl_node_t *node;
  
        node = avl_search_closest_smaller_node(tree, data);
        return node ? node->data : NULL;
  }
  
 -void *avl_search_closest_greater(const avl_tree_t *tree, const void *data)
 -{
 +void *avl_search_closest_greater(const avl_tree_t *tree, const void *data) {
        avl_node_t *node;
  
        node = avl_search_closest_greater_node(tree, data);
        return node ? node->data : NULL;
  }
  
 -avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data)
 -{
 +avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data) {
        avl_node_t *node;
        int result;
  
  }
  
  avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data,
 -                                                                      int *result)
 -{
 +                                                                      int *result) {
        avl_node_t *node;
        int c;
  
  }
  
  avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *tree,
 -                                                                                      const void *data)
 -{
 +                                                                                      const void *data) {
        avl_node_t *node;
        int result;
  
  }
  
  avl_node_t *avl_search_closest_greater_node(const avl_tree_t *tree,
 -                                                                                      const void *data)
 -{
 +                                                                                      const void *data) {
        avl_node_t *node;
        int result;
  
  
  /* Insertion and deletion */
  
 -avl_node_t *avl_insert(avl_tree_t *tree, void *data)
 -{
 +avl_node_t *avl_insert(avl_tree_t *tree, void *data) {
        avl_node_t *closest, *new;
        int result;
  
        return new;
  }
  
 -avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node)
 -{
 +avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node) {
        avl_node_t *closest;
        int result;
  
        return node;
  }
  
 -void avl_insert_top(avl_tree_t *tree, avl_node_t *node)
 -{
 +void avl_insert_top(avl_tree_t *tree, avl_node_t *node) {
        node->prev = node->next = node->parent = NULL;
        tree->head = tree->tail = tree->root = node;
  }
  
  void avl_insert_before(avl_tree_t *tree, avl_node_t *before,
 -                                         avl_node_t *node)
 -{
 +                                         avl_node_t *node) {
        if(!before) {
                if(tree->tail)
                        avl_insert_after(tree, tree->tail, node);
        avl_rebalance(tree, before);
  }
  
 -void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node)
 -{
 +void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node) {
        if(!after) {
                if(tree->head)
                        avl_insert_before(tree, tree->head, node);
        avl_rebalance(tree, after);
  }
  
 -avl_node_t *avl_unlink(avl_tree_t *tree, void *data)
 -{
 +avl_node_t *avl_unlink(avl_tree_t *tree, void *data) {
        avl_node_t *node;
  
        node = avl_search_node(tree, data);
        return node;
  }
  
 -void avl_unlink_node(avl_tree_t *tree, avl_node_t *node)
 -{
 +void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) {
        avl_node_t *parent;
        avl_node_t **superparent;
        avl_node_t *subst, *left, *right;
  #endif
  }
  
 -void avl_delete_node(avl_tree_t *tree, avl_node_t *node)
 -{
 +void avl_delete_node(avl_tree_t *tree, avl_node_t *node) {
        avl_unlink_node(tree, node);
        avl_free_node(tree, node);
  }
  
 -void avl_delete(avl_tree_t *tree, void *data)
 -{
 +void avl_delete(avl_tree_t *tree, void *data) {
        avl_node_t *node;
  
        node = avl_search_node(tree, data);
  
  /* Fast tree cleanup */
  
 -void avl_delete_tree(avl_tree_t *tree)
 -{
 +void avl_delete_tree(avl_tree_t *tree) {
        avl_node_t *node, *next;
  
        for(node = tree->head; node; node = next) {
  
  /* Tree walking */
  
 -void avl_foreach(const avl_tree_t *tree, avl_action_t action)
 -{
 +void avl_foreach(const avl_tree_t *tree, avl_action_t action) {
        avl_node_t *node, *next;
  
        for(node = tree->head; node; node = next) {
        }
  }
  
 -void avl_foreach_node(const avl_tree_t *tree, avl_action_t action)
 -{
 +void avl_foreach_node(const avl_tree_t *tree, avl_action_t action) {
        avl_node_t *node, *next;
  
        for(node = tree->head; node; node = next) {
  /* Indexing */
  
  #ifdef AVL_COUNT
 -unsigned int avl_count(const avl_tree_t *tree)
 -{
 +unsigned int avl_count(const avl_tree_t *tree) {
        return AVL_NODE_COUNT(tree->root);
  }
  
 -avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index)
 -{
 +avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index) {
        avl_node_t *node;
        unsigned int c;
  
        return NULL;
  }
  
 -unsigned int avl_index(const avl_node_t *node)
 -{
 +unsigned int avl_index(const avl_node_t *node) {
        avl_node_t *next;
        unsigned int index;
  
  }
  #endif
  #ifdef AVL_DEPTH
 -unsigned int avl_depth(const avl_tree_t *tree)
 -{
 +unsigned int avl_depth(const avl_tree_t *tree) {
        return AVL_NODE_DEPTH(tree->root);
  }
  #endif
diff --combined src/Makefile.am
@@@ -1,15 -1,12 +1,14 @@@
  ## 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
  
 -tincd_SOURCES = conf.c connection.c edge.c event.c graph.c logger.c meta.c net.c net_packet.c net_setup.c     \
 +tincd_SOURCES = cipher.c conf.c connection.c control.c crypto.c digest.c edge.c graph.c logger.c meta.c net.c net_packet.c net_setup.c        \
        net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c       \
 -      protocol_key.c protocol_subnet.c route.c subnet.c tincd.c
 +      protocol_key.c protocol_subnet.c route.c rsa.c subnet.c tincd.c
 +
 +tincctl_SOURCES = tincctl.c rsagen.c
  
  if TUNEMU
  tincd_SOURCES += bsd/tunemu.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
@@@ -33,12 -30,9 +32,12 @@@ endi
  tincd_LDADD = \
        $(top_builddir)/lib/libvpn.a
  
 +tincctl_LDADD = \
 +      $(top_builddir)/lib/libvpn.a
 +
  localedir = $(datadir)/locale
  
 -AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALEDIR=\"$(localedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\"
 +AM_CFLAGS = @CFLAGS@ -DCONFDIR=\"$(sysconfdir)\" -DLOCALEDIR=\"$(localedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\"
  
  dist-hook:
        rm -f `find . -type l`
diff --combined src/bsd/device.c
@@@ -2,6 -2,7 +2,7 @@@
      device.c -- Interaction BSD tun/tap device
      Copyright (C) 2001-2005 Ivo Timmermans,
                    2001-2009 Guus Sliepen <guus@tinc-vpn.org>
+                   2009      Grzegorz Dymarek <gregd72002@googlemail.com>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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: device.c 1398 2004-11-01 15:18:53Z guus $
+     You should have received a copy of the GNU General Public License along
+     with this program; if not, write to the Free Software Foundation, Inc.,
+     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
  
  #include "system.h"
@@@ -61,8 -60,6 +60,6 @@@ static device_type_t device_type = DEVI
  bool setup_device(void) {
        char *type;
  
-       cp();
        if(!get_config_string(lookup_config(config_tree, "Device"), &device))
                device = xstrdup(DEFAULT_DEVICE);
  
@@@ -83,7 -80,7 +80,7 @@@
                else if(!strcasecmp(type, "tap"))
                        device_type = DEVICE_TYPE_TAP;
                else {
-                       logger(LOG_ERR, _("Unknown device type %s!"), type);
+                       logger(LOG_ERR, "Unknown device type %s!", type);
                        return false;
                }
        } else {
        }
  
        if(device_fd < 0) {
-               logger(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
+               logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
                return false;
        }
  
                {       
                        const int zero = 0;
                        if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof zero) == -1) {
-                               logger(LOG_ERR, _("System call `%s' failed: %s"), "ioctl", strerror(errno));
+                               logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
                                return false;
                        }
                }
                }
  #endif
  
-                       device_info = _("Generic BSD tun device");
+                       device_info = "Generic BSD tun device";
                        break;
                case DEVICE_TYPE_TUNIFHEAD:
  #ifdef TUNSIFHEAD
                {
                        const int one = 1;
                        if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof one) == -1) {
-                               logger(LOG_ERR, _("System call `%s' failed: %s"), "ioctl", strerror(errno));
+                               logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
                                return false;
                        }
                }
                }
  #endif
  
-                       device_info = _("Generic BSD tun device");
+                       device_info = "Generic BSD tun device";
                        break;
                case DEVICE_TYPE_TAP:
                        if(routing_mode == RMODE_ROUTER)
                                overwrite_mac = true;
-                       device_info = _("Generic BSD tap device");
+                       device_info = "Generic BSD tap device";
                        break;
  #ifdef HAVE_TUNEMU
                case DEVICE_TYPE_TUNEMU:
-                       device_info = _("BSD tunemu device");
+                       device_info = "BSD tunemu device";
                        break;
  #endif
        }
  
-       logger(LOG_INFO, _("%s is a %s"), device, device_info);
+       logger(LOG_INFO, "%s is a %s", device, device_info);
  
        return true;
  }
  
  void close_device(void) {
-       cp();
        switch(device_type) {
  #ifdef HAVE_TUNEMU
                case DEVICE_TYPE_TUNEMU:
  }
  
  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;
                        }
                                        return false;
                        }
  
 -                      packet->len = lenin + 14;
 +                      packet->len = inlen + 14;
                        break;
  
                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;
                        }
                                        return false;
                        }
  
 -                      packet->len = lenin + 10;
 +                      packet->len = inlen + 10;
                        break;
                }
  
                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;
                        }
  
 -                      packet->len = lenin;
 +                      packet->len = inlen;
                        break;
  
                default:
                
        device_total_in += packet->len;
  
-       ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"),
+       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s",
                           packet->len, device_info);
  
        logger(LOG_INFO, "E:fd_read");
  }
  
  bool write_packet(vpn_packet_t *packet) {
-       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);
  
        switch(device_type) {
                case DEVICE_TYPE_TUN:
                        if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
-                               logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info,
+                               logger(LOG_ERR, "Error while writing to %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, packet->len - 14}};
 +                      struct iovec vector[2] = {{&type, sizeof type}, {packet->data + 14, packet->len - 14}};
                        int af;
                        
                        af = (packet->data[12] << 8) + packet->data[13];
                                        break;
                                default:
                                        ifdebug(TRAFFIC) logger(LOG_ERR,
-                                                          _("Unknown address family %x while writing packet to %s %s"),
+                                                          "Unknown address family %x while writing packet to %s %s",
                                                           af, device_info, device);
                                        return false;
                        }
  
                        if(writev(device_fd, vector, 2) < 0) {
-                               logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
+                               logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
                                           strerror(errno));
                                return false;
                        }
                        
                case DEVICE_TYPE_TAP:
                        if(write(device_fd, packet->data, packet->len) < 0) {
-                               logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info,
+                               logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
                                           device, strerror(errno));
                                return false;
                        }
  #ifdef HAVE_TUNEMU
                case DEVICE_TYPE_TUNEMU:
                        if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) {
-                               logger(LOG_ERR, _("Error while writing to %s %s: %s"), device_info,
+                               logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
                                           device, strerror(errno));
                                return false;
                        }
  }
  
  void dump_device_stats(void) {
-       cp();
-       logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
-       logger(LOG_DEBUG, _(" total bytes in:  %10d"), device_total_in);
-       logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
+       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
+       logger(LOG_DEBUG, " total bytes in:  %10d", device_total_in);
+       logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
  }
diff --combined src/conf.c
      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.
  */
  
  #include "system.h"
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  #include "conf.h"
  #include "logger.h"
  #include "netutl.h"                           /* for str2address */
  #include "utils.h"                            /* for cp */
  #include "xalloc.h"
  
 -avl_tree_t *config_tree;
 +splay_tree_t *config_tree;
  
  int pinginterval = 0;                 /* seconds between pings */
  int pingtimeout = 0;                  /* seconds to wait for response */
@@@ -54,28 -52,20 +52,20 @@@ 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;
  }
  
  config_t *new_config(void) {
-       cp();
        return xmalloc_and_zero(sizeof(config_t));
  }
  
  void free_config(config_t *cfg) {
-       cp();
        if(cfg->variable)
                free(cfg->variable);
  
        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;
  
 -      found = avl_search_closest_greater(config_tree, &cfg);
 +      found = splay_search_closest_greater(config_tree, &cfg);
  
        if(!found)
                return NULL;
        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) {
  }
  
  bool get_config_bool(const config_t *cfg, bool *result) {
-       cp();
        if(!cfg)
                return false;
  
                return true;
        }
  
-       logger(LOG_ERR, _("\"yes\" or \"no\" expected for configuration variable %s in %s line %d"),
+       logger(LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d",
                   cfg->variable, cfg->file, cfg->line);
  
        return false;
  }
  
  bool get_config_int(const config_t *cfg, int *result) {
-       cp();
        if(!cfg)
                return false;
  
        if(sscanf(cfg->value, "%d", result) == 1)
                return true;
  
-       logger(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
+       logger(LOG_ERR, "Integer expected for configuration variable %s in %s line %d",
                   cfg->variable, cfg->file, cfg->line);
  
        return false;
  }
  
  bool get_config_string(const config_t *cfg, char **result) {
-       cp();
        if(!cfg)
                return false;
  
  bool get_config_address(const config_t *cfg, struct addrinfo **result) {
        struct addrinfo *ai;
  
-       cp();
        if(!cfg)
                return false;
  
                return true;
        }
  
-       logger(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
+       logger(LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d",
                   cfg->variable, cfg->file, cfg->line);
  
        return false;
  bool get_config_subnet(const config_t *cfg, subnet_t ** result) {
        subnet_t subnet = {0};
  
-       cp();
        if(!cfg)
                return false;
  
        if(!str2net(&subnet, cfg->value)) {
-               logger(LOG_ERR, _("Subnet expected for configuration variable %s in %s line %d"),
+               logger(LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
                           cfg->variable, cfg->file, cfg->line);
                return false;
        }
        /* 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;
        }
@@@ -305,7 -279,7 +279,7 @@@ static char *readline(FILE * fp, char *
    Parse a configuration file and put the results in the configuration tree
    starting at *base.
  */
 -int read_config_file(avl_tree_t *config_tree, const char *fname) {
 +int read_config_file(splay_tree_t *config_tree, const char *fname) {
        int err = -2;                           /* Parse error */
        FILE *fp;
        char *buffer, *line;
        config_t *cfg;
        size_t bufsize;
  
-       cp();
        fp = fopen(fname, "r");
  
        if(!fp) {
-               logger(LOG_ERR, _("Cannot open config file %s: %s"), fname,
+               logger(LOG_ERR, "Cannot open config file %s: %s", fname,
                           strerror(errno));
                return -3;
        }
  
        
                if(!*value) {
-                       logger(LOG_ERR, _("No value for variable `%s' on line %d while reading config file %s"),
+                       logger(LOG_ERR, "No value for variable `%s' on line %d while reading config file %s",
                                   variable, lineno, fname);
                        break;
                }
@@@ -399,16 -371,108 +371,14 @@@ bool read_server_config() 
        char *fname;
        int x;
  
-       cp();
        xasprintf(&fname, "%s/tinc.conf", confbase);
        x = read_config_file(config_tree, fname);
  
        if(x == -1) {                           /* System error: complain */
-               logger(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
+               logger(LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
        }
  
        free(fname);
  
        return x == 0;
  }
 -
 -FILE *ask_and_open(const char *filename, const char *what) {
 -      FILE *r;
 -      char *directory;
 -      char *fn;
 -
 -      /* Check stdin and stdout */
 -      if(!isatty(0) || !isatty(1)) {
 -              /* Argh, they are running us from a script or something.  Write
 -                 the files to the current directory and let them burn in hell
 -                 for ever. */
 -              fn = xstrdup(filename);
 -      } else {
 -              /* Ask for a file and/or directory name. */
 -              fprintf(stdout, "Please enter a file to save %s to [%s]: ",
 -                              what, filename);
 -              fflush(stdout);
 -
 -              fn = readline(stdin, NULL, NULL);
 -
 -              if(!fn) {
 -                      fprintf(stderr, "Error while reading stdin: %s\n",
 -                                      strerror(errno));
 -                      return NULL;
 -              }
 -
 -              if(!strlen(fn))
 -                      /* User just pressed enter. */
 -                      fn = xstrdup(filename);
 -      }
 -
 -#ifdef HAVE_MINGW
 -      if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) {
 -#else
 -      if(fn[0] != '/') {
 -#endif
 -              /* The directory is a relative path or a filename. */
 -              char *p;
 -
 -              directory = get_current_dir_name();
 -              xasprintf(&p, "%s/%s", directory, fn);
 -              free(fn);
 -              free(directory);
 -              fn = p;
 -      }
 -
 -      umask(0077);                            /* Disallow everything for group and other */
 -
 -      /* Open it first to keep the inode busy */
 -
 -      r = fopen(fn, "r+") ?: fopen(fn, "w+");
 -
 -      if(!r) {
 -              fprintf(stderr, "Error opening file `%s': %s\n",
 -                              fn, strerror(errno));
 -              free(fn);
 -              return NULL;
 -      }
 -
 -      free(fn);
 -
 -      return r;
 -}
 -
 -bool disable_old_keys(FILE *f) {
 -      char buf[100];
 -      long pos;
 -      bool disabled = false;
 -
 -      rewind(f);
 -      pos = ftell(f);
 -
 -      while(fgets(buf, sizeof buf, f)) {
 -              if(!strncmp(buf, "-----BEGIN RSA", 14)) {       
 -                      buf[11] = 'O';
 -                      buf[12] = 'L';
 -                      buf[13] = 'D';
 -                      fseek(f, pos, SEEK_SET);
 -                      fputs(buf, f);
 -                      disabled = true;
 -              }
 -              else if(!strncmp(buf, "-----END RSA", 12)) {    
 -                      buf[ 9] = 'O';
 -                      buf[10] = 'L';
 -                      buf[11] = 'D';
 -                      fseek(f, pos, SEEK_SET);
 -                      fputs(buf, f);
 -                      disabled = true;
 -              }
 -              pos = ftell(f);
 -      }
 -
 -      return disabled;
 -}
diff --combined src/conf.h
      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_CONF_H__
  #define __TINC_CONF_H__
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  
  typedef struct config_t {
        char *variable;
@@@ -34,7 -32,7 +32,7 @@@
  
  #include "subnet.h"
  
 -extern avl_tree_t *config_tree;
 +extern splay_tree_t *config_tree;
  
  extern int pinginterval;
  extern int pingtimeout;
@@@ -43,22 -41,22 +41,22 @@@ extern bool bypass_security
  extern char *confbase;
  extern char *netname;
  
 -extern void init_configuration(avl_tree_t **);
 -extern void exit_configuration(avl_tree_t **);
 +extern void init_configuration(splay_tree_t **);
 +extern void exit_configuration(splay_tree_t **);
  extern config_t *new_config(void) __attribute__ ((__malloc__));
  extern void free_config(config_t *);
 -extern void config_add(avl_tree_t *, config_t *);
 -extern config_t *lookup_config(avl_tree_t *, char *);
 -extern config_t *lookup_config_next(avl_tree_t *, const config_t *);
 +extern void config_add(splay_tree_t *, config_t *);
 +extern config_t *lookup_config(splay_tree_t *, char *);
 +extern config_t *lookup_config_next(splay_tree_t *, const config_t *);
  extern bool get_config_bool(const config_t *, bool *);
  extern bool get_config_int(const config_t *, int *);
  extern bool get_config_string(const config_t *, char **);
  extern bool get_config_address(const config_t *, struct addrinfo **);
  extern bool get_config_subnet(const config_t *, struct subnet_t **);
  
 -extern int read_config_file(avl_tree_t *, const char *);
 +extern int read_config_file(splay_tree_t *, const char *);
  extern bool read_server_config(void);
 -extern FILE *ask_and_open(const char *, const char *);
 +extern FILE *ask_and_open(const char *, const char *, const char *);
  extern bool is_safe_path(const char *);
  extern bool disable_old_keys(FILE *);
  
diff --combined src/connection.c
@@@ -1,7 -1,8 +1,8 @@@
  /*
      connection.c -- connection list management
-     Copyright (C) 2000-2007 Guus Sliepen <guus@tinc-vpn.org>,
+     Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
                    2000-2005 Ivo Timmermans
+                   2008      Max Rijevski <maksuf@gmail.com>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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.
  */
  
  #include "system.h"
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
 +#include "cipher.h"
  #include "conf.h"
  #include "list.h"
  #include "logger.h"
@@@ -33,7 -31,7 +32,7 @@@
  #include "utils.h"
  #include "xalloc.h"
  
 -avl_tree_t *connection_tree;  /* Meta connections */
 +splay_tree_t *connection_tree;        /* Meta connections */
  connection_t *broadcast;
  
  static int connection_compare(const connection_t *a, const connection_t *b) {
  }
  
  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);
  
        if(c->hostname)
                free(c->hostname);
  
 -      if(c->inkey)
 -              free(c->inkey);
 -
 -      if(c->outkey)
 -              free(c->outkey);
 -
 -      if(c->inctx) {
 -              EVP_CIPHER_CTX_cleanup(c->inctx);
 -              free(c->inctx);
 -      }
 -
 -      if(c->outctx) {
 -              EVP_CIPHER_CTX_cleanup(c->outctx);
 -              free(c->outctx);
 -      }
 -
 -      if(c->mychallenge)
 -              free(c->mychallenge);
 +      cipher_close(&c->incipher);
 +      cipher_close(&c->outcipher);
  
        if(c->hischallenge)
                free(c->hischallenge);
        if(c->config_tree)
                exit_configuration(&c->config_tree);
  
 -      if(c->outbuf)
 -              free(c->outbuf);
 -
 -      if(c->rsa_key)
 -              RSA_free(c->rsa_key);
 +      if(c->buffer)
 +              bufferevent_free(c->buffer);
 +      
 +      if(event_initialized(&c->inevent))
 +              event_del(&c->inevent);
  
        free(c);
  }
  
  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) {
        char *fname;
        int x;
  
-       cp();
        xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
        x = read_config_file(c->config_tree, fname);
        free(fname);
diff --combined src/connection.h
@@@ -1,6 -1,6 +1,6 @@@
  /*
      connection.h -- header for connection.c
-     Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
+     Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
                    2000-2005 Ivo Timmermans
  
      This program is free software; you can redistribute it and/or modify
      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_CONNECTION_H__
  #define __TINC_CONNECTION_H__
  
 -#include <openssl/rsa.h>
 -#include <openssl/evp.h>
 -
 -#include "avl_tree.h"
 +#include "cipher.h"
 +#include "digest.h"
 +#include "rsa.h"
 +#include "splay_tree.h"
  
  #define OPTION_INDIRECT               0x0001
  #define OPTION_TCPONLY                0x0002
  #define OPTION_PMTU_DISCOVERY 0x0004
  
  typedef struct connection_status_t {
 -      int pinged:1;                           /* sent ping */
 -      int active:1;                           /* 1 if active.. */
 -      int connecting:1;                       /* 1 if we are waiting for a non-blocking connect() to finish */
 -      int termreq:1;                          /* the termination of this connection was requested */
 -      int remove:1;                           /* Set to 1 if you want this connection removed */
 -      int timeout:1;                          /* 1 if gotten timeout */
 -      int encryptout:1;                       /* 1 if we can encrypt outgoing traffic */
 -      int decryptin:1;                        /* 1 if we have to decrypt incoming traffic */
 -      int mst:1;                              /* 1 if this connection is part of a minimum spanning tree */
 -      int unused:23;
 +              int pinged:1;                           /* sent ping */
 +              int active:1;                           /* 1 if active.. */
 +              int connecting:1;                       /* 1 if we are waiting for a non-blocking connect() to finish */
 +              int termreq:1;                          /* the termination of this connection was requested */
 +              int remove_unused:1;                            /* Set to 1 if you want this connection removed */
 +              int timeout_unused:1;                           /* 1 if gotten timeout */
 +              int encryptout:1;                       /* 1 if we can encrypt outgoing traffic */
 +              int decryptin:1;                        /* 1 if we have to decrypt incoming traffic */
 +              int mst:1;                              /* 1 if this connection is part of a minimum spanning tree */
 +              int unused:23;
  } connection_status_t;
  
  #include "edge.h"
@@@ -67,30 -65,42 +65,30 @@@ typedef struct connection_t 
        struct node_t *node;            /* node associated with the other end */
        struct edge_t *edge;            /* edge associated with this connection */
  
 -      RSA *rsa_key;                           /* his public/private key */
 -      const EVP_CIPHER *incipher;     /* Cipher he will use to send data to us */
 -      const EVP_CIPHER *outcipher;    /* Cipher we will use to send data to him */
 -      EVP_CIPHER_CTX *inctx;          /* Context of encrypted meta data that will come from him to us */
 -      EVP_CIPHER_CTX *outctx;         /* Context of encrypted meta data that will be sent from us to him */
 -      char *inkey;                            /* His symmetric meta key + iv */
 -      char *outkey;                           /* Our symmetric meta key + iv */
 -      int inkeylength;                        /* Length of his key + iv */
 -      int outkeylength;                       /* Length of our key + iv */
 -      const EVP_MD *indigest;
 -      const EVP_MD *outdigest;
 +      rsa_t rsa;                      /* his public/private key */
 +      cipher_t incipher;              /* Cipher he will use to send data to us */
 +      cipher_t outcipher;             /* Cipher we will use to send data to him */
 +      digest_t indigest;
 +      digest_t outdigest;
 +
        int inmaclength;
        int outmaclength;
        int incompression;
        int outcompression;
 -      char *mychallenge;                      /* challenge we received from him */
 -      char *hischallenge;                     /* challenge we sent to him */
  
 -      char buffer[MAXBUFSIZE];        /* metadata input buffer */
 -      int buflen;                                     /* bytes read into buffer */
 -      int reqlen;                                     /* length of incoming request */
 +      char *hischallenge;             /* The challenge we sent to him */
 +
 +      struct bufferevent *buffer;                     /* buffer events on this metadata connection */
 +      struct event inevent;                           /* input event on this metadata connection */
        int tcplen;                                     /* length of incoming TCPpacket */
        int allow_request;                      /* defined if there's only one request possible */
  
 -      char *outbuf;                           /* metadata output buffer */
 -      int outbufstart;                        /* index of first meaningful byte in output buffer */
 -      int outbuflen;                          /* number of meaningful bytes in output buffer */
 -      int outbufsize;                         /* number of bytes allocated to output buffer */
 -
        time_t last_ping_time;          /* last time we saw some activity from the other end or pinged them */
 -      time_t last_flushed_time;       /* last time buffer was empty. Only meaningful if outbuflen > 0 */
  
 -      avl_tree_t *config_tree;        /* Pointer to configuration tree belonging to him */
 +      splay_tree_t *config_tree;      /* Pointer to configuration tree belonging to him */
  } connection_t;
  
 -extern avl_tree_t *connection_tree;
 +extern splay_tree_t *connection_tree;
  extern connection_t *broadcast;
  
  extern void init_connections(void);
@@@ -99,7 -109,7 +97,7 @@@ extern connection_t *new_connection(voi
  extern void free_connection(connection_t *);
  extern void connection_add(connection_t *);
  extern void connection_del(connection_t *);
 -extern void dump_connections(void);
 +extern int dump_connections(struct evbuffer *);
  extern bool read_connection_config(connection_t *);
  
  #endif                                                        /* __TINC_CONNECTION_H__ */
diff --combined src/cygwin/device.c
      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.
  */
  
  #include "system.h"
@@@ -59,31 -57,29 +57,29 @@@ bool setup_device(void) 
  
        bool found = false;
  
-       cp();
        get_config_string(lookup_config(config_tree, "Device"), &device);
        get_config_string(lookup_config(config_tree, "Interface"), &iface);
  
        /* Open registry and look for network adapters */
  
        if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
-               logger(LOG_ERR, _("Unable to read registry: %s"), winerror(GetLastError()));
+               logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
                return false;
        }
  
        for (i = 0; ; i++) {
 -              len = sizeof(adapterid);
 +              len = sizeof adapterid;
                if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL))
                        break;
  
                /* Find out more about this adapter */
  
 -              snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid);
 +              snprintf(regpath, sizeof regpath, "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid);
  
                  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2))
                        continue;
  
 -              len = sizeof(adaptername);
 +              len = sizeof adaptername;
                err = RegQueryValueEx(key2, "Name", 0, 0, adaptername, &len);
  
                RegCloseKey(key2);
                                continue;
                }
  
 -              snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
 +              snprintf(tapname, sizeof tapname, USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
                device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
                if(device_handle != INVALID_HANDLE_VALUE) {
                        CloseHandle(device_handle);
        RegCloseKey(key);
  
        if(!found) {
-               logger(LOG_ERR, _("No Windows tap device found!"));
+               logger(LOG_ERR, "No Windows tap device found!");
                return false;
        }
  
        if(!iface)
                iface = xstrdup(adaptername);
  
 -      snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
 +      snprintf(tapname, sizeof tapname, USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
        
        /* Now we are going to open this device twice: once for reading and once for writing.
           We do this because apparently it isn't possible to check for activity in the select() loop.
           Furthermore I don't really know how to do it the "Windows" way. */
  
        if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) {
-               logger(LOG_DEBUG, _("System call `%s' failed: %s"), "socketpair", strerror(errno));
+               logger(LOG_DEBUG, "System call `%s' failed: %s", "socketpair", strerror(errno));
                return false;
        }
  
        device_handle = CreateFile(tapname, GENERIC_WRITE,  FILE_SHARE_READ,  0,  OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM , 0);
        
        if(device_handle == INVALID_HANDLE_VALUE) {
-               logger(LOG_ERR, _("Could not open Windows tap device %s (%s) for writing: %s"), device, iface, winerror(GetLastError()));
+               logger(LOG_ERR, "Could not open Windows tap device %s (%s) for writing: %s", device, iface, winerror(GetLastError()));
                return false;
        }
  
  
        /* 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;
        }
  
        reader_pid = fork();
  
        if(reader_pid == -1) {
-               logger(LOG_DEBUG, _("System call `%s' failed: %s"), "fork", strerror(errno));
+               logger(LOG_DEBUG, "System call `%s' failed: %s", "fork", strerror(errno));
                return false;
        }
  
                   It passes everything it reads to the socket. */
        
                char buf[MTU];
 -              long lenin;
 +              long inlen;
  
                CloseHandle(device_handle);
  
                device_handle = CreateFile(tapname, GENERIC_READ, FILE_SHARE_WRITE, 0,  OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
  
                if(device_handle == INVALID_HANDLE_VALUE) {
-                       logger(LOG_ERR, _("Could not open Windows tap device %s (%s) for reading: %s"), device, iface, winerror(GetLastError()));
+                       logger(LOG_ERR, "Could not open Windows tap device %s (%s) for reading: %s", device, iface, winerror(GetLastError()));
                        buf[0] = 0;
                        write(sp[1], buf, 1);
                        exit(1);
                }
  
-               logger(LOG_DEBUG, _("Tap reader forked and running."));
+               logger(LOG_DEBUG, "Tap reader forked and running.");
  
                /* Notify success */
  
                /* Pass packets */
  
                for(;;) {
 -                      ReadFile(device_handle, buf, MTU, &lenin, NULL);
 -                      write(sp[1], buf, lenin);
 +                      ReadFile(device_handle, buf, MTU, &inlen, NULL);
 +                      write(sp[1], buf, inlen);
                }
        }
  
        read(device_fd, &gelukt, 1);
        if(gelukt != 1) {
-               logger(LOG_DEBUG, _("Tap reader failed!"));
+               logger(LOG_DEBUG, "Tap reader failed!");
                return false;
        }
  
-       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;
  }
  
  void close_device(void) {
-       cp();
        close(sp[0]);
        close(sp[1]);
        CloseHandle(device_handle);
  }
  
  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;
        }
        
 -      packet->len = lenin;
 +      packet->len = inlen;
  
        device_total_in += packet->len;
  
-       ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
+       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
                           device_info);
  
        return true;
  }
  
  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;
        }
  
  }
  
  void dump_device_stats(void) {
-       cp();
-       logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
-       logger(LOG_DEBUG, _(" total bytes in:  %10d"), device_total_in);
-       logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
+       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
+       logger(LOG_DEBUG, " total bytes in:  %10d", device_total_in);
+       logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
  }
diff --combined src/edge.c
      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.
  */
  
  #include "system.h"
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  #include "edge.h"
  #include "logger.h"
  #include "netutl.h"
@@@ -30,7 -28,7 +28,7 @@@
  #include "utils.h"
  #include "xalloc.h"
  
 -avl_tree_t *edge_weight_tree; /* Tree with all edges, sorted on weight */
 +splay_tree_t *edge_weight_tree;       /* Tree with all edges, sorted on weight */
  
  static int edge_compare(const edge_t *a, const edge_t *b) {
        return strcmp(a->to->name, b->to->name);
@@@ -53,50 -51,36 +51,36 @@@ 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 */
  
  edge_t *new_edge(void) {
-       cp();
        return xmalloc_and_zero(sizeof(edge_t));
  }
  
  void free_edge(edge_t *e) {
-       cp();
-       
        sockaddrfree(&e->address);
  
        free(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);
  
  }
  
  void edge_del(edge_t *e) {
-       cp();
        if(e->reverse)
                e->reverse->reverse = NULL;
  
 -      avl_delete(edge_weight_tree, e);
 -      avl_delete(e->from->edge_tree, e);
 +      splay_delete(edge_weight_tree, e);
 +      splay_delete(e->from->edge_tree, e);
  }
  
  edge_t *lookup_edge(node_t *from, node_t *to) {
        edge_t v;
        
-       cp();
        v.from = from;
        v.to = to;
  
 -      return avl_search(from->edge_tree, &v);
 +      return splay_search(from->edge_tree, &v);
  }
  
 -void dump_edges(void) {
 -      avl_node_t *node, *node2;
 +int dump_edges(struct evbuffer *out) {
 +      splay_node_t *node, *node2;
        node_t *n;
        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);
                }
        }
  
 -      logger(LOG_DEBUG, "End of edges.");
 +      return 0;
  }
diff --combined src/edge.h
      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_EDGE_H__
  #define __TINC_EDGE_H__
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  #include "connection.h"
  #include "net.h"
  #include "node.h"
@@@ -40,17 -38,17 +38,17 @@@ typedef struct edge_t 
        struct edge_t *reverse;         /* edge in the opposite direction, if available */
  } edge_t;
  
 -extern avl_tree_t *edge_weight_tree;  /* Tree with all known edges sorted on weight */
 +extern splay_tree_t *edge_weight_tree;        /* Tree with all known edges sorted on weight */
  
  extern void init_edges(void);
  extern void exit_edges(void);
  extern edge_t *new_edge(void) __attribute__ ((__malloc__));
  extern void free_edge(edge_t *);
 -extern avl_tree_t *new_edge_tree(void) __attribute__ ((__malloc__));
 -extern void free_edge_tree(avl_tree_t *);
 +extern splay_tree_t *new_edge_tree(void) __attribute__ ((__malloc__));
 +extern void free_edge_tree(splay_tree_t *);
  extern void edge_add(edge_t *);
  extern void edge_del(edge_t *);
  extern edge_t *lookup_edge(struct node_t *, struct node_t *);
 -extern void dump_edges(void);
 +extern int dump_edges(struct evbuffer *);
  
  #endif                                                        /* __TINC_EDGE_H__ */
diff --combined src/graph.c
      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.
  */
  
  /* We need to generate two trees from the graph:
@@@ -46,7 -44,7 +44,7 @@@
  
  #include "system.h"
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  #include "config.h"
  #include "connection.h"
  #include "device.h"
  #include "utils.h"
  #include "xalloc.h"
  
 -static bool graph_changed = true;
 -
  /* Implementation of Kruskal's algorithm.
 -   Running time: O(EN)
 +   Running time: O(E)
     Please note that sorting on weight is already done by add_edge().
  */
  
  void mst_kruskal(void) {
 -      avl_node_t *node, *next;
 +      splay_node_t *node, *next;
        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) {
                c->status.mst = false;
        }
  
 -      /* Do we have something to do at all? */
 -
 -      if(!edge_weight_tree->head)
 -              return;
 -
        ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Kruskal's algorithm:");
  
        /* Clear visited status on nodes */
        for(node = node_tree->head; node; node = node->next) {
                n = node->data;
                n->status.visited = false;
 -              nodes++;
 -      }
 -
 -      /* Starting point */
 -
 -      for(node = edge_weight_tree->head; node; node = node->next) {
 -              e = node->data;
 -              if(e->from->status.reachable) {
 -                      e->from->status.visited = true;
 -                      break;
 -              }
        }
  
        /* Add safe edges */
  
 -      for(skipped = false, node = edge_weight_tree->head; node; node = next) {
 +      for(node = edge_weight_tree->head; node; node = next) {
                next = node->next;
                e = node->data;
  
 -              if(!e->reverse || e->from->status.visited == e->to->status.visited) {
 -                      skipped = true;
 +              if(!e->reverse || (e->from->status.visited && e->to->status.visited))
                        continue;
 -              }
  
                e->from->status.visited = true;
                e->to->status.visited = true;
                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);
                }
        }
  
 -      ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Done, counted %d nodes and %d safe edges.", nodes,
 -                         safe_edges);
 +      list_free(todo_list);
  }
  
  /* Implementation of a simple breadth-first search algorithm.
  */
  
  void sssp_bfs(void) {
 -      avl_node_t *node, *next, *to;
 +      splay_node_t *node, *to;
        edge_t *e;
        node_t *n;
        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 */
        }
  
        list_free(todo_list);
 +}
 +
 +void check_reachability() {
 +      splay_node_t *node, *next;
 +      node_t *n;
 +      char *name;
 +      char *address, *port;
 +      char *envp[7];
 +      int i;
  
        /* Check reachability status. */
  
                        n->status.reachable = !n->status.reachable;
  
                        if(n->status.reachable) {
-                               ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Node %s (%s) became reachable"),
+                               ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became reachable",
                                           n->name, n->hostname);
                        } else {
-                               ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Node %s (%s) became unreachable"),
+                               ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became unreachable",
                                           n->name, n->hostname);
                        }
  
                        n->minmtu = 0;
                        n->mtuprobes = 0;
  
 -                      if(n->mtuevent) {
 -                              event_del(n->mtuevent);
 -                              n->mtuevent = NULL;
 -                      }
 +                      event_del(&n->mtuevent);
  
                        xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
                        xasprintf(&envp[1], "DEVICE=%s", device ? : "");
        }
  }
  
 -void graph(void) {
 -      subnet_cache_flush();
 -      sssp_bfs();
 -      mst_kruskal();
 -      graph_changed = true;
 -}
 -
 -
 -
  /* Dump nodes and edges to a graphviz file.
           
     The file can be converted to an image with
     dot -Tpng graph_filename -o image_filename.png -Gconcentrate=true
  */
  
 -void dump_graph(void) {
 -      avl_node_t *node;
 +int dump_graph(struct evbuffer *out) {
 +      splay_node_t *node;
        node_t *n;
        edge_t *e;
 -      char *filename = NULL, *tmpname = NULL;
 -      FILE *file;
 -      
 -      if(!graph_changed || !get_config_string(lookup_config(config_tree, "GraphDumpFile"), &filename))
 -              return;
 -
 -      graph_changed = false;
 -
 -      ifdebug(PROTOCOL) logger(LOG_NOTICE, "Dumping graph");
 -      
 -      if(filename[0] == '|') {
 -              file = popen(filename + 1, "w");
 -      } else {
 -              xasprintf(&tmpname, "%s.new", filename);
 -              file = fopen(tmpname, "w");
 -      }
 -
 -      if(!file) {
 -              logger(LOG_ERR, "Unable to open graph dump file %s: %s", filename, strerror(errno));
 -              free(tmpname);
 -              return;
 -      }
  
 -      fprintf(file, "digraph {\n");
 +      if(evbuffer_add_printf(out, "digraph {\n") == -1)
 +              return errno;
        
        /* dump all nodes first */
        for(node = node_tree->head; node; node = node->next) {
                n = node->data;
 -              fprintf(file, " %s [label = \"%s\"];\n", n->name, n->name);
 +              if(evbuffer_add_printf(out, "   %s [label = \"%s\"];\n",
 +                                                         n->name, n->name) == -1)
 +                      return errno;
        }
  
        /* now dump all edges */
        for(node = edge_weight_tree->head; node; node = node->next) {
                e = node->data;
 -              fprintf(file, " %s -> %s;\n", e->from->name, e->to->name);
 +              if(evbuffer_add_printf(out, "   %s -> %s;\n",
 +                                                         e->from->name, e->to->name) == -1)
 +                      return errno;
        }
  
 -      fprintf(file, "}\n");   
 -      
 -      if(filename[0] == '|') {
 -              pclose(file);
 -      } else {
 -              fclose(file);
 -#ifdef HAVE_MINGW
 -              unlink(filename);
 -#endif
 -              rename(tmpname, filename);
 -              free(tmpname);
 -      }
 +      if(evbuffer_add_printf(out, "}\n") == -1)
 +              return errno;
 +
 +      return 0;
 +}
 +
 +void graph(void) {
 +    subnet_cache_flush();
 +      sssp_dijkstra();
 +      check_reachability();
 +      mst_kruskal();
  }
diff --combined src/graph.h
      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_GRAPH_H__
@@@ -26,6 -24,6 +24,6 @@@
  extern void graph(void);
  extern void mst_kruskal(void);
  extern void sssp_bfs(void);
 -extern void dump_graph(void);
 +extern int dump_graph(struct evbuffer *);
  
  #endif /* __TINC_GRAPH_H__ */
diff --combined src/linux/device.c
      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.
  */
  
  #include "system.h"
@@@ -55,8 -53,6 +53,6 @@@ static int device_total_out = 0
  bool setup_device(void) {
        struct ifreq ifr;
  
-       cp();
        if(!get_config_string(lookup_config(config_tree, "Device"), &device))
                device = xstrdup(DEFAULT_DEVICE);
  
        device_fd = open(device, O_RDWR | O_NONBLOCK);
  
        if(device_fd < 0) {
-               logger(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
+               logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
                return false;
        }
  
  #ifdef HAVE_LINUX_IF_TUN_H
        /* Ok now check if this is an old ethertap or a new tun/tap thingie */
  
 -      memset(&ifr, 0, sizeof(ifr));
 +      memset(&ifr, 0, sizeof ifr);
        if(routing_mode == RMODE_ROUTER) {
                ifr.ifr_flags = IFF_TUN;
                device_type = DEVICE_TYPE_TUN;
-               device_info = _("Linux tun/tap device (tun mode)");
+               device_info = "Linux tun/tap device (tun mode)";
        } else {
                ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
                device_type = DEVICE_TYPE_TAP;
-               device_info = _("Linux tun/tap device (tap mode)");
+               device_info = "Linux tun/tap device (tap mode)";
        }
  
        if(iface)
@@@ -96,7 -92,7 +92,7 @@@
                if(iface) free(iface);
                iface = xstrdup(ifrname);
        } else if(!ioctl(device_fd, (('T' << 8) | 202), &ifr)) {
-               logger(LOG_WARNING, _("Old ioctl() request was needed for %s"), device);
+               logger(LOG_WARNING, "Old ioctl() request was needed for %s", device);
                strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
                if(iface) free(iface);
                iface = xstrdup(ifrname);
        {
                if(routing_mode == RMODE_ROUTER)
                        overwrite_mac = true;
-               device_info = _("Linux ethertap device");
+               device_info = "Linux ethertap device";
                device_type = DEVICE_TYPE_ETHERTAP;
                if(iface)
                        free(iface);
                iface = xstrdup(rindex(device, '/') ? rindex(device, '/') + 1 : device);
        }
  
-       logger(LOG_INFO, _("%s is a %s"), device, device_info);
+       logger(LOG_INFO, "%s is a %s", device, device_info);
  
        return true;
  }
  
  void close_device(void) {
-       cp();
-       
        close(device_fd);
  
        free(device);
  }
  
  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;
                        }
  
 -                      packet->len = lenin - 2;
 +                      packet->len = inlen - 2;
                        break;
        }
  
        device_total_in += packet->len;
  
-       ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
+       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
                           device_info);
  
        return true;
  }
  
  bool write_packet(vpn_packet_t *packet) {
-       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);
  
        switch(device_type) {
                case DEVICE_TYPE_TUN:
                        packet->data[10] = packet->data[11] = 0;
                        if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
-                               logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
+                               logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
                                           strerror(errno));
                                return false;
                        }
                        break;
                case DEVICE_TYPE_TAP:
                        if(write(device_fd, packet->data, packet->len) < 0) {
-                               logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
+                               logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
                                           strerror(errno));
                                return false;
                        }
                        *(short int *)(packet->data - 2) = packet->len;
  
                        if(write(device_fd, packet->data - 2, packet->len + 2) < 0) {
-                               logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
+                               logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
                                           strerror(errno));
                                return false;
                        }
  }
  
  void dump_device_stats(void) {
-       cp();
-       logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
-       logger(LOG_DEBUG, _(" total bytes in:  %10d"), device_total_in);
-       logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
+       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
+       logger(LOG_DEBUG, " total bytes in:  %10d", device_total_in);
+       logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
  }
diff --combined src/logger.c
      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.
  */
  
  #include "system.h"
@@@ -88,7 -86,7 +86,7 @@@ void logger(int priority, const char *f
                        {
                                char message[4096];
                                char *messages[] = {message};
 -                              vsnprintf(message, sizeof(message), format, ap);
 +                              vsnprintf(message, sizeof message, format, ap);
                                ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL);
                        }
  #else
@@@ -98,7 -96,7 +96,7 @@@
  #else
                        {
                                char message[4096];
 -                              vsnprintf(message, sizeof(message), format, ap);
 +                              vsnprintf(message, sizeof message, format, ap);
                                syslog(priority, "%s", message);
                        }
  #endif
diff --combined src/meta.c
@@@ -1,7 -1,8 +1,8 @@@
  /*
      meta.c -- handle the meta communication
-     Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
+     Copyright (C) 2000-2009 Guus Sliepen <guus@tinc-vpn.org>,
                    2000-2005 Ivo Timmermans
+                   2006      Scott Lamb <slamb@slamb.org>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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.
  */
  
  #include "system.h"
  
 -#include <openssl/err.h>
 -#include <openssl/evp.h>
 -
 -#include "avl_tree.h"
 +#include "splay_tree.h"
 +#include "cipher.h"
  #include "connection.h"
  #include "logger.h"
  #include "meta.h"
  #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;
                        }
                }
 +      } while(inlen);
  
 -              /* Otherwise we are waiting for a request */
 -
 -              reqlen = 0;
 -
 -              for(i = oldlen; i < c->buflen; i++) {
 -                      if(c->buffer[i] == '\n') {
 -                              c->buffer[i] = '\0';    /* replace end-of-line by end-of-string so we can use sscanf */
 -                              reqlen = i + 1;
 -                              break;
 -                      }
 -              }
 -
 -              if(reqlen) {
 -                      c->reqlen = reqlen;
 -                      if(!receive_request(c))
 -                              return false;
 -
 -                      c->buflen -= reqlen;
 -                      lenin -= reqlen - oldlen;
 -                      memmove(c->buffer, c->buffer + reqlen, c->buflen);
 -                      oldlen = 0;
 -                      continue;
 -              } else {
 -                      break;
 -              }
 -      }
 -
 -      if(c->buflen >= MAXBUFSIZE) {
 -              logger(LOG_ERR, "Metadata read buffer overflow for %s (%s)",
 -                         c->name, c->hostname);
 -              return false;
 -      }
 -
 -      c->last_ping_time = now;
 +      c->last_ping_time = time(NULL);
  
        return true;
  }
diff --combined src/meta.h
      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_META_H__
@@@ -27,7 -25,7 +25,7 @@@
  
  extern bool send_meta(struct connection_t *, const char *, int);
  extern void broadcast_meta(struct connection_t *, const char *, int);
 -extern bool flush_meta(struct connection_t *);
 +extern void flush_meta(int fd, short events, void *data);
  extern bool receive_meta(struct connection_t *);
  
  #endif                                                        /* __TINC_META_H__ */
diff --combined src/mingw/device.c
      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.
  */
  
  #include "system.h"
@@@ -51,7 -49,7 +49,7 @@@ static DWORD WINAPI tapreader(void *bla
        OVERLAPPED overlapped;
        vpn_packet_t packet;
  
-       logger(LOG_DEBUG, _("Tap reader running"));
+       logger(LOG_DEBUG, "Tap reader running");
  
        /* Read from tap device and send to parent */
  
@@@ -70,7 -68,7 +68,7 @@@
                                if(!GetOverlappedResult(device_handle, &overlapped, &len, FALSE))
                                        continue;
                        } else {
-                               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 -1;
                        }
@@@ -108,31 -106,29 +106,29 @@@ bool setup_device(void) 
                .ai_flags = 0,
        };
  
-       cp();
        get_config_string(lookup_config(config_tree, "Device"), &device);
        get_config_string(lookup_config(config_tree, "Interface"), &iface);
  
        /* Open registry and look for network adapters */
  
        if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
-               logger(LOG_ERR, _("Unable to read registry: %s"), winerror(GetLastError()));
+               logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
                return false;
        }
  
        for (i = 0; ; i++) {
 -              len = sizeof(adapterid);
 +              len = sizeof adapterid;
                if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL))
                        break;
  
                /* Find out more about this adapter */
  
 -              snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid);
 +              snprintf(regpath, sizeof regpath, "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid);
  
                  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2))
                        continue;
  
 -              len = sizeof(adaptername);
 +              len = sizeof adaptername;
                err = RegQueryValueEx(key2, "Name", 0, 0, adaptername, &len);
  
                RegCloseKey(key2);
                                continue;
                }
  
 -              snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
 +              snprintf(tapname, sizeof tapname, USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
                device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
                if(device_handle != INVALID_HANDLE_VALUE) {
                        found = true;
        RegCloseKey(key);
  
        if(!found) {
-               logger(LOG_ERR, _("No Windows tap device found!"));
+               logger(LOG_ERR, "No Windows tap device found!");
                return false;
        }
  
        /* Try to open the corresponding tap device */
  
        if(device_handle == INVALID_HANDLE_VALUE) {
 -              snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
 +              snprintf(tapname, sizeof tapname, USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
                device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
        }
        
        if(device_handle == INVALID_HANDLE_VALUE) {
-               logger(LOG_ERR, _("%s (%s) is not a usable Windows tap device: %s"), device, iface, winerror(GetLastError()));
+               logger(LOG_ERR, "%s (%s) is not a usable Windows tap device: %s", device, iface, winerror(GetLastError()));
                return false;
        }
  
        /* 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;
        }
  
        thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL);
  
        if(!thread) {
-               logger(LOG_ERR, _("System call `%s' failed: %s"), "CreateThread", winerror(GetLastError()));
+               logger(LOG_ERR, "System call `%s' failed: %s", "CreateThread", 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;
  }
  
  void close_device(void) {
-       cp();
        CloseHandle(device_handle);
  
        free(device);
@@@ -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;
        }
  
  }
  
  void dump_device_stats(void) {
-       cp();
-       logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
-       logger(LOG_DEBUG, _(" total bytes in:  %10d"), device_total_in);
-       logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
+       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
+       logger(LOG_DEBUG, " total bytes in:  %10d", device_total_in);
+       logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
  }
diff --combined src/net.c
+++ b/src/net.c
@@@ -2,6 -2,7 +2,7 @@@
      net.c -- most of the network code
      Copyright (C) 1998-2005 Ivo Timmermans,
                    2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                   2006      Scott Lamb <slamb@slamb.org>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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.
  */
  
  #include "system.h"
  #include <openssl/rand.h>
  
  #include "utils.h"
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  #include "conf.h"
  #include "connection.h"
  #include "device.h"
 -#include "event.h"
  #include "graph.h"
  #include "logger.h"
  #include "meta.h"
  #include "netutl.h"
  #include "process.h"
  #include "protocol.h"
 -#include "route.h"
  #include "subnet.h"
  #include "xalloc.h"
  
 -bool do_purge = false;
 -volatile bool running = false;
 -
 -time_t now = 0;
 -
  /* Purge edges and subnets of unreachable nodes. Use carefully. */
  
 -static void purge(void) {
 -      avl_node_t *nnode, *nnext, *enode, *enext, *snode, *snext;
 +void purge(void) {
 +      splay_node_t *nnode, *nnext, *enode, *enext, *snode, *snext;
        node_t *n;
        edge_t *e;
        subnet_t *s;
  
-       cp();
-       ifdebug(PROTOCOL) logger(LOG_DEBUG, _("Purging unreachable nodes"));
+       ifdebug(PROTOCOL) logger(LOG_DEBUG, "Purging unreachable nodes");
  
        /* Remove all edges and subnets owned by unreachable nodes. */
  
@@@ -58,7 -62,7 +55,7 @@@
                n = nnode->data;
  
                if(!n->status.reachable) {
-                       ifdebug(SCARY_THINGS) logger(LOG_DEBUG, _("Purging node %s (%s)"), n->name,
+                       ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Purging node %s (%s)", n->name,
                                           n->hostname);
  
                        for(snode = n->subnet_tree->head; snode; snode = snext) {
        }
  }
  
 -/*
 -  put all file descriptors in an fd_set array
 -  While we're at it, purge stuff that needs to be removed.
 -*/
 -static int build_fdset(fd_set *readset, fd_set *writeset) {
 -      avl_node_t *node, *next;
 -      connection_t *c;
 -      int i, max = 0;
 -
 -      FD_ZERO(readset);
 -      FD_ZERO(writeset);
 -
 -      for(node = connection_tree->head; node; node = next) {
 -              next = node->next;
 -              c = node->data;
 -
 -              if(c->status.remove) {
 -                      connection_del(c);
 -                      if(!connection_tree->head)
 -                              purge();
 -              } else {
 -                      FD_SET(c->socket, readset);
 -                      if(c->outbuflen > 0)
 -                              FD_SET(c->socket, writeset);
 -                      if(c->socket > max)
 -                              max = c->socket;
 -              }
 -      }
 -
 -      for(i = 0; i < listen_sockets; i++) {
 -              FD_SET(listen_socket[i].tcp, readset);
 -              if(listen_socket[i].tcp > max)
 -                      max = listen_socket[i].tcp;
 -              FD_SET(listen_socket[i].udp, readset);
 -              if(listen_socket[i].udp > max)
 -                      max = listen_socket[i].udp;
 -      }
 -
 -      if(device_fd >= 0)
 -              FD_SET(device_fd, readset);
 -      if(device_fd > max)
 -              max = device_fd;
 -      
 -      return max;
 -}
 -
  /*
    Terminate a connection:
    - Close the socket
    - 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)
  
        /* Check if this was our outgoing connection */
  
 -      if(c->outgoing) {
 +      if(c->outgoing)
                retry_outgoing(c->outgoing);
 -              c->outgoing = NULL;
 -      }
  
 -      free(c->outbuf);
 -      c->outbuf = NULL;
 -      c->outbuflen = 0;
 -      c->outbufsize = 0;
 -      c->outbufstart = 0;
 +      connection_del(c);
  }
  
  /*
    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;
                }
        }
  
 -      for(i = 0; i < listen_sockets; i++) {
 -              if(FD_ISSET(listen_socket[i].udp, readset))
 -                      handle_incoming_vpn_data(listen_socket[i].udp);
 -
 -              if(FD_ISSET(listen_socket[i].tcp, readset))
 -                      handle_new_meta_connection(listen_socket[i].tcp);
 +      if (!receive_meta(c)) {
 +              terminate_connection(c, c->status.active);
 +              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 --combined src/net.h
+++ b/src/net.h
@@@ -1,6 -1,6 +1,6 @@@
  /*
      net.h -- header for net.c
-     Copyright (C) 1998-2005 Ivo Timmermans <zarq@iname.com>
+     Copyright (C) 1998-2005 Ivo Timmermans
                    2000-2009 Guus Sliepen <guus@tinc-vpn.org>
  
      This program is free software; you can redistribute it and/or modify
      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_NET_H__
  #define __TINC_NET_H__
  
 -#include <openssl/evp.h>
 +#include <event.h>
  
  #include "ipv6.h"
 +#include "cipher.h"
 +#include "digest.h"
  
  #ifdef ENABLE_JUMBOGRAMS
  #define MTU 9018                              /* 9000 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
  #define MTU 1518                              /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
  #endif
  
 -#define MAXSIZE (MTU + 4 + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + MTU/64 + 20)      /* MTU + seqno + padding + HMAC + compressor overhead */
 +#define MAXSIZE (MTU + 4 + CIPHER_MAX_BLOCK_SIZE + DIGEST_MAX_SIZE + MTU/64 + 20)     /* MTU + seqno + padding + HMAC + compressor overhead */
  #define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128)  /* Enough room for a request with a MAXSIZEd packet or a 8192 bits RSA key */
  
 -#define MAXSOCKETS 128                        /* Overkill... */
 +#define MAXSOCKETS 8                  /* Probably overkill... */
  
  typedef struct mac_t {
        uint8_t x[6];
@@@ -88,8 -84,6 +86,8 @@@ typedef struct vpn_packet_t 
  } vpn_packet_t;
  
  typedef struct listen_socket_t {
 +      struct event ev_tcp;
 +      struct event ev_udp;
        int tcp;
        int udp;
        sockaddr_t sa;
@@@ -104,7 -98,6 +102,7 @@@ typedef struct outgoing_t 
        struct config_t *cfg;
        struct addrinfo *ai;
        struct addrinfo *aip;
 +      struct event ev;
  } outgoing_t;
  
  extern list_t *outgoing_list;
@@@ -115,19 -108,22 +113,19 @@@ extern int addressfamily
  
  extern listen_socket_t listen_socket[MAXSOCKETS];
  extern int listen_sockets;
 -extern int keyexpires;
  extern int keylifetime;
  extern bool do_prune;
 -extern bool do_purge;
  extern char *myport;
 -extern time_t now;
  
  /* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */
  #include "connection.h"
  #include "node.h"
  
  extern void retry_outgoing(outgoing_t *);
 -extern void handle_incoming_vpn_data(int);
 +extern void handle_incoming_vpn_data(int, short, void *);
  extern void finish_connecting(struct connection_t *);
  extern void do_outgoing_connection(struct connection_t *);
 -extern bool handle_new_meta_connection(int);
 +extern void handle_new_meta_connection(int, short, void *);
  extern int setup_listen_socket(const sockaddr_t *);
  extern int setup_vpn_in_socket(const sockaddr_t *);
  extern void send_packet(const struct node_t *, vpn_packet_t *);
@@@ -142,12 -138,6 +140,12 @@@ extern void terminate_connection(struc
  extern void flush_queue(struct node_t *);
  extern bool read_rsa_public_key(struct connection_t *);
  extern void send_mtu_probe(struct node_t *);
 +extern void handle_device_data(int, short, void *);
 +extern void handle_meta_connection_data(int, short, void *);
 +extern void regenerate_key();
 +extern void purge(void);
 +extern void retry(void);
 +extern int reload_configuration(void);
  
  #ifndef HAVE_MINGW
  #define closesocket(s) close(s)
diff --combined src/net_packet.c
      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.
  */
  
  #include "system.h"
  
 -#include <openssl/rand.h>
 -#include <openssl/err.h>
 -#include <openssl/evp.h>
 -#include <openssl/pem.h>
 -#include <openssl/hmac.h>
 -
  #include <zlib.h>
  #include LZO1X_H
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
 +#include "cipher.h"
  #include "conf.h"
  #include "connection.h"
 +#include "crypto.h"
 +#include "digest.h"
  #include "device.h"
  #include "ethernet.h"
 -#include "event.h"
  #include "graph.h"
  #include "list.h"
  #include "logger.h"
@@@ -56,29 -58,27 +54,27 @@@ static void send_udppacket(node_t *, vp
  
  #define MAX_SEQNO 1073741824
  
 -void send_mtu_probe(node_t *n) {
 +static void send_mtu_probe_handler(int fd, short events, void *data) {
 +      node_t *n = data;
        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;
        }
  
        if(n->mtuprobes >= 10 && !n->minmtu) {
-               ifdebug(TRAFFIC) logger(LOG_INFO, _("No response to MTU probes from %s (%s)"), n->name, n->hostname);
+               ifdebug(TRAFFIC) logger(LOG_INFO, "No response to MTU probes from %s (%s)", n->name, n->hostname);
                return;
        }
  
        for(i = 0; i < 3; i++) {
                if(n->mtuprobes >= 30 || n->minmtu >= n->maxmtu) {
                        n->mtu = n->minmtu;
-                       ifdebug(TRAFFIC) logger(LOG_INFO, _("Fixing MTU of %s (%s) to %d after %d probes"), n->name, n->hostname, n->mtu, n->mtuprobes);
+                       ifdebug(TRAFFIC) logger(LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes);
                        return;
                }
  
                        len = 64;
                
                memset(packet.data, 0, 14);
 -              RAND_pseudo_bytes(packet.data + 14, len - 14);
 +              randomize(packet.data + 14, len - 14);
                packet.len = len;
                packet.priority = 0;
  
-               ifdebug(TRAFFIC) logger(LOG_INFO, _("Sending MTU probe length %d to %s (%s)"), len, n->name, n->hostname);
+               ifdebug(TRAFFIC) logger(LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname);
  
                send_udppacket(n, &packet);
        }
  
 -      n->mtuevent = new_event();
 -      n->mtuevent->handler = (event_handler_t)send_mtu_probe;
 -      n->mtuevent->data = n;
 -      n->mtuevent->time = now + 1;
 -      event_add(n->mtuevent);
 +      event_add(&n->mtuevent, &(struct timeval){1, 0});
 +}
 +
 +void send_mtu_probe(node_t *n) {
 +      if(!timeout_initialized(&n->mtuevent))
 +              timeout_set(&n->mtuevent, send_mtu_probe_handler, n);
 +      send_mtu_probe_handler(0, 0, n);
  }
  
  void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
-       ifdebug(TRAFFIC) logger(LOG_INFO, _("Got MTU probe length %d from %s (%s)"), packet->len, n->name, n->hostname);
+       ifdebug(TRAFFIC) logger(LOG_INFO, "Got MTU probe length %d from %s (%s)", packet->len, n->name, n->hostname);
  
        if(!packet->data[0]) {
                packet->data[0] = 1;
@@@ -158,99 -156,108 +154,93 @@@ static length_t uncompress_packet(uint8
  /* VPN packet I/O */
  
  static void receive_packet(node_t *n, vpn_packet_t *packet) {
-       cp();
-       ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Received packet of %d bytes from %s (%s)"),
+       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Received packet of %d bytes from %s (%s)",
                           packet->len, n->name, n->hostname);
  
        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;
                }
                
 -              outpkt->len = outlen + outpad;
 +              outpkt->len = outlen;
                inpkt = outpkt;
        }
  
        /* Check the sequence number */
  
 -      inpkt->len -= sizeof(inpkt->seqno);
 +      inpkt->len -= sizeof inpkt->seqno;
        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;
                        }
                } else {
                        for(i = n->received_seqno + 1; i < inpkt->seqno; i++)
 -                              n->late[(i / 8) % sizeof(n->late)] |= 1 << i % 8;
 +                              n->late[(i / 8) % sizeof n->late] |= 1 << i % 8;
                }
        }
        
 -      n->late[(inpkt->seqno / 8) % sizeof(n->late)] &= ~(1 << inpkt->seqno % 8);
 +      n->late[(inpkt->seqno / 8) % sizeof n->late] &= ~(1 << inpkt->seqno % 8);
  
        if(inpkt->seqno > n->received_seqno)
                n->received_seqno = inpkt->seqno;
                        
        if(n->received_seqno > MAX_SEQNO)
 -              keyexpires = 0;
 +              regenerate_key();
  
        /* Decompress the packet */
  
                outpkt = pkt[nextpkt++];
  
                if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression)) < 0) {
-                       ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while uncompressing packet from %s (%s)"),
+                       ifdebug(TRAFFIC) logger(LOG_ERR, "Error while uncompressing packet from %s (%s)",
                                                 n->name, n->hostname);
                        return;
                }
  
        inpkt->priority = 0;
  
 -      if(n->connection)
 -              n->connection->last_ping_time = now;
 -
        if(!inpkt->data[12] && !inpkt->data[13])
                mtu_probe_h(n, inpkt, origlen);
        else
  void receive_tcppacket(connection_t *c, char *buffer, int len) {
        vpn_packet_t outpkt;
  
-       cp();
        outpkt.len = len;
        if(c->options & OPTION_TCPONLY)
                outpkt.priority = 0;
@@@ -300,15 -308,13 +288,13 @@@ static void send_udppacket(node_t *n, v
        int nextpkt = 0;
        vpn_packet_t *outpkt;
        int origlen;
 -      int outlen, outpad;
 +      size_t outlen;
        static int priority = 0;
        int origpriority;
        int sock;
  
-       cp();
        if(!n->status.reachable) {
-               ifdebug(TRAFFIC) logger(LOG_INFO, _("Trying to send UDP packet to unreachable node %s (%s)"), n->name, n->hostname);
+               ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname);
                return;
        }
  
  
        if(!n->status.validkey) {
                ifdebug(TRAFFIC) logger(LOG_INFO,
-                                  _("No valid key known yet for %s (%s), forwarding via TCP"),
+                                  "No valid key known yet for %s (%s), forwarding via TCP",
                                   n->name, n->hostname);
  
                if(!n->status.waitingforkey)
  
        if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (inpkt->data[12] | inpkt->data[13])) {
                ifdebug(TRAFFIC) logger(LOG_INFO,
-                               _("Packet for %s (%s) larger than minimum MTU, forwarding via TCP"),
+                               "Packet for %s (%s) larger than minimum MTU, forwarding via TCP",
                                n->name, n->hostname);
  
                send_tcppacket(n->nexthop->connection, origpkt);
                outpkt = pkt[nextpkt++];
  
                if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression)) < 0) {
-                       ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while compressing packet to %s (%s)"),
+                       ifdebug(TRAFFIC) logger(LOG_ERR, "Error while compressing packet to %s (%s)",
                                   n->name, n->hostname);
                        return;
                }
        /* Add sequence number */
  
        inpkt->seqno = htonl(++(n->sent_seqno));
 -      inpkt->len += sizeof(inpkt->seqno);
 +      inpkt->len += sizeof inpkt->seqno;
  
        /* 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;
                }
  
 -              outpkt->len = outlen + outpad;
 +              outpkt->len = outlen;
                inpkt = outpkt;
        }
  
        /* Add the message authentication code */
  
 -      if(n->outdigest && n->outmaclength) {
 -              HMAC(n->outdigest, n->outkey, n->outkeylength, (unsigned char *) &inpkt->seqno,
 -                       inpkt->len, (unsigned char *) &inpkt->seqno + inpkt->len, NULL);
 -              inpkt->len += n->outmaclength;
 +      if(digest_active(&n->outdigest)) {
 +              digest_create(&n->outdigest, &inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len);
 +              inpkt->len += digest_length(&n->outdigest);
        }
  
        /* Determine which socket we have to use */
        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
  
                        if(n->mtu >= origlen)
                                n->mtu = origlen - 1;
                } else
-                       logger(LOG_ERR, _("Error sending packet to %s (%s): %s"), n->name, n->hostname, strerror(errno));
+                       logger(LOG_ERR, "Error sending packet to %s (%s): %s", n->name, n->hostname, strerror(errno));
        }
  
  end:
  void send_packet(const node_t *n, vpn_packet_t *packet) {
        node_t *via;
  
-       cp();
        if(n == myself) {
                if(overwrite_mac)
                         memcpy(packet->data, mymac.x, ETH_ALEN);
                return;
        }
  
-       ifdebug(TRAFFIC) logger(LOG_ERR, _("Sending packet of %d bytes to %s (%s)"),
+       ifdebug(TRAFFIC) logger(LOG_ERR, "Sending packet of %d bytes to %s (%s)",
                           packet->len, n->name, n->hostname);
  
        if(!n->status.reachable) {
-               ifdebug(TRAFFIC) logger(LOG_INFO, _("Node %s (%s) is not reachable"),
+               ifdebug(TRAFFIC) logger(LOG_INFO, "Node %s (%s) is not reachable",
                                   n->name, n->hostname);
                return;
        }
        via = (packet->priority == -1 || n->via == myself) ? n->nexthop : n->via;
  
        if(via != n)
-               ifdebug(TRAFFIC) logger(LOG_INFO, _("Sending packet to %s via %s (%s)"),
+               ifdebug(TRAFFIC) logger(LOG_INFO, "Sending packet to %s via %s (%s)",
                           n->name, via->name, n->via->hostname);
  
        if(packet->priority == -1 || ((myself->options | via->options) & OPTION_TCPONLY)) {
  /* 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) {
  }
  
  static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
 -      avl_node_t *node;
 +      splay_node_t *node;
        edge_t *e;
        node_t *n = NULL;
  
        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) {
                if(errno != EAGAIN && errno != EINTR)
-                       logger(LOG_ERR, _("Receiving packet failed: %s"), strerror(errno));
+                       logger(LOG_ERR, "Receiving packet failed: %s", strerror(errno));
                return;
        }
  
                        update_node_udp(n, &from);
                else ifdebug(PROTOCOL) {
                        hostname = sockaddr2hostname(&from);
-                       logger(LOG_WARNING, _("Received UDP packet from unknown source %s"), hostname);
+                       logger(LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
                        free(hostname);
                        return;
                }
  
        receive_udppacket(n, &pkt);
  }
 +
 +void handle_device_data(int sock, short events, void *data) {
 +      vpn_packet_t packet;
 +
 +      if(read_packet(&packet))
 +              route(myself, &packet);
 +}
diff --combined src/net_setup.c
@@@ -2,6 -2,7 +2,7 @@@
      net_setup.c -- Setup.
      Copyright (C) 1998-2005 Ivo Timmermans,
                    2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                   2006      Scott Lamb <slamb@slamb.org>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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.
  */
  
  #include "system.h"
  
 -#include <openssl/pem.h>
 -#include <openssl/rsa.h>
 -#include <openssl/rand.h>
 -#include <openssl/err.h>
 -#include <openssl/evp.h>
 -
 -#include "avl_tree.h"
 +#include "splay_tree.h"
 +#include "cipher.h"
  #include "conf.h"
  #include "connection.h"
 +#include "control.h"
  #include "device.h"
 -#include "event.h"
 +#include "digest.h"
  #include "graph.h"
  #include "logger.h"
  #include "net.h"
  #include "process.h"
  #include "protocol.h"
  #include "route.h"
 +#include "rsa.h"
  #include "subnet.h"
  #include "utils.h"
  #include "xalloc.h"
  
  char *myport;
 +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;
        }
  
 +      /* Else, check for PrivateKeyFile statement and read it */
 +
        if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname))
                xasprintf(&fname, "%s/rsa_key.priv", confbase);
  
        fp = fopen(fname, "r");
  
        if(!fp) {
-               logger(LOG_ERR, _("Error reading RSA private key file `%s': %s"),
+               logger(LOG_ERR, "Error reading RSA private key file `%s': %s",
                           fname, strerror(errno));
                free(fname);
                return false;
        }
  
  #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});
  }
  
  /*
@@@ -172,25 -214,23 +167,23 @@@ bool setup_myself(void) 
        bool choice;
        int i, err;
  
-       cp();
        myself = new_node();
        myself->connection = new_connection();
        init_configuration(&myself->connection->config_tree);
  
-       xasprintf(&myself->hostname, _("MYSELF"));
-       xasprintf(&myself->connection->hostname, _("MYSELF"));
+       xasprintf(&myself->hostname, "MYSELF");
+       xasprintf(&myself->connection->hostname, "MYSELF");
  
        myself->connection->options = 0;
        myself->connection->protocol_version = PROT_CURRENT;
  
        if(!get_config_string(lookup_config(config_tree, "Name"), &name)) {     /* Not acceptable */
-               logger(LOG_ERR, _("Name for tinc daemon required!"));
+               logger(LOG_ERR, "Name for tinc daemon required!");
                return false;
        }
  
        if(!check_id(name)) {
-               logger(LOG_ERR, _("Invalid name for myself!"));
+               logger(LOG_ERR, "Invalid name for myself!");
                free(name);
                return false;
        }
        myself->connection->name = xstrdup(name);
  
        if(!read_connection_config(myself->connection)) {
-               logger(LOG_ERR, _("Cannot open host configuration file for myself!"));
+               logger(LOG_ERR, "Cannot open host configuration file for myself!");
                return false;
        }
  
                else if(!strcasecmp(mode, "hub"))
                        routing_mode = RMODE_HUB;
                else {
-                       logger(LOG_ERR, _("Invalid routing mode!"));
+                       logger(LOG_ERR, "Invalid routing mode!");
                        return false;
                }
                free(mode);
  
  #if !defined(SOL_IP) || !defined(IP_TOS)
        if(priorityinheritance)
-               logger(LOG_WARNING, _("%s not supported on this platform"), "PriorityInheritance");
+               logger(LOG_WARNING, "%s not supported on this platform", "PriorityInheritance");
  #endif
  
        if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire))
  
        if(get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout)) {
                if(maxtimeout <= 0) {
-                       logger(LOG_ERR, _("Bogus maximum timeout!"));
+                       logger(LOG_ERR, "Bogus maximum timeout!");
                        return false;
                }
        } else
                else if(!strcasecmp(afname, "any"))
                        addressfamily = AF_UNSPEC;
                else {
-                       logger(LOG_ERR, _("Invalid address family!"));
+                       logger(LOG_ERR, "Invalid address family!");
                        return false;
                }
                free(afname);
  
        /* 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(get_config_int(lookup_config(myself->connection->config_tree, "Compression"), &myself->incompression)) {
                if(myself->incompression < 0 || myself->incompression > 11) {
-                       logger(LOG_ERR, _("Bogus compression level!"));
+                       logger(LOG_ERR, "Bogus compression level!");
                        return false;
                }
        } else
        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 ? : "");
        err = getaddrinfo(address, myport, &hint, &ai);
  
        if(err || !ai) {
-               logger(LOG_ERR, _("System call `%s' failed: %s"), "getaddrinfo",
+               logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo",
                           gai_strerror(err));
                return false;
        }
                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);
-                       logger(LOG_NOTICE, _("Listening on %s"), hostname);
+                       logger(LOG_NOTICE, "Listening on %s", hostname);
                        free(hostname);
                }
  
                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);
  
        if(listen_sockets)
-               logger(LOG_NOTICE, _("Ready"));
+               logger(LOG_NOTICE, "Ready");
        else {
-               logger(LOG_ERR, _("Unable to create any listening socket!"));
+               logger(LOG_ERR, "Unable to create any listening socket!");
                return false;
        }
  
  /*
    initialize network
  */
- bool setup_network(void)
- {
-       cp();
+ bool setup_network(void) {
 -      now = time(NULL);
 -
 -      init_events();
        init_connections();
        init_subnets();
        init_nodes();
    close all open network connections
  */
  void close_network_connections(void) {
 -      avl_node_t *node, *next;
 +      splay_node_t *node, *next;
        connection_t *c;
        char *envp[5];
        int i;
  
-       cp();
        for(node = connection_tree->head; node; node = next) {
                next = node->next;
                c = node->data;
        }
  
        for(i = 0; i < listen_sockets; i++) {
 +              event_del(&listen_socket[i].ev_tcp);
 +              event_del(&listen_socket[i].ev_udp);
                close(listen_socket[i].tcp);
                close(listen_socket[i].udp);
        }
        exit_subnets();
        exit_nodes();
        exit_connections();
 -      exit_events();
  
        execute_script("tinc-down", envp);
  
diff --combined src/net_socket.c
@@@ -2,6 -2,8 +2,8 @@@
      net_socket.c -- Handle various kinds of sockets.
      Copyright (C) 1998-2005 Ivo Timmermans,
                    2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                   2006      Scott Lamb <slamb@slamb.org>
+                   2009      Florian Forster <octo@verplant.org>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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.
  */
  
  #include "system.h"
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  #include "conf.h"
  #include "connection.h"
 -#include "event.h"
  #include "logger.h"
  #include "meta.h"
  #include "net.h"
@@@ -61,28 -62,28 +61,28 @@@ static void configure_tcp(connection_t 
        int flags = fcntl(c->socket, F_GETFL);
  
        if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0) {
-               logger(LOG_ERR, _("fcntl for %s: %s"), c->hostname, strerror(errno));
+               logger(LOG_ERR, "fcntl for %s: %s", c->hostname, strerror(errno));
        }
  #elif defined(WIN32)
        unsigned long arg = 1;
  
        if(ioctlsocket(c->socket, FIONBIO, &arg) != 0) {
-               logger(LOG_ERR, _("ioctlsocket for %s: WSA error %d"), c->hostname, WSAGetLastError());
+               logger(LOG_ERR, "ioctlsocket for %s: WSA error %d", c->hostname, WSAGetLastError());
        }
  #endif
  
  #if defined(SOL_TCP) && defined(TCP_NODELAY)
        option = 1;
 -      setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof(option));
 +      setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof option);
  #endif
  
  #if defined(SOL_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY)
        option = IPTOS_LOWDELAY;
 -      setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof(option));
 +      setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof option);
  #endif
  }
  
- static bool bind_to_interface(int sd) { /* {{{ */
+ static bool bind_to_interface(int sd) {
        char *iface;
  
  #if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
  
        status = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
        if(status) {
-               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 false;
        }
  #else /* if !defined(SOL_SOCKET) || !defined(SO_BINDTODEVICE) */
-       logger(LOG_WARNING, _("%s not supported on this platform"), "BindToInterface");
+       logger(LOG_WARNING, "%s not supported on this platform", "BindToInterface");
  #endif
  
        return true;
- } /* }}} bool bind_to_interface */
+ }
  
- static bool bind_to_address(connection_t *c) { /* {{{ */
+ static bool bind_to_address(connection_t *c) {
        char *node;
        struct addrinfo *ai_list;
        struct addrinfo *ai_ptr;
                        &ai_hints, &ai_list);
        if(status) {
                free(node);
-               logger(LOG_WARNING, _("Error looking up %s port %s: %s"),
-                               node, _("any"), gai_strerror(status));
+               logger(LOG_WARNING, "Error looking up %s port %s: %s",
+                               node, "any", gai_strerror(status));
                return false;
        }
        assert(ai_list != NULL);
  
  
        if(status) {
-               logger(LOG_ERR, _("Can't bind to %s/tcp: %s"), node,
+               logger(LOG_ERR, "Can't bind to %s/tcp: %s", node,
                                strerror(errno));
        } else ifdebug(CONNECTIONS) {
                logger(LOG_DEBUG, "Successfully bound outgoing "
        freeaddrinfo(ai_list);
  
        return status ? false : true;
- } /* }}} bool bind_to_address */
+ }
  
- int setup_listen_socket(const sockaddr_t *sa)
- {
+ int setup_listen_socket(const sockaddr_t *sa) {
        int nfd;
        char *addrstr;
        int option;
        char *iface;
  
-       cp();
        nfd = socket(sa->sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
  
        if(nfd < 0) {
-               ifdebug(STATUS) logger(LOG_ERR, _("Creating metasocket failed: %s"), strerror(errno));
+               ifdebug(STATUS) logger(LOG_ERR, "Creating metasocket failed: %s", strerror(errno));
                return -1;
        }
  
        /* Optimize TCP settings */
  
        option = 1;
 -      setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
 +      setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof option);
  
  #if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
        if(sa->sa.sa_family == AF_INET6)
  #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;
                }
  #else
-               logger(LOG_WARNING, _("%s not supported on this platform"), "BindToInterface");
+               logger(LOG_WARNING, "%s not supported on this platform", "BindToInterface");
  #endif
        }
  
        if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
                closesocket(nfd);
                addrstr = sockaddr2hostname(sa);
-               logger(LOG_ERR, _("Can't bind to %s/tcp: %s"), addrstr,
+               logger(LOG_ERR, "Can't bind to %s/tcp: %s", addrstr,
                           strerror(errno));
                free(addrstr);
                return -1;
  
        if(listen(nfd, 3)) {
                closesocket(nfd);
-               logger(LOG_ERR, _("System call `%s' failed: %s"), "listen",
+               logger(LOG_ERR, "System call `%s' failed: %s", "listen",
                           strerror(errno));
                return -1;
        }
@@@ -238,12 -236,10 +235,10 @@@ int setup_vpn_in_socket(const sockaddr_
        char *addrstr;
        int option;
  
-       cp();
        nfd = socket(sa->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
  
        if(nfd < 0) {
-               logger(LOG_ERR, _("Creating UDP socket failed: %s"), strerror(errno));
+               logger(LOG_ERR, "Creating UDP socket failed: %s", strerror(errno));
                return -1;
        }
  
  
                if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
                        closesocket(nfd);
-                       logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl",
+                       logger(LOG_ERR, "System call `%s' failed: %s", "fcntl",
                                   strerror(errno));
                        return -1;
                }
                unsigned long arg = 1;
                if(ioctlsocket(nfd, FIONBIO, &arg) != 0) {
                        closesocket(nfd);
-                       logger(LOG_ERR, _("Call to `%s' failed: WSA error %d"), "ioctlsocket",
+                       logger(LOG_ERR, "Call to `%s' failed: WSA error %d", "ioctlsocket",
                                WSAGetLastError());
                        return -1;
                }
  #endif
  
        option = 1;
 -      setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
 +      setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof option);
  
  #if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
        if(sa->sa.sa_family == AF_INET6)
        if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
                closesocket(nfd);
                addrstr = sockaddr2hostname(sa);
-               logger(LOG_ERR, _("Can't bind to %s/udp: %s"), addrstr,
+               logger(LOG_ERR, "Can't bind to %s/udp: %s", addrstr,
                           strerror(errno));
                free(addrstr);
                return -1;
        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);
  }
  
  void finish_connecting(connection_t *c) {
-       cp();
-       ifdebug(CONNECTIONS) logger(LOG_INFO, _("Connected to %s (%s)"), c->name, c->hostname);
+       ifdebug(CONNECTIONS) logger(LOG_INFO, "Connected to %s (%s)", c->name, c->hostname);
  
        configure_tcp(c);
  
 -      c->last_ping_time = now;
 +      c->last_ping_time = time(NULL);
 +      c->status.connecting = false;
  
        send_id(c);
  }
@@@ -346,16 -338,13 +337,14 @@@ void do_outgoing_connection(connection_
        char *address, *port;
        int result;
  
-       cp();
  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;
                }
  
  
        c->hostname = sockaddr2hostname(&c->address);
  
-       ifdebug(CONNECTIONS) logger(LOG_INFO, _("Trying to connect to %s (%s)"), c->name,
+       ifdebug(CONNECTIONS) logger(LOG_INFO, "Trying to connect to %s (%s)", c->name,
                           c->hostname);
  
        c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
  
        if(c->socket == -1) {
-               ifdebug(CONNECTIONS) logger(LOG_ERR, _("Creating socket for %s failed: %s"), c->hostname,
+               ifdebug(CONNECTIONS) logger(LOG_ERR, "Creating socket for %s failed: %s", c->hostname,
                                   strerror(errno));
  
                goto begin;
  
                closesocket(c->socket);
  
-               ifdebug(CONNECTIONS) logger(LOG_ERR, _("%s: %s"), c->hostname, strerror(errno));
+               ifdebug(CONNECTIONS) logger(LOG_ERR, "%s: %s", c->hostname, strerror(errno));
  
                goto begin;
        }
        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;
  
-       cp();
        n = lookup_node(outgoing->name);
  
        if(n)
                if(n->connection) {
-                       ifdebug(CONNECTIONS) logger(LOG_INFO, _("Already connected to %s"), outgoing->name);
+                       ifdebug(CONNECTIONS) logger(LOG_INFO, "Already connected to %s", outgoing->name);
  
                        n->connection->outgoing = outgoing;
                        return;
        outgoing->cfg = lookup_config(c->config_tree, "Address");
  
        if(!outgoing->cfg) {
-               logger(LOG_ERR, _("No address specified for %s"), c->name);
+               logger(LOG_ERR, "No address specified for %s", c->name);
                free_connection(c);
                return;
        }
  
        c->outgoing = outgoing;
 -      c->last_ping_time = now;
 +      c->last_ping_time = time(NULL);
  
        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);
  }
  
  /*
    accept a new tcp connect and create a
    new connection
  */
 -bool handle_new_meta_connection(int sock) {
 +void handle_new_meta_connection(int sock, short events, void *data) {
        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);
  
        c->allow_request = ID;
        send_id(c);
 -
 -      return true;
  }
  
  void free_outgoing(outgoing_t *outgoing) {
        free(outgoing);
  }
  
- void try_outgoing_connections(void)
- {
+ void try_outgoing_connections(void) {
        static config_t *cfg = NULL;
        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;
  
                if(!check_id(name)) {
                        logger(LOG_ERR,
-                                  _("Invalid name for outgoing connection in %s line %d"),
+                                  "Invalid name for outgoing connection in %s line %d",
                                   cfg->file, cfg->line);
                        free(name);
                        continue;
                }
  
 -              outgoing = xmalloc_and_zero(sizeof(*outgoing));
 +              outgoing = xmalloc_and_zero(sizeof *outgoing);
                outgoing->name = name;
                list_insert_tail(outgoing_list, outgoing);
                setup_outgoing_connection(outgoing);
diff --combined src/netutl.c
@@@ -1,7 -1,7 +1,7 @@@
  /*
      netutl.c -- some supporting network utility code
      Copyright (C) 1998-2005 Ivo Timmermans
-                   2000-2006 Guus Sliepen <guus@tinc-vpn.org>
+                   2000-2009 Guus Sliepen <guus@tinc-vpn.org>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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.
  */
  
  #include "system.h"
@@@ -38,15 -36,13 +36,13 @@@ struct addrinfo *str2addrinfo(const cha
        struct addrinfo *ai, hint = {0};
        int err;
  
-       cp();
        hint.ai_family = addressfamily;
        hint.ai_socktype = socktype;
  
        err = getaddrinfo(address, service, &hint, &ai);
  
        if(err) {
-               logger(LOG_WARNING, _("Error looking up %s port %s: %s"), address,
+               logger(LOG_WARNING, "Error looking up %s port %s: %s", address,
                                   service, gai_strerror(err));
                return NULL;
        }
@@@ -59,8 -55,6 +55,6 @@@ sockaddr_t str2sockaddr(const char *add
        sockaddr_t result;
        int err;
  
-       cp();
        hint.ai_family = AF_UNSPEC;
        hint.ai_flags = AI_NUMERICHOST;
        hint.ai_socktype = SOCK_STREAM;
@@@ -88,20 -82,17 +82,17 @@@ void sockaddr2str(const sockaddr_t *sa
        char *scopeid;
        int err;
  
-       cp();
        if(sa->sa.sa_family == AF_UNKNOWN) {
                *addrstr = xstrdup(sa->unknown.address);
                *portstr = xstrdup(sa->unknown.port);
                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);
        }
@@@ -121,31 -112,26 +112,26 @@@ char *sockaddr2hostname(const sockaddr_
        char port[NI_MAXSERV] = "unknown";
        int err;
  
-       cp();
        if(sa->sa.sa_family == AF_UNKNOWN) {
-               xasprintf(&str, _("%s port %s"), sa->unknown.address, sa->unknown.port);
+               xasprintf(&str, "%s port %s", sa->unknown.address, sa->unknown.port);
                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));
        }
  
-       xasprintf(&str, _("%s port %s"), address, port);
+       xasprintf(&str, "%s port %s", address, port);
  
        return str;
  }
  
- int sockaddrcmp_noport(const sockaddr_t *a, const sockaddr_t *b)
- {
+ int sockaddrcmp_noport(const sockaddr_t *a, const sockaddr_t *b) {
        int result;
  
-       cp();
        result = a->sa.sa_family - b->sa.sa_family;
  
        if(result)
                        return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
  
                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);
        }
  }
  
- int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b)
- {
+ int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b) {
        int result;
  
-       cp();
        result = a->sa.sa_family - b->sa.sa_family;
  
        if(result)
                        return strcmp(a->unknown.port, b->unknown.port);
  
                case AF_INET:
 -                      result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr));
 +                      result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof a->in.sin_addr);
  
                        if(result)
                                return result;
  
 -                      return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof(a->in.sin_port));
 +                      return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof a->in.sin_port);
  
                case AF_INET6:
 -                      result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
 +                      result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof a->in6.sin6_addr);
  
                        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);
        }
  }
  
  void sockaddrcpy(sockaddr_t *a, const sockaddr_t *b) {
-       cp();
        if(b->sa.sa_family != AF_UNKNOWN) {
                *a = *b;
        } else {
  }
  
  void sockaddrfree(sockaddr_t *a) {
-       cp();
        if(a->sa.sa_family == AF_UNKNOWN) {
                free(a->unknown.address);
                free(a->unknown.port);
  }
        
  void sockaddrunmap(sockaddr_t *sa) {
-       cp();
        if(sa->sa.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr)) {
                sa->in.sin_addr.s_addr = ((uint32_t *) & sa->in6.sin6_addr)[3];
                sa->in.sin_family = AF_INET;
@@@ -258,8 -233,6 +233,6 @@@ int maskcmp(const void *va, const void 
        const char *a = va;
        const char *b = vb;
  
-       cp();
        for(m = masklen, i = 0; m >= 8; m -= 8, i++) {
                result = a[i] - b[i];
                if(result)
@@@ -277,8 -250,6 +250,6 @@@ void mask(void *va, int masklen, int le
        int i;
        char *a = va;
  
-       cp();
        i = masklen / 8;
        masklen %= 8;
  
@@@ -294,8 -265,6 +265,6 @@@ void maskcpy(void *va, const void *vb, 
        char *a = va;
        const char *b = vb;
  
-       cp();
        for(m = masklen, i = 0; m >= 8; m -= 8, i++)
                a[i] = b[i];
  
@@@ -312,8 -281,6 +281,6 @@@ bool maskcheck(const void *va, int mask
        int i;
        const char *a = va;
  
-       cp();
        i = masklen / 8;
        masklen %= 8;
  
diff --combined src/node.c
      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.
  */
  
  #include "system.h"
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  #include "logger.h"
  #include "net.h"
  #include "netutl.h"
@@@ -30,8 -28,8 +28,8 @@@
  #include "utils.h"
  #include "xalloc.h"
  
 -avl_tree_t *node_tree;                        /* Known nodes, sorted by name */
 -avl_tree_t *node_udp_tree;            /* Known nodes, sorted by address and port */
 +splay_tree_t *node_tree;                      /* Known nodes, sorted by name */
 +splay_tree_t *node_udp_tree;          /* Known nodes, sorted by address and port */
  
  node_t *myself;
  
@@@ -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);
  
  
        sockaddrfree(&n->address);
  
 -      EVP_CIPHER_CTX_cleanup(&n->inctx);
 -      EVP_CIPHER_CTX_cleanup(&n->outctx);
 +      cipher_close(&n->incipher);
 +      digest_close(&n->indigest);
 +      cipher_close(&n->outcipher);
 +      digest_close(&n->outdigest);
  
 -      if(n->mtuevent)
 -              event_del(n->mtuevent);
 +      event_del(&n->mtuevent);
        
        if(n->hostname)
                free(n->hostname);
  }
  
  void node_add(node_t *n) {
-       cp();
 -      avl_insert(node_tree, n);
 +      splay_insert(node_tree, n);
  }
  
  void node_del(node_t *n) {
 -      avl_node_t *node, *next;
 +      splay_node_t *node, *next;
        edge_t *e;
        subnet_t *s;
  
-       cp();
        for(node = n->subnet_tree->head; node; node = next) {
                next = node->next;
                s = node->data;
                edge_del(e);
        }
  
 -      avl_delete(node_udp_tree, n);
 -      avl_delete(node_tree, n);
 +      splay_delete(node_udp_tree, n);
 +      splay_delete(node_tree, 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) {
        node_t n = {0};
  
-       cp();
        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);
        if(sa) {
                n->address = *sa;
                n->hostname = sockaddr2hostname(&n->address);
 -              avl_insert(node_udp_tree, n);
 -              ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
 +              splay_insert(node_udp_tree, n);
 +              logger(LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
        } else {
                memset(&n->address, 0, sizeof n->address);
                n->hostname = 0;
        }
  }
  
 -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 --combined src/node.h
      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_NODE_H__
  #define __TINC_NODE_H__
  
 -#include "avl_tree.h"
 +#include <event.h>
 +
 +#include "splay_tree.h"
 +#include "cipher.h"
  #include "connection.h"
 -#include "event.h"
 +#include "digest.h"
  #include "list.h"
  #include "subnet.h"
  
@@@ -51,22 -46,31 +49,22 @@@ typedef struct node_t 
  
        node_status_t status;
  
 -      const EVP_CIPHER *incipher;             /* Cipher type for UDP packets received from him */
 -      char *inkey;                            /* Cipher key and iv */
 -      int inkeylength;                        /* Cipher key and iv length */
 -      EVP_CIPHER_CTX inctx;                   /* Cipher context */
 -      
 -      const EVP_CIPHER *outcipher;            /* Cipher type for UDP packets sent to him*/
 -      char *outkey;                           /* Cipher key and iv */
 -      int outkeylength;                       /* Cipher key and iv length */
 -      EVP_CIPHER_CTX outctx;                  /* Cipher context */
 -      
 -      const EVP_MD *indigest;                 /* Digest type for MAC of packets received from him */
 -      int inmaclength;                        /* Length of MAC */
 -
 -      const EVP_MD *outdigest;                /* Digest type for MAC of packets sent to him*/
 -      int outmaclength;                       /* Length of MAC */
 +      cipher_t incipher;                        /* Cipher for UDP packets */
 +      digest_t indigest;                        /* Digest for UDP packets */  
 +
 +      cipher_t outcipher;                        /* Cipher for UDP packets */
 +      digest_t outdigest;                        /* Digest for UDP packets */ 
  
        int incompression;                      /* Compressionlevel, 0 = no compression */
        int outcompression;                     /* Compressionlevel, 0 = no compression */
  
 +      int distance;
        struct node_t *nexthop;                 /* nearest node from us to him */
        struct node_t *via;                     /* next hop for UDP packets */
  
 -      avl_tree_t *subnet_tree;                /* Pointer to a tree of subnets belonging to this node */
 +      splay_tree_t *subnet_tree;              /* Pointer to a tree of subnets belonging to this node */
  
 -      avl_tree_t *edge_tree;                  /* Edges with this node as one of the endpoints */
 +      splay_tree_t *edge_tree;                        /* Edges with this node as one of the endpoints */
  
        struct connection_t *connection;        /* Connection associated with this node (if a direct connection exists) */
  
        length_t minmtu;                        /* Probed minimum MTU */
        length_t maxmtu;                        /* Probed maximum MTU */
        int mtuprobes;                          /* Number of probes */
 -      event_t *mtuevent;                      /* Probe event */
 +      struct event mtuevent;                  /* Probe event */
  } node_t;
  
  extern struct node_t *myself;
 -extern avl_tree_t *node_tree;
 -extern avl_tree_t *node_udp_tree;
 +extern splay_tree_t *node_tree;
 +extern splay_tree_t *node_udp_tree;
  
  extern void init_nodes(void);
  extern void exit_nodes(void);
@@@ -93,7 -97,7 +91,7 @@@ extern void node_add(node_t *)
  extern void node_del(node_t *);
  extern node_t *lookup_node(char *);
  extern node_t *lookup_node_udp(const sockaddr_t *);
 +extern int dump_nodes(struct evbuffer *);
  extern void update_node_udp(node_t *, const sockaddr_t *);
 -extern void dump_nodes(void);
  
  #endif                                                        /* __TINC_NODE_H__ */
diff --combined src/openssl/rsagen.h
@@@ -1,6 -1,7 +1,6 @@@
  /*
 -    event.h -- header for event.c
 -    Copyright (C) 2002-2009 Guus Sliepen <guus@tinc-vpn.org>,
 -                  2002-2005 Ivo Timmermans
 +    rsagen.h -- RSA key generation and export
 +    Copyright (C) 2008 Guus Sliepen <guus@tinc-vpn.org>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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 --combined src/process.c
@@@ -1,7 -1,7 +1,7 @@@
  /*
      process.c -- process management functions
      Copyright (C) 1999-2005 Ivo Timmermans,
-                   2000-2007 Guus Sliepen <guus@tinc-vpn.org>
+                   2000-2009 Guus Sliepen <guus@tinc-vpn.org>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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.
  */
  
  #include "system.h"
  
  #include "conf.h"
  #include "connection.h"
 +#include "control.h"
  #include "device.h"
  #include "edge.h"
  #include "logger.h"
  #include "node.h"
 -#include "pidfile.h"
  #include "process.h"
  #include "subnet.h"
  #include "utils.h"
  
  /* If zero, don't detach from the terminal. */
  bool do_detach = true;
 -bool sighup = false;
  bool sigalrm = false;
  
  extern char *identname;
 -extern char *pidfilename;
  extern char **g_argv;
  extern bool use_logfile;
 -extern volatile bool running;
  
  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);
  }
  
@@@ -70,7 -72,7 +67,7 @@@ bool install_service(void) 
  
        manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
        if(!manager) {
-               logger(LOG_ERR, _("Could not open service manager: %s"), winerror(GetLastError()));
+               logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError()));
                return false;
        }
  
                        command, NULL, NULL, NULL, NULL, NULL);
        
        if(!service) {
-               logger(LOG_ERR, _("Could not create %s service: %s"), identname, winerror(GetLastError()));
+               logger(LOG_ERR, "Could not create %s service: %s", identname, winerror(GetLastError()));
                return false;
        }
  
        ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description);
  
-       logger(LOG_INFO, _("%s service installed"), identname);
+       logger(LOG_INFO, "%s service installed", identname);
  
        if(!StartService(service, 0, NULL))
-               logger(LOG_WARNING, _("Could not start %s service: %s"), identname, winerror(GetLastError()));
+               logger(LOG_WARNING, "Could not start %s service: %s", identname, winerror(GetLastError()));
        else
-               logger(LOG_INFO, _("%s service started"), identname);
+               logger(LOG_INFO, "%s service started", identname);
  
        return true;
  }
  bool remove_service(void) {
        manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
        if(!manager) {
-               logger(LOG_ERR, _("Could not open service manager: %s"), winerror(GetLastError()));
+               logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError()));
                return false;
        }
  
        service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
  
        if(!service) {
-               logger(LOG_ERR, _("Could not open %s service: %s"), identname, winerror(GetLastError()));
+               logger(LOG_ERR, "Could not open %s service: %s", identname, winerror(GetLastError()));
                return false;
        }
  
        if(!ControlService(service, SERVICE_CONTROL_STOP, &status))
-               logger(LOG_ERR, _("Could not stop %s service: %s"), identname, winerror(GetLastError()));
+               logger(LOG_ERR, "Could not stop %s service: %s", identname, winerror(GetLastError()));
        else
-               logger(LOG_INFO, _("%s service stopped"), identname);
+               logger(LOG_INFO, "%s service stopped", identname);
  
        if(!DeleteService(service)) {
-               logger(LOG_ERR, _("Could not remove %s service: %s"), identname, winerror(GetLastError()));
+               logger(LOG_ERR, "Could not remove %s service: %s", identname, winerror(GetLastError()));
                return false;
        }
  
-       logger(LOG_INFO, _("%s service removed"), identname);
+       logger(LOG_INFO, "%s service removed", identname);
  
        return true;
  }
@@@ -152,21 -154,29 +149,21 @@@ DWORD WINAPI controlhandler(DWORD reque
                        SetServiceStatus(statushandle, &status);
                        return NO_ERROR;
                case SERVICE_CONTROL_STOP:
-                       logger(LOG_NOTICE, _("Got %s request"), "SERVICE_CONTROL_STOP");
+                       logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_STOP");
                        break;
                case SERVICE_CONTROL_SHUTDOWN:
-                       logger(LOG_NOTICE, _("Got %s request"), "SERVICE_CONTROL_SHUTDOWN");
+                       logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_SHUTDOWN");
                        break;
                default:
-                       logger(LOG_WARNING, _("Got unexpected request %d"), request);
+                       logger(LOG_WARNING, "Got unexpected request %d", request);
                        return ERROR_CALL_NOT_IMPLEMENTED;
        }
  
 -      if(running) {
 -              running = false;
 -              status.dwWaitHint = 30000; 
 -              status.dwCurrentState = SERVICE_STOP_PENDING; 
 -              SetServiceStatus(statushandle, &status);
 -              return NO_ERROR;
 -      } else {
 -              status.dwWaitHint = 0; 
 -              status.dwCurrentState = SERVICE_STOPPED; 
 -              SetServiceStatus(statushandle, &status);
 -              exit(1);
 -      }
 -
 +      event_loopexit(NULL);
 +      status.dwWaitHint = 30000; 
 +      status.dwCurrentState = SERVICE_STOP_PENDING; 
 +      SetServiceStatus(statushandle, &status);
 +      return NO_ERROR;
  }
  
  VOID WINAPI run_service(DWORD argc, LPTSTR* argv) {
        statushandle = RegisterServiceCtrlHandlerEx(identname, controlhandler, NULL); 
  
        if (!statushandle) {
-               logger(LOG_ERR, _("System call `%s' failed: %s"), "RegisterServiceCtrlHandlerEx", winerror(GetLastError()));
+               logger(LOG_ERR, "System call `%s' failed: %s", "RegisterServiceCtrlHandlerEx", winerror(GetLastError()));
                err = 1;
        } else {
                status.dwWaitHint = 30000; 
@@@ -216,32 -226,110 +213,30 @@@ bool init_service(void) 
                        return false;
                }
                else
-                       logger(LOG_ERR, _("System call `%s' failed: %s"), "StartServiceCtrlDispatcher", winerror(GetLastError()));
+                       logger(LOG_ERR, "System call `%s' failed: %s", "StartServiceCtrlDispatcher", winerror(GetLastError()));
        }
  
        return true;
  }
  #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
  
        if(do_detach) {
  #ifndef HAVE_MINGW
                if(daemon(0, 0)) {
-                       fprintf(stderr, _("Couldn't detach from terminal: %s"),
+                       fprintf(stderr, "Couldn't detach from terminal: %s",
                                        strerror(errno));
                        return false;
                }
 -
 -              /* Now UPDATE the pid in the pidfile, because we changed it... */
 -
 -              if(!write_pid(pidfilename)) {
 -                      fprintf(stderr, "Could not write pid file %s: %s\n", pidfilename, strerror(errno));
 -                      return false;
 -              }
  #else
                if(!statushandle)
                        exit(install_service());
  
        openlogger(identname, use_logfile?LOGMODE_FILE:(do_detach?LOGMODE_SYSLOG:LOGMODE_STDERR));
  
-       logger(LOG_NOTICE, _("tincd %s (%s %s) starting, debug level %d"),
+       logger(LOG_NOTICE, "tincd %s (%s %s) starting, debug level %d",
                           VERSION, __DATE__, __TIME__, debug_level);
  
        xalloc_fail_func = memory_full;
@@@ -264,8 -352,6 +259,6 @@@ bool execute_script(const char *name, c
        char *scriptname, *p;
        int i;
  
-       cp();
  #ifndef HAVE_MINGW
        len = xasprintf(&scriptname, "\"%s/%s\"", confbase, name);
  #else
        }
  #endif
  
-       ifdebug(STATUS) logger(LOG_INFO, _("Executing script %s"), name);
+       ifdebug(STATUS) logger(LOG_INFO, "Executing script %s", name);
  
  #ifdef HAVE_PUTENV
        /* Set environment */
        if(status != -1) {
                if(WIFEXITED(status)) { /* Child exited by itself */
                        if(WEXITSTATUS(status)) {
-                               logger(LOG_ERR, _("Script %s exited with non-zero status %d"),
+                               logger(LOG_ERR, "Script %s exited with non-zero status %d",
                                           name, WEXITSTATUS(status));
                                return false;
                        }
                } else if(WIFSIGNALED(status)) {        /* Child was killed by a signal */
-                       logger(LOG_ERR, _("Script %s was killed by signal %d (%s)"),
+                       logger(LOG_ERR, "Script %s was killed by signal %d (%s)",
                                   name, WTERMSIG(status), strsignal(WTERMSIG(status)));
                        return false;
                } else {                        /* Something strange happened */
-                       logger(LOG_ERR, _("Script %s terminated abnormally"), name);
+                       logger(LOG_ERR, "Script %s terminated abnormally", name);
                        return false;
                }
        } else {
-               logger(LOG_ERR, _("System call `%s' failed: %s"), "system", strerror(errno));
+               logger(LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno));
                return false;
        }
  #endif
  */
  
  #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);
  }
  
  static RETSIGTYPE fatal_signal_handler(int a) {
        struct sigaction act;
-       logger(LOG_ERR, _("Got fatal signal %d (%s)"), a, strsignal(a));
-       cp_trace();
+       logger(LOG_ERR, "Got fatal signal %d (%s)", a, strsignal(a));
  
        if(do_detach) {
-               logger(LOG_NOTICE, _("Trying to re-execute in 5 seconds..."));
+               logger(LOG_NOTICE, "Trying to re-execute in 5 seconds...");
  
                act.sa_handler = fatal_signal_square;
                act.sa_mask = emptysigset;
  
                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) {
-       ifdebug(SCARY_THINGS) logger(LOG_DEBUG, _("Ignored signal %d (%s)"), a, strsignal(a));
+       ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Ignored signal %d (%s)", a, strsignal(a));
  }
  
  static struct {
        int signal;
        void (*handler)(int);
  } sighandlers[] = {
 -      {SIGHUP, sighup_handler},
 -      {SIGTERM, sigterm_handler},
 -      {SIGQUIT, sigquit_handler},
        {SIGSEGV, fatal_signal_handler},
        {SIGBUS, fatal_signal_handler},
        {SIGILL, fatal_signal_handler},
        {SIGPIPE, ignore_signal_handler},
 -      {SIGINT, sigint_handler},
 -      {SIGUSR1, sigusr1_handler},
 -      {SIGUSR2, sigusr2_handler},
        {SIGCHLD, ignore_signal_handler},
 -      {SIGALRM, sigalrm_handler},
 -      {SIGWINCH, sigwinch_handler},
        {0, NULL}
  };
  #endif
@@@ -416,14 -565,14 +406,14 @@@ void setup_signals(void) 
  
        /* If we didn't detach, allow coredumps */
        if(!do_detach)
 -              sighandlers[3].handler = SIG_DFL;
 +              sighandlers[0].handler = SIG_DFL;
  
        /* Then, for each known signal that we want to catch, assign a
           handler to the signal, with error checking this time. */
        for(i = 0; sighandlers[i].signal; i++) {
                act.sa_handler = sighandlers[i].handler;
                if(sigaction(sighandlers[i].signal, &act, NULL) < 0)
-                       fprintf(stderr, _("Installing signal handler for signal %d (%s) failed: %s\n"),
+                       fprintf(stderr, "Installing signal handler for signal %d (%s) failed: %s\n",
                                        sighandlers[i].signal, strsignal(sighandlers[i].signal),
                                        strerror(errno));
        }
diff --combined src/process.h
      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_PROCESS_H__
  #define __TINC_PROCESS_H__
  
  extern bool do_detach;
 -extern bool sighup;
  extern bool sigalrm;
  
  extern void setup_signals(void);
diff --combined src/protocol.c
@@@ -1,7 -1,7 +1,7 @@@
  /*
      protocol.c -- handle the meta-protocol, basic functions
      Copyright (C) 1999-2005 Ivo Timmermans,
-                   2000-2006 Guus Sliepen <guus@tinc-vpn.org>
+                   2000-2009 Guus Sliepen <guus@tinc-vpn.org>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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.
  */
  
  #include "system.h"
@@@ -34,7 -32,7 +32,7 @@@ bool tunnelserver = false
  
  /* Jumptable for the request handlers */
  
 -static bool (*request_handlers[])(connection_t *) = {
 +static bool (*request_handlers[])(connection_t *, char *) = {
                id_h, metakey_h, challenge_h, chal_reply_h, ack_h,
                status_h, error_h, termreq_h,
                ping_h, pong_h,
@@@ -53,7 -51,7 +51,7 @@@ static char (*request_name[]) = 
                "ADD_EDGE", "DEL_EDGE", "KEY_CHANGED", "REQ_KEY", "ANS_KEY", "PACKET",
  };
  
 -static avl_tree_t *past_request_tree;
 +static splay_tree_t *past_request_tree;
  
  bool check_id(const char *id) {
        for(; *id; 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 */
  
        va_start(args, format);
 -      len = vsnprintf(buffer, MAXBUFSIZE, format, args);
 +      len = vsnprintf(request, MAXBUFSIZE, format, args);
        va_end(args);
  
        if(len < 0 || len > MAXBUFSIZE - 1) {
-               logger(LOG_ERR, _("Output buffer overflow while sending request to %s (%s)"),
+               logger(LOG_ERR, "Output buffer overflow while sending request to %s (%s)",
                           c->name, c->hostname);
                return false;
        }
  
        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 {
-               logger(LOG_ERR, _("Bogus data received from %s (%s)"),
+               logger(LOG_ERR, "Bogus data received from %s (%s)",
                           c->name, c->hostname);
                return false;
        }
@@@ -175,74 -173,53 +167,64 @@@ static int past_request_compare(const p
  }
  
  static void free_past_request(past_request_t *r) {
-       cp();
        if(r->request)
                free(r->request);
  
        free(r);
  }
  
 -void init_requests(void) {
 -      past_request_tree = avl_alloc_tree((avl_compare_t) past_request_compare, (avl_action_t) free_past_request);
 -}
 -
 -void exit_requests(void) {
 -      avl_delete_tree(past_request_tree);
 -}
 +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(p->firstseen + pinginterval < now)
 -                      avl_delete_node(past_request_tree, node), deleted++;
 +                      splay_delete_node(past_request_tree, node), deleted++;
                else
                        left++;
        }
  
        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 --combined src/protocol.h
@@@ -1,7 -1,7 +1,7 @@@
  /*
      protocol.h -- header for protocol.c
      Copyright (C) 1999-2005 Ivo Timmermans,
-                   2000-2006 Guus Sliepen <guus@tinc-vpn.org>
+                   2000-2009 Guus Sliepen <guus@tinc-vpn.org>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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_PROTOCOL_H__
@@@ -72,13 -70,14 +70,13 @@@ extern bool tunnelserver
  /* Basic functions */
  
  extern bool send_request(struct connection_t *, const char *, ...) __attribute__ ((__format__(printf, 2, 3)));
 -extern void forward_request(struct connection_t *);
 -extern bool receive_request(struct connection_t *);
 +extern void forward_request(struct connection_t *, char *);
 +extern bool receive_request(struct connection_t *, char *);
  extern bool check_id(const char *);
  
  extern void init_requests(void);
  extern void exit_requests(void);
  extern bool seen_request(char *);
 -extern void age_past_requests(void);
  
  /* Requests */
  
@@@ -103,23 -102,23 +101,23 @@@ extern bool send_tcppacket(struct conne
  
  /* Request handlers  */
  
 -extern bool id_h(struct connection_t *);
 -extern bool metakey_h(struct connection_t *);
 -extern bool challenge_h(struct connection_t *);
 -extern bool chal_reply_h(struct connection_t *);
 -extern bool ack_h(struct connection_t *);
 -extern bool status_h(struct connection_t *);
 -extern bool error_h(struct connection_t *);
 -extern bool termreq_h(struct connection_t *);
 -extern bool ping_h(struct connection_t *);
 -extern bool pong_h(struct connection_t *);
 -extern bool add_subnet_h(struct connection_t *);
 -extern bool del_subnet_h(struct connection_t *);
 -extern bool add_edge_h(struct connection_t *);
 -extern bool del_edge_h(struct connection_t *);
 -extern bool key_changed_h(struct connection_t *);
 -extern bool req_key_h(struct connection_t *);
 -extern bool ans_key_h(struct connection_t *);
 -extern bool tcppacket_h(struct connection_t *);
 +extern bool id_h(struct connection_t *, char *);
 +extern bool metakey_h(struct connection_t *, char *);
 +extern bool challenge_h(struct connection_t *, char *);
 +extern bool chal_reply_h(struct connection_t *, char *);
 +extern bool ack_h(struct connection_t *, char *);
 +extern bool status_h(struct connection_t *, char *);
 +extern bool error_h(struct connection_t *, char *);
 +extern bool termreq_h(struct connection_t *, char *);
 +extern bool ping_h(struct connection_t *, char *);
 +extern bool pong_h(struct connection_t *, char *);
 +extern bool add_subnet_h(struct connection_t *, char *);
 +extern bool del_subnet_h(struct connection_t *, char *);
 +extern bool add_edge_h(struct connection_t *, char *);
 +extern bool del_edge_h(struct connection_t *, char *);
 +extern bool key_changed_h(struct connection_t *, char *);
 +extern bool req_key_h(struct connection_t *, char *);
 +extern bool ans_key_h(struct connection_t *, char *);
 +extern bool tcppacket_h(struct connection_t *, char *);
  
  #endif                                                        /* __TINC_PROTOCOL_H__ */
diff --combined src/protocol_auth.c
      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.
  */
  
  #include "system.h"
  
 -#include <openssl/sha.h>
 -#include <openssl/rand.h>
 -#include <openssl/err.h>
 -#include <openssl/evp.h>
 -
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  #include "conf.h"
  #include "connection.h"
 +#include "crypto.h"
  #include "edge.h"
  #include "graph.h"
  #include "logger.h"
  #include "netutl.h"
  #include "node.h"
  #include "protocol.h"
 +#include "rsa.h"
  #include "utils.h"
  #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;
        }
@@@ -60,7 -55,7 +54,7 @@@
        /* Check if identity is a valid name */
  
        if(!check_id(name)) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ID", c->name,
+               logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ID", c->name,
                           c->hostname, "invalid name");
                return false;
        }
@@@ -69,7 -64,7 +63,7 @@@
  
        if(c->outgoing) {
                if(strcmp(c->name, name)) {
-                       logger(LOG_ERR, _("Peer %s is %s instead of %s"), c->hostname, name,
+                       logger(LOG_ERR, "Peer %s is %s instead of %s", c->hostname, name,
                                   c->name);
                        return false;
                }
@@@ -82,7 -77,7 +76,7 @@@
        /* Check if version matches */
  
        if(c->protocol_version != myself->connection->protocol_version) {
-               logger(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"),
+               logger(LOG_ERR, "Peer %s (%s) uses incompatible version %d",
                           c->name, c->hostname, c->protocol_version);
                return false;
        }
@@@ -98,7 -93,7 +92,7 @@@
                init_configuration(&c->config_tree);
  
                if(!read_connection_config(c)) {
-                       logger(LOG_ERR, _("Peer %s had unknown identity (%s)"), c->hostname,
+                       logger(LOG_ERR, "Peer %s had unknown identity (%s)", c->hostname,
                                   c->name);
                        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;
        }
  
        /* Convert the encrypted random data to a hexadecimal formatted string */
  
 -      bin2hex(buffer, buffer, len);
 -      buffer[len * 2] = '\0';
 +      bin2hex(enckey, hexkey, len);
 +      hexkey[len * 2] = '\0';
  
        /* 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;
        }
  
 -      /* Allocate buffers for the meta key */
 -
 -      c->inkey = xrealloc(c->inkey, len);
 -
 -      if(!c->inctx)
 -              c->inctx = xmalloc_and_zero(sizeof(*c->inctx));
 -
        /* Convert the challenge from hexadecimal back to binary */
  
 -      hex2bin(buffer, buffer, len);
 +      hex2bin(hexkey, enckey, len);
  
        /* 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 */
  
 -      RAND_pseudo_bytes((unsigned char *)c->hischallenge, len);
 +      randomize(c->hischallenge, len);
  
        /* Convert to hex */
  
        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;
        }
  
 -      len = RSA_size(myself->connection->rsa_key);
 -
        /* 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;
        }
  
 -      /* Allocate buffers for the challenge */
 -
 -      c->mychallenge = xrealloc(c->mychallenge, len);
 -
        /* Convert the challenge from hexadecimal back to binary */
  
 -      hex2bin(buffer, c->mychallenge, len);
 +      hex2bin(buffer, buffer, len);
  
        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 */
  
 -      bin2hex(hash, hash, c->indigest->md_size);
 -      hash[c->indigest->md_size * 2] = '\0';
 +      bin2hex(digest, buffer, digestlen);
 +      buffer[digestlen * 2] = '\0';
  
        /* 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;
        }
  
           Send an acknowledgement with the rest of the information needed.
         */
  
 +      free(c->hischallenge);
 +      c->hischallenge = NULL;
        c->allow_request = ACK;
  
        return send_ack(c);
@@@ -348,8 -437,6 +330,6 @@@ bool send_ack(connection_t *c) 
        struct timeval now;
        bool choice;
  
-       cp();
        /* Estimate weight */
  
        gettimeofday(&now, NULL);
  }
  
  static void send_everything(connection_t *c) {
 -      avl_node_t *node, *node2;
 +      splay_node_t *node, *node2;
        node_t *n;
        subnet_t *s;
        edge_t *e;
        }
  }
  
 -bool ack_h(connection_t *c) {
 +bool ack_h(connection_t *c, char *request) {
        char hisport[MAX_STRING_SIZE];
        char *hisaddress, *dummy;
        int weight, mtu;
        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();
        c->allow_request = ALL;
        c->status.active = true;
  
-       ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Connection with %s (%s) activated"), c->name,
+       ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection with %s (%s) activated", c->name,
                           c->hostname);
  
        /* Send him everything we know */
        /* Create an edge_t for this connection */
  
        c->edge = new_edge();
-       cp();
        c->edge->from = myself;
        c->edge->to = n;
        sockaddr2str(&c->address, &hisaddress, &dummy);
diff --combined src/protocol_edge.c
@@@ -1,7 -1,8 +1,8 @@@
  /*
      protocol_edge.c -- handle the meta-protocol, edges
      Copyright (C) 1999-2005 Ivo Timmermans,
-                   2000-2006 Guus Sliepen <guus@tinc-vpn.org>
+                   2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                   2009      Michael Tokarev <mjt@corpit.ru>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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.
  */
  
  #include "system.h"
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  #include "conf.h"
  #include "connection.h"
  #include "edge.h"
@@@ -40,8 -39,6 +39,6 @@@ bool send_add_edge(connection_t *c, con
        bool x;
        char *address, *port;
  
-       cp();
        sockaddr2str(&e->address, &address, &port);
  
        x = send_request(c, "%d %x %s %s %s %s %lx %d", ADD_EDGE, rand(),
@@@ -53,7 -50,7 +50,7 @@@
        return x;
  }
  
 -bool add_edge_h(connection_t *c) {
 +bool add_edge_h(connection_t *c, char *request) {
        edge_t *e;
        node_t *from, *to;
        char from_name[MAX_STRING_SIZE];
        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;
        }
        /* Check if names are valid */
  
        if(!check_id(from_name)) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_EDGE", c->name,
-                          c->hostname, _("invalid name"));
+               logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name,
+                          c->hostname, "invalid name");
                return false;
        }
  
        if(!check_id(to_name)) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_EDGE", c->name,
-                          c->hostname, _("invalid name"));
+               logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name,
+                          c->hostname, "invalid name");
                return false;
        }
  
 -      if(seen_request(c->buffer))
 +      if(seen_request(request))
                return true;
  
        /* Lookup nodes */
           to != myself && to != c->node) {
                /* ignore indirect edge registrations for tunnelserver */
                ifdebug(PROTOCOL) logger(LOG_WARNING,
-                  _("Ignoring indirect %s from %s (%s)"),
+                  "Ignoring indirect %s from %s (%s)",
                   "ADD_EDGE", c->name, c->hostname);
                return true;
        }
        if(e) {
                if(e->weight != weight || e->options != options || sockaddrcmp(&e->address, &address)) {
                        if(from == myself) {
-                               ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself which does not match existing entry"),
+                               ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself which does not match existing entry",
                                                   "ADD_EDGE", c->name, c->hostname);
                                send_add_edge(c, e);
                                return true;
                        } else {
-                               ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) which does not match existing entry"),
+                               ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) which does not match existing entry",
                                                   "ADD_EDGE", c->name, c->hostname);
                                edge_del(e);
                                graph();
                } else
                        return true;
        } else if(from == myself) {
-               ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself which does not exist"),
+               ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself which does not exist",
                                   "ADD_EDGE", c->name, c->hostname);
                e = new_edge();
                e->from = from;
        /* Tell the rest about the new edge */
  
        if(!tunnelserver)
 -              forward_request(c);
 +              forward_request(c, request);
  
        /* Run MST before or after we tell the rest? */
  
  }
  
  bool send_del_edge(connection_t *c, const edge_t *e) {
-       cp();
        return send_request(c, "%d %x %s %s", DEL_EDGE, rand(),
                                                e->from->name, e->to->name);
  }
  
 -bool del_edge_h(connection_t *c) {
 +bool del_edge_h(connection_t *c, char *request) {
        edge_t *e;
        char from_name[MAX_STRING_SIZE];
        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;
        }
        /* Check if names are valid */
  
        if(!check_id(from_name)) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_EDGE", c->name,
-                          c->hostname, _("invalid name"));
+               logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name,
+                          c->hostname, "invalid name");
                return false;
        }
  
        if(!check_id(to_name)) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_EDGE", c->name,
-                          c->hostname, _("invalid name"));
+               logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_EDGE", c->name,
+                          c->hostname, "invalid name");
                return false;
        }
  
 -      if(seen_request(c->buffer))
 +      if(seen_request(request))
                return true;
  
        /* Lookup nodes */
           to != myself && to != c->node) {
                /* ignore indirect edge registrations for tunnelserver */
                ifdebug(PROTOCOL) logger(LOG_WARNING,
-                  _("Ignoring indirect %s from %s (%s)"),
+                  "Ignoring indirect %s from %s (%s)",
                   "DEL_EDGE", c->name, c->hostname);
                return true;
        }
  
        if(!from) {
-               ifdebug(PROTOCOL) logger(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"),
+               ifdebug(PROTOCOL) logger(LOG_ERR, "Got %s from %s (%s) which does not appear in the edge tree",
                                   "DEL_EDGE", c->name, c->hostname);
                return true;
        }
  
        if(!to) {
-               ifdebug(PROTOCOL) logger(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"),
+               ifdebug(PROTOCOL) logger(LOG_ERR, "Got %s from %s (%s) which does not appear in the edge tree",
                                   "DEL_EDGE", c->name, c->hostname);
                return true;
        }
        e = lookup_edge(from, to);
  
        if(!e) {
-               ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) which does not appear in the edge tree"),
+               ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) which does not appear in the edge tree",
                                   "DEL_EDGE", c->name, c->hostname);
                return true;
        }
  
        if(e->from == myself) {
-               ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself"),
+               ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself",
                                   "DEL_EDGE", c->name, c->hostname);
                send_add_edge(c, e);    /* Send back a correction */
                return true;
        /* Tell the rest about the deleted edge */
  
        if(!tunnelserver)
 -              forward_request(c);
 +              forward_request(c, request);
  
        /* Delete the edge */
  
diff --combined src/protocol_key.c
      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.
  */
  
  #include "system.h"
  
 -#include <openssl/evp.h>
 -#include <openssl/err.h>
 -#include <openssl/rand.h>
 -
 -#include "avl_tree.h"
 +#include "splay_tree.h"
 +#include "cipher.h"
  #include "connection.h"
 +#include "crypto.h"
  #include "logger.h"
  #include "net.h"
  #include "netutl.h"
  #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.
         */
        return send_request(broadcast, "%d %x %s", KEY_CHANGED, rand(), myself->name);
  }
  
 -bool key_changed_h(connection_t *c) {
 +bool key_changed_h(connection_t *c, char *request) {
        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;
        }
  
 -      if(seen_request(c->buffer))
 +      if(seen_request(request))
                return true;
  
        n = lookup_node(name);
  
        if(!n) {
-               logger(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist"),
+               logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist",
                           "KEY_CHANGED", c->name, c->hostname, name);
                return false;
        }
        /* Tell the others */
  
        if(!tunnelserver)
 -              forward_request(c);
 +              forward_request(c, request);
  
        return true;
  }
  
  bool send_req_key(node_t *to) {
-       cp();
        return send_request(to->nexthop->connection, "%d %s %s", REQ_KEY, myself->name, to->name);
  }
  
 -bool req_key_h(connection_t *c) {
 +bool req_key_h(connection_t *c, char *request) {
        char from_name[MAX_STRING_SIZE];
        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;
        }
        from = lookup_node(from_name);
  
        if(!from) {
-               logger(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist in our connection list"),
+               logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
                           "REQ_KEY", c->name, c->hostname, from_name);
                return false;
        }
        to = lookup_node(to_name);
  
        if(!to) {
-               logger(LOG_ERR, _("Got %s from %s (%s) destination %s which does not exist in our connection list"),
+               logger(LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
                           "REQ_KEY", c->name, c->hostname, to_name);
                return false;
        }
        /* Check if this key request is for us */
  
        if(to == myself) {                      /* Yes, send our own key back */
 +
                send_ans_key(from);
        } else {
                if(tunnelserver)
                        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",
                                "REQ_KEY", c->name, c->hostname, to_name);
                        return true;
                }
  
 -              send_request(to->nexthop->connection, "%s", c->buffer);
 +              send_request(to->nexthop->connection, "%s", request);
        }
  
        return true;
  }
  
  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;
        to->received_seqno = 0;
        memset(to->late, 0, sizeof(to->late));
  
 -      // Convert to hexadecimal and send
 -      key = alloca(2 * to->inkeylength + 1);
 -      bin2hex(to->inkey, key, to->inkeylength);
 -      key[to->inkeylength * 2] = '\0';
 -
 -      return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY,
 -                      myself->name, to->name, key,
 -                      to->incipher ? to->incipher->nid : 0,
 -                      to->indigest ? to->indigest->type : 0, to->inmaclength,
 -                      to->incompression);
 +      return send_request(to->nexthop->connection, "%d %s %s %s %d %d %zu %d", ANS_KEY,
 +                                              myself->name, to->name, key,
 +                                              cipher_get_nid(&to->incipher),
 +                                              digest_get_nid(&to->indigest),
 +                                              digest_length(&to->indigest),
 +                                              to->incompression);
  }
  
 -bool ans_key_h(connection_t *c) {
 +bool ans_key_h(connection_t *c, char *request) {
        char from_name[MAX_STRING_SIZE];
        char to_name[MAX_STRING_SIZE];
        char key[MAX_STRING_SIZE];
        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;
        }
        from = lookup_node(from_name);
  
        if(!from) {
-               logger(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist in our connection list"),
+               logger(LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
                           "ANS_KEY", c->name, c->hostname, from_name);
                return false;
        }
        to = lookup_node(to_name);
  
        if(!to) {
-               logger(LOG_ERR, _("Got %s from %s (%s) destination %s which does not exist in our connection list"),
+               logger(LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
                           "ANS_KEY", c->name, c->hostname, to_name);
                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) {
-               logger(LOG_ERR, _("Node %s (%s) uses bogus compression level!"), from->name, from->hostname);
+               logger(LOG_ERR, "Node %s (%s) uses bogus compression level!", from->name, from->hostname);
                return false;
        }
        
        from->outcompression = compression;
  
 -      if(from->outcipher)
 -              if(!EVP_EncryptInit_ex(&from->outctx, from->outcipher, NULL, (unsigned char *)from->outkey, (unsigned char *)from->outkey + from->outcipher->key_len)) {
 -                      logger(LOG_ERR, "Error during initialisation of key from %s (%s): %s",
 -                                      from->name, from->hostname, ERR_error_string(ERR_get_error(), NULL));
 -                      return false;
 -              }
 +      /* Update our copy of the origin's packet key */
 +
 +      hex2bin(key, key, cipher_keylength(&from->outcipher));
 +      cipher_set_key(&from->outcipher, key, false);
  
        from->status.validkey = true;
 +      from->status.waitingforkey = false;
        from->sent_seqno = 0;
  
        if(from->options & OPTION_PMTU_DISCOVERY && !from->mtuprobes)
diff --combined src/protocol_misc.c
@@@ -1,7 -1,7 +1,7 @@@
  /*
      protocol_misc.c -- handle the meta-protocol, miscellaneous functions
      Copyright (C) 1999-2005 Ivo Timmermans,
-                   2000-2006 Guus Sliepen <guus@tinc-vpn.org>
+                   2000-2009 Guus Sliepen <guus@tinc-vpn.org>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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.
  */
  
  #include "system.h"
@@@ -35,106 -33,80 +33,76 @@@ int maxoutbufsize = 0
  
  /* Status and error notification routines */
  
- bool send_status(connection_t *c, int statusno, const char *statusstring)
- {
-       cp();
+ bool send_status(connection_t *c, int statusno, const char *statusstring) {
        if(!statusstring)
                statusstring = "Status";
  
        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;
        }
  
-       ifdebug(STATUS) logger(LOG_NOTICE, _("Status message from %s (%s): %d: %s"),
+       ifdebug(STATUS) logger(LOG_NOTICE, "Status message from %s (%s): %d: %s",
                           c->name, c->hostname, statusno, statusstring);
  
        return true;
  }
  
- bool send_error(connection_t *c, int err, const char *errstring)
- {
-       cp();
+ bool send_error(connection_t *c, int err, const char *errstring) {
        if(!errstring)
                errstring = "Error";
  
        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);
  }
  
- bool send_pong(connection_t *c)
- {
-       cp();
+ 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. */
  
  /* Sending and receiving packets via TCP */
  
- bool send_tcppacket(connection_t *c, vpn_packet_t *packet)
- {
-       cp();
+ bool send_tcppacket(connection_t *c, vpn_packet_t *packet) {
        /* If there already is a lot of data in the outbuf buffer, discard this packet.
             We use a very simple Random Early Drop algorithm. */
  
 -      if(2.0 * c->outbuflen / (float)maxoutbufsize - 1 > (float)rand()/(float)RAND_MAX)
 +      if(2.0 * c->buffer->output->off / (float)maxoutbufsize - 1 > (float)rand()/(float)RAND_MAX)
                return true;
  
        if(!send_request(c, "%d %hd", PACKET, packet->len))
        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;
        }
diff --combined src/protocol_subnet.c
@@@ -2,6 -2,7 +2,7 @@@
      protocol_subnet.c -- handle the meta-protocol, subnets
      Copyright (C) 1999-2005 Ivo Timmermans,
                    2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                   2009      Michael Tokarev <mjt@tls.msk.ru>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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.
  */
  
  #include "system.h"
  #include "utils.h"
  #include "xalloc.h"
  
- bool send_add_subnet(connection_t *c, const subnet_t *subnet)
- {
+ bool send_add_subnet(connection_t *c, const subnet_t *subnet) {
        char netstr[MAXNETSTR];
  
-       cp();
        if(!net2str(netstr, sizeof netstr, subnet))
                return false;
  
        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;
        }
        /* Check if owner name is valid */
  
        if(!check_id(name)) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_SUBNET", c->name,
-                          c->hostname, _("invalid name"));
+               logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_SUBNET", c->name,
+                          c->hostname, "invalid name");
                return false;
        }
  
        /* Check if subnet string is valid */
  
        if(!str2net(&s, subnetstr)) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_SUBNET", c->name,
-                          c->hostname, _("invalid subnet string"));
+               logger(LOG_ERR, "Got bad %s from %s (%s): %s", "ADD_SUBNET", c->name,
+                          c->hostname, "invalid subnet string");
                return false;
        }
  
 -      if(seen_request(c->buffer))
 +      if(seen_request(request))
                return true;
  
        /* Check if the owner of the new subnet is in the connection list */
@@@ -85,7 -78,7 +78,7 @@@
  
        if(tunnelserver && owner != myself && owner != c->node) {
                /* in case of tunnelserver, ignore indirect subnet registrations */
-               ifdebug(PROTOCOL) logger(LOG_WARNING, _("Ignoring indirect %s from %s (%s) for %s"),
+               ifdebug(PROTOCOL) logger(LOG_WARNING, "Ignoring indirect %s from %s (%s) for %s",
                                   "ADD_SUBNET", c->name, c->hostname, subnetstr);
                return true;
        }
        /* If we don't know this subnet, but we are the owner, retaliate with a DEL_SUBNET */
  
        if(owner == myself) {
-               ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself"),
+               ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself",
                                   "ADD_SUBNET", c->name, c->hostname);
                s.owner = myself;
                send_del_subnet(c, &s);
                }
  
                if(!cfg) {
-                       logger(LOG_WARNING, _("Unauthorized %s from %s (%s) for %s"),
+                       logger(LOG_WARNING, "Unauthorized %s from %s (%s) for %s",
                                "ADD_SUBNET", c->name, c->hostname, subnetstr);
                        return false;
                }
        /* Tell the rest */
  
        if(!tunnelserver)
 -              forward_request(c);
 +              forward_request(c, request);
  
        return true;
  }
  
- bool send_del_subnet(connection_t *c, const subnet_t *s)
- {
+ bool send_del_subnet(connection_t *c, const subnet_t *s) {
        char netstr[MAXNETSTR];
  
-       cp();
        if(!net2str(netstr, sizeof netstr, s))
                return false;
  
        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;
        }
        /* Check if owner name is valid */
  
        if(!check_id(name)) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name,
-                          c->hostname, _("invalid name"));
+               logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_SUBNET", c->name,
+                          c->hostname, "invalid name");
                return false;
        }
  
        /* Check if subnet string is valid */
  
        if(!str2net(&s, subnetstr)) {
-               logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name,
-                          c->hostname, _("invalid subnet string"));
+               logger(LOG_ERR, "Got bad %s from %s (%s): %s", "DEL_SUBNET", c->name,
+                          c->hostname, "invalid subnet string");
                return false;
        }
  
 -      if(seen_request(c->buffer))
 +      if(seen_request(request))
                return true;
  
        /* Check if the owner of the subnet being deleted is in the connection list */
  
        if(tunnelserver && owner != myself && owner != c->node) {
                /* in case of tunnelserver, ignore indirect subnet deletion */
-               ifdebug(PROTOCOL) logger(LOG_WARNING, _("Ignoring indirect %s from %s (%s) for %s"),
+               ifdebug(PROTOCOL) logger(LOG_WARNING, "Ignoring indirect %s from %s (%s) for %s",
                                    "DEL_SUBNET", c->name, c->hostname, subnetstr);
                return true;
        }
  
        if(!owner) {
-               ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for %s which is not in our node tree"),
+               ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for %s which is not in our node tree",
                                   "DEL_SUBNET", c->name, c->hostname, name);
                return true;
        }
        find = lookup_subnet(owner, &s);
  
        if(!find) {
-               ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for %s which does not appear in his subnet tree"),
+               ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for %s which does not appear in his subnet tree",
                                   "DEL_SUBNET", c->name, c->hostname, name);
                return true;
        }
        /* If we are the owner of this subnet, retaliate with an ADD_SUBNET */
  
        if(owner == myself) {
-               ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for ourself"),
+               ifdebug(PROTOCOL) logger(LOG_WARNING, "Got %s from %s (%s) for ourself",
                                   "DEL_SUBNET", c->name, c->hostname);
                send_add_subnet(c, find);
                return true;
        /* Tell the rest */
  
        if(!tunnelserver)
 -              forward_request(c);
 +              forward_request(c, request);
  
        /* Finally, delete it. */
  
diff --combined src/raw_socket/device.c
      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.
  */
  
  #include "system.h"
@@@ -44,49 -42,45 +42,45 @@@ bool setup_device(void) 
        struct ifreq ifr;
        struct sockaddr_ll sa;
  
-       cp();
        if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
                iface = xstrdup("eth0");
  
        if(!get_config_string(lookup_config(config_tree, "Device"), &device))
                device = xstrdup(iface);
  
-       device_info = _("raw socket");
+       device_info = "raw socket";
  
        if((device_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
-               logger(LOG_ERR, _("Could not open %s: %s"), device_info,
+               logger(LOG_ERR, "Could not open %s: %s", device_info,
                           strerror(errno));
                return false;
        }
  
 -      memset(&ifr, 0, sizeof(ifr));
 +      memset(&ifr, 0, sizeof ifr);
        strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
        if(ioctl(device_fd, SIOCGIFINDEX, &ifr)) {
                close(device_fd);
-               logger(LOG_ERR, _("Can't find interface %s: %s"), iface,
+               logger(LOG_ERR, "Can't find interface %s: %s", iface,
                           strerror(errno));
                return false;
        }
  
 -      memset(&sa, '0', sizeof(sa));
 +      memset(&sa, '0', sizeof sa);
        sa.sll_family = AF_PACKET;
        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;
        }
  
-       logger(LOG_INFO, _("%s is a %s"), device, device_info);
+       logger(LOG_INFO, "%s is a %s", device, device_info);
  
        return true;
  }
  
  void close_device(void) {
-       cp();
        close(device_fd);
  
        free(device);
  }
  
  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;
        }
  
 -      packet->len = lenin;
 +      packet->len = inlen;
  
        device_total_in += packet->len;
  
-       ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
+       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
                           device_info);
  
        return true;
  }
  
  bool write_packet(vpn_packet_t *packet) {
-       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(write(device_fd, packet->data, packet->len) < 0) {
-               logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device,
+               logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
                           strerror(errno));
                return false;
        }
  }
  
  void dump_device_stats(void) {
-       cp();
-       logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
-       logger(LOG_DEBUG, _(" total bytes in:  %10d"), device_total_in);
-       logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
+       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
+       logger(LOG_DEBUG, " total bytes in:  %10d", device_total_in);
+       logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
  }
diff --combined src/route.c
      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.
  */
  
  #include "system.h"
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  #include "connection.h"
  #include "ethernet.h"
  #include "ipv4.h"
@@@ -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;
  
@@@ -77,7 -72,6 +74,7 @@@
  static bool ratelimit(int frequency) {
        static time_t lasttime = 0;
        static int count = 0;
 +      time_t now = time(NULL);
        
        if(lasttime == now) {
                if(++count > frequency)
@@@ -92,7 -86,7 +89,7 @@@
  
  static bool checklength(node_t *source, vpn_packet_t *packet, length_t length) {
        if(packet->len < length) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Got too short packet from %s (%s)"), source->name, source->hostname);
+               ifdebug(TRAFFIC) logger(LOG_WARNING, "Got too short packet from %s (%s)", source->name, source->hostname);
                return false;
        } else
                return true;
@@@ -105,63 -99,23 +102,58 @@@ 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 */
  
        if(!subnet) {
-               ifdebug(TRAFFIC) logger(LOG_INFO, _("Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx"),
+               ifdebug(TRAFFIC) logger(LOG_INFO, "Learned new MAC address %hx:%hx:%hx:%hx:%hx:%hx",
                                   address->x[0], address->x[1], address->x[2], address->x[3],
                                   address->x[4], address->x[5]);
  
                subnet = new_subnet();
                subnet->type = SUBNET_MAC;
 -              subnet->expires = now + macexpire;
 +              subnet->expires = time(NULL) + macexpire;
                subnet->net.mac.address = *address;
                subnet_add(myself, subnet);
  
                        if(c->status.active)
                                send_add_subnet(c, subnet);
                }
 -      }
 -
 -      if(subnet->expires)
 -              subnet->expires = now + macexpire;
 -}
 -
 -void age_subnets(void) {
 -      subnet_t *s;
 -      connection_t *c;
 -      avl_node_t *node, *next, *node2;
 -
 -      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);
 -                      }
  
 -                      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);
 -              }
 +              if(!timeout_initialized(&age_subnets_event))
 +                      timeout_set(&age_subnets_event, age_subnets, NULL);
 +              event_add(&age_subnets_event, &(struct timeval){10, 0});
 +      } else {
 +              if(subnet->expires)
 +                      subnet->expires = time(NULL) + macexpire;
        }
  }
  
  /* RFC 792 */
  
- static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code)
- {
+ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code) {
        struct ip ip = {0};
        struct icmp icmp = {0};
        
        if(ratelimit(3))
                return;
        
-       cp();
        /* Swap Ethernet source and destination addresses */
  
        swap_mac_addresses(packet);
@@@ -267,8 -240,6 +256,6 @@@ static void fragment_ipv4_packet(node_
        uint8_t *offset;
        uint16_t ip_off, origf;
        
-       cp();
        memcpy(&ip, packet->data + ether_size, ip_size);
        fragment.priority = packet->priority;
  
        todo = ntohs(ip.ip_len) - ip_size;
  
        if(ether_size + ip_size + todo != packet->len) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Length of packet (%d) doesn't match length in IPv4 header (%zd)"), packet->len, ether_size + ip_size + todo);
+               ifdebug(TRAFFIC) logger(LOG_WARNING, "Length of packet (%d) doesn't match length in IPv4 header (%zd)", packet->len, ether_size + ip_size + todo);
                return;
        }
  
-       ifdebug(TRAFFIC) logger(LOG_INFO, _("Fragmenting packet of %d bytes to %s (%s)"), packet->len, dest->name, dest->hostname);
+       ifdebug(TRAFFIC) logger(LOG_INFO, "Fragmenting packet of %d bytes to %s (%s)", packet->len, dest->name, dest->hostname);
  
        offset = packet->data + ether_size + ip_size;
        maxlen = (dest->mtu - ether_size - ip_size) & ~0x7;
        }       
  }
  
- static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet)
- {
+ static void route_ipv4_unicast(node_t *source, vpn_packet_t *packet) {
        subnet_t *subnet;
        node_t *via;
        ipv4_t dest;
  
-       cp();
        memcpy(&dest, &packet->data[30], sizeof dest);
        subnet = lookup_subnet_ipv4(&dest);
  
        if(!subnet) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet from %s (%s): unknown IPv4 destination address %d.%d.%d.%d"),
+               ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown IPv4 destination address %d.%d.%d.%d",
                                source->name, source->hostname,
                                dest.x[0],
                                dest.x[1],
        }
        
        if(subnet->owner == source) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Packet looping back to %s (%s)!"), source->name, source->hostname);
+               ifdebug(TRAFFIC) logger(LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname);
                return;
        }
  
        via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
        
        if(via && packet->len > via->mtu && via != myself) {
-               ifdebug(TRAFFIC) logger(LOG_INFO, _("Packet for %s (%s) length %d larger than MTU %d"), subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
+               ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
                if(packet->data[20] & 0x40) {
                        packet->len = via->mtu;
                        route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
        send_packet(subnet->owner, packet);
  }
  
- static void route_ipv4(node_t *source, vpn_packet_t *packet)
- {
-       cp();
+ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
        if(!checklength(source, packet, ether_size + ip_size))
                return;
  
  
  /* RFC 2463 */
  
- static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code)
- {
+ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code) {
        struct ip6_hdr ip6;
        struct icmp6_hdr icmp6 = {0};
        uint16_t checksum;      
        if(ratelimit(3))
                return;
        
-       cp();
        /* Swap Ethernet source and destination addresses */
  
        swap_mac_addresses(packet);
  
        /* Generate checksum */
        
 -      checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
 +      checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
        checksum = inet_checksum(&icmp6, icmp6_size, checksum);
        checksum = inet_checksum(packet->data + ether_size + ip6_size + icmp6_size, ntohl(pseudo.length) - icmp6_size, checksum);
  
        send_packet(source, packet);
  }
  
- static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet)
- {
+ static void route_ipv6_unicast(node_t *source, vpn_packet_t *packet) {
        subnet_t *subnet;
        node_t *via;
        ipv6_t dest;
  
-       cp();
        memcpy(&dest, &packet->data[38], sizeof dest);
        subnet = lookup_subnet_ipv6(&dest);
  
        if(!subnet) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet from %s (%s): unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
+               ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown IPv6 destination address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
                                source->name, source->hostname,
                                ntohs(dest.x[0]),
                                ntohs(dest.x[1]),
        }
  
        if(subnet->owner == source) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Packet looping back to %s (%s)!"), source->name, source->hostname);
+               ifdebug(TRAFFIC) logger(LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname);
                return;
        }
  
        via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
        
        if(via && packet->len > via->mtu && via != myself) {
-               ifdebug(TRAFFIC) logger(LOG_INFO, _("Packet for %s (%s) length %d larger than MTU %d"), subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
+               ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
                packet->len = via->mtu;
                route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0);
                return;
  
  /* RFC 2461 */
  
- static void route_neighborsol(node_t *source, vpn_packet_t *packet)
- {
+ static void route_neighborsol(node_t *source, vpn_packet_t *packet) {
        struct ip6_hdr ip6;
        struct nd_neighbor_solicit ns;
        struct nd_opt_hdr opt;
                uint32_t next;
        } pseudo;
  
-       cp();
        if(!checklength(source, packet, ether_size + ip6_size + ns_size))
                return;
        
        has_opt = packet->len >= ether_size + ip6_size + ns_size + opt_size + ETH_ALEN;
        
        if(source != myself) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Got neighbor solicitation request from %s (%s) while in router mode!"), source->name, source->hostname);
+               ifdebug(TRAFFIC) logger(LOG_WARNING, "Got neighbor solicitation request from %s (%s) while in router mode!", source->name, source->hostname);
                return;
        }
  
  
        if(ns.nd_ns_hdr.icmp6_type != ND_NEIGHBOR_SOLICIT ||
           (has_opt && opt.nd_opt_type != ND_OPT_SOURCE_LINKADDR)) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: received unknown type neighbor solicitation request"));
+               ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: received unknown type neighbor solicitation request");
                return;
        }
  
  
        /* Generate checksum */
  
 -      checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
 +      checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
        checksum = inet_checksum(&ns, ns_size, checksum);
        if(has_opt) {
                checksum = inet_checksum(&opt, opt_size, checksum);
        }
  
        if(checksum) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
+               ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: checksum error for neighbor solicitation request");
                return;
        }
  
        subnet = lookup_subnet_ipv6((ipv6_t *) &ns.nd_ns_target);
  
        if(!subnet) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx"),
+               ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: neighbor solicitation request for unknown address %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
                                   ntohs(((uint16_t *) &ns.nd_ns_target)[0]),
                                   ntohs(((uint16_t *) &ns.nd_ns_target)[1]),
                                   ntohs(((uint16_t *) &ns.nd_ns_target)[2]),
  
        /* Generate checksum */
  
 -      checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
 +      checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
        checksum = inet_checksum(&ns, ns_size, checksum);
        if(has_opt) {
                checksum = inet_checksum(&opt, opt_size, checksum);
        send_packet(source, packet);
  }
  
- static void route_ipv6(node_t *source, vpn_packet_t *packet)
- {
-       cp();
+ static void route_ipv6(node_t *source, vpn_packet_t *packet) {
        if(!checklength(source, packet, ether_size + ip6_size))
                return;
  
  
  /* RFC 826 */
  
- static void route_arp(node_t *source, vpn_packet_t *packet)
- {
+ static void route_arp(node_t *source, vpn_packet_t *packet) {
        struct ether_arp arp;
        subnet_t *subnet;
        struct in_addr addr;
  
-       cp();
        if(!checklength(source, packet, ether_size + arp_size))
                return;
  
        if(source != myself) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Got ARP request from %s (%s) while in router mode!"), source->name, source->hostname);
+               ifdebug(TRAFFIC) logger(LOG_WARNING, "Got ARP request from %s (%s) while in router mode!", source->name, source->hostname);
                return;
        }
  
        /* 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;
        }
  
        subnet = lookup_subnet_ipv4((ipv4_t *) &arp.arp_tpa);
  
        if(!subnet) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: ARP request for unknown address %d.%d.%d.%d"),
+               ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet: ARP request for unknown address %d.%d.%d.%d",
                                   arp.arp_tpa[0], arp.arp_tpa[1], arp.arp_tpa[2],
                                   arp.arp_tpa[3]);
                return;
        memcpy(packet->data, packet->data + ETH_ALEN, ETH_ALEN);        /* copy destination address */
        packet->data[ETH_ALEN * 2 - 1] ^= 0xFF; /* mangle source address so it looks like it's not from us */
  
 -      memcpy(&addr, arp.arp_tpa, sizeof(addr));       /* save protocol addr */
 -      memcpy(arp.arp_tpa, arp.arp_spa, sizeof(addr)); /* swap destination and source protocol address */
 -      memcpy(arp.arp_spa, &addr, sizeof(addr));       /* ... */
 +      memcpy(&addr, arp.arp_tpa, sizeof addr);        /* save protocol addr */
 +      memcpy(arp.arp_tpa, arp.arp_spa, sizeof addr);  /* swap destination and source protocol address */
 +      memcpy(arp.arp_spa, &addr, sizeof addr);        /* ... */
  
        memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN);     /* set target hard/proto addr */
        memcpy(arp.arp_sha, packet->data + ETH_ALEN, ETH_ALEN); /* add fake source hard addr */
        send_packet(source, packet);
  }
  
- static void route_mac(node_t *source, vpn_packet_t *packet)
- {
+ static void route_mac(node_t *source, vpn_packet_t *packet) {
        subnet_t *subnet;
        mac_t dest;
  
-       cp();
        /* Learn source address */
  
        if(source == myself) {
        }
  
        if(subnet->owner == source) {
-               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Packet looping back to %s (%s)!"), source->name, source->hostname);
+               ifdebug(TRAFFIC) logger(LOG_WARNING, "Packet looping back to %s (%s)!", source->name, source->hostname);
                return;
        }
  
        node_t *via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
        
        if(via && packet->len > via->mtu && via != myself) {
-               ifdebug(TRAFFIC) logger(LOG_INFO, _("Packet for %s (%s) length %d larger than MTU %d"), subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
+               ifdebug(TRAFFIC) logger(LOG_INFO, "Packet for %s (%s) length %d larger than MTU %d", subnet->owner->name, subnet->owner->hostname, packet->len, via->mtu);
                uint16_t type = packet->data[12] << 8 | packet->data[13];
                if(type == ETH_P_IP) {
                        if(packet->data[20] & 0x40) {
        send_packet(subnet->owner, packet);
  }
  
- void route(node_t *source, vpn_packet_t *packet)
- {
-       cp();
+ void route(node_t *source, vpn_packet_t *packet) {
        if(!checklength(source, packet, ether_size))
                return;
  
                                                break;
  
                                        default:
-                                               ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet from %s (%s): unknown type %hx"), source->name, source->hostname, type);
+                                               ifdebug(TRAFFIC) logger(LOG_WARNING, "Cannot route packet from %s (%s): unknown type %hx", source->name, source->hostname, type);
                                                break;
                                }
                        }
diff --combined src/route.h
@@@ -1,6 -1,6 +1,6 @@@
  /*
      route.h -- header file for route.c
-     Copyright (C) 2000-2005 Ivo Timmermans <zarq@iname.com>
+     Copyright (C) 2000-2005 Ivo Timmermans
                    2000-2006 Guus Sliepen <guus@tinc-vpn.org>         
  
      This program is free software; you can redistribute it and/or modify
      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_ROUTE_H__
@@@ -39,6 -37,7 +37,6 @@@ extern int macexpire
  
  extern mac_t mymac;
  
 -extern void age_subnets(void);
  extern void route(struct node_t *, struct vpn_packet_t *);
  
  #endif                                                        /* __TINC_ROUTE_H__ */
diff --combined src/solaris/device.c
      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.
  */
  
  
@@@ -48,13 -46,11 +46,11 @@@ bool setup_device(void) 
        int ppa;
        char *ptr;
  
-       cp();
        if(!get_config_string(lookup_config(config_tree, "Device"), &device))
                device = xstrdup(DEFAULT_DEVICE);
  
        if((device_fd = open(device, O_RDWR | O_NONBLOCK)) < 0) {
-               logger(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
+               logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
                return false;
        }
  
        ppa = atoi(ptr);
  
        if((ip_fd = open("/dev/ip", O_RDWR, 0)) < 0) {
-               logger(LOG_ERR, _("Could not open /dev/ip: %s"), strerror(errno));
+               logger(LOG_ERR, "Could not open /dev/ip: %s", strerror(errno));
                return false;
        }
  
        /* Assign a new PPA and get its unit number. */
        if((ppa = ioctl(device_fd, TUNNEWPPA, ppa)) < 0) {
-               logger(LOG_ERR, _("Can't assign new interface: %s"), strerror(errno));
+               logger(LOG_ERR, "Can't assign new interface: %s", strerror(errno));
                return false;
        }
  
        if((if_fd = open(device, O_RDWR, 0)) < 0) {
-               logger(LOG_ERR, _("Could not open %s twice: %s"), device,
+               logger(LOG_ERR, "Could not open %s twice: %s", device,
                           strerror(errno));
                return false;
        }
  
        if(ioctl(if_fd, I_PUSH, "ip") < 0) {
-               logger(LOG_ERR, _("Can't push IP module: %s"), strerror(errno));
+               logger(LOG_ERR, "Can't push IP module: %s", strerror(errno));
                return false;
        }
  
        /* Assign ppa according to the unit number returned by tun device */
        if(ioctl(if_fd, IF_UNITSEL, (char *) &ppa) < 0) {
-               logger(LOG_ERR, _("Can't set PPA %d: %s"), ppa, strerror(errno));
+               logger(LOG_ERR, "Can't set PPA %d: %s", ppa, strerror(errno));
                return false;
        }
  
        if(ioctl(ip_fd, I_LINK, if_fd) < 0) {
-               logger(LOG_ERR, _("Can't link TUN device to IP: %s"), strerror(errno));
+               logger(LOG_ERR, "Can't link TUN device to IP: %s", strerror(errno));
                return false;
        }
  
        if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
                xasprintf(&iface, "tun%d", ppa);
  
-       device_info = _("Solaris tun device");
+       device_info = "Solaris tun device";
  
-       logger(LOG_INFO, _("%s is a %s"), device, device_info);
+       logger(LOG_INFO, "%s is a %s", device, device_info);
  
        return true;
  }
  
  void close_device(void) {
-       cp();
        close(device_fd);
  
        free(device);
  }
  
  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;
        }
                        return false;
        }
  
 -      packet->len = lenin + 14;
 +      packet->len = inlen + 14;
  
        device_total_in += packet->len;
  
-       ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
+       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
                           device_info);
  
        return true;
  }
  
  bool write_packet(vpn_packet_t *packet) {
-       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(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
-               logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info,
+               logger(LOG_ERR, "Can't write to %s %s: %s", device_info,
                           device, strerror(errno));
                return false;
        }
  }
  
  void dump_device_stats(void) {
-       cp();
-       logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
-       logger(LOG_DEBUG, _(" total bytes in:  %10d"), device_total_in);
-       logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
+       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
+       logger(LOG_DEBUG, " total bytes in:  %10d", device_total_in);
+       logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
  }
diff --combined src/subnet.c
      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.
  */
  
  #include "system.h"
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
  #include "device.h"
  #include "logger.h"
  #include "net.h"
@@@ -35,7 -33,7 +33,7 @@@
  
  /* lists type of subnet */
  
 -avl_tree_t *subnet_tree;
 +splay_tree_t *subnet_tree;
  
  /* Subnet lookup cache */
  
@@@ -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;
@@@ -73,8 -70,7 +70,7 @@@
        return strcmp(a->owner->name, b->owner->name);
  }
  
- static int subnet_compare_ipv4(const subnet_t *a, const subnet_t *b)
- {
+ static int subnet_compare_ipv4(const subnet_t *a, const subnet_t *b) {
        int result;
  
        result = b->net.ipv4.prefixlength - a->net.ipv4.prefixlength;
@@@ -95,8 -91,7 +91,7 @@@
        return strcmp(a->owner->name, b->owner->name);
  }
  
- static int subnet_compare_ipv6(const subnet_t *a, const subnet_t *b)
- {
+ static int subnet_compare_ipv6(const subnet_t *a, const subnet_t *b) {
        int result;
  
        result = b->net.ipv6.prefixlength - a->net.ipv6.prefixlength;
        return strcmp(a->owner->name, b->owner->name);
  }
  
- int subnet_compare(const subnet_t *a, const subnet_t *b)
- {
+ int subnet_compare(const subnet_t *a, const subnet_t *b) {
        int result;
  
        result = a->type - b->type;
        case SUBNET_IPV6:
                return subnet_compare_ipv6(a, b);
        default:
-               logger(LOG_ERR, _("subnet_compare() was called with unknown subnet type %d, exitting!"),
+               logger(LOG_ERR, "subnet_compare() was called with unknown subnet type %d, exitting!",
                           a->type);
-               cp_trace();
                exit(0);
        }
  
  
  /* 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 */
  
- subnet_t *new_subnet(void)
- {
-       cp();
+ subnet_t *new_subnet(void) {
        return xmalloc_and_zero(sizeof(subnet_t));
  }
  
- void free_subnet(subnet_t *subnet)
- {
-       cp();
+ void free_subnet(subnet_t *subnet) {
        free(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();
  }
  
  /* Ascii representation of subnets */
  
- bool str2net(subnet_t *subnet, const char *subnetstr)
- {
+ bool str2net(subnet_t *subnet, const char *subnetstr) {
        int i, l;
        uint16_t x[8];
        int weight = 10;
  
-       cp();
        if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d#%d",
                          &x[0], &x[1], &x[2], &x[3], &l, &weight) >= 5) {
                if(l < 0 || l > 32)
        return false;
  }
  
- bool net2str(char *netstr, int len, const subnet_t *subnet)
- {
-       cp();
+ bool net2str(char *netstr, int len, const subnet_t *subnet) {
        if(!netstr || !subnet) {
-               logger(LOG_ERR, _("net2str() was called with netstr=%p, subnet=%p!\n"), netstr, subnet);
+               logger(LOG_ERR, "net2str() was called with netstr=%p, subnet=%p!\n", netstr, subnet);
                return false;
        }
  
  
                default:
                        logger(LOG_ERR,
-                                  _("net2str() was called with unknown subnet type %d, exiting!"),
+                                  "net2str() was called with unknown subnet type %d, exiting!",
                                   subnet->type);
-                       cp_trace();
                        exit(0);
        }
  
  
  /* 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;
  
 -      p = avl_search(subnet_tree, &subnet);
 +      p = splay_search(subnet_tree, &subnet);
  
        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++) {
  }
  
  void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
 -      avl_node_t *node;
 +      splay_node_t *node;
        int i;
        char *envp[9] = {0};
        char netstr[MAXNETSTR];
                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 --combined src/subnet.h
      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_SUBNET_H__
@@@ -71,8 -69,8 +69,8 @@@ extern subnet_t *new_subnet(void) __att
  extern void free_subnet(subnet_t *);
  extern void init_subnets(void);
  extern void exit_subnets(void);
 -extern avl_tree_t *new_subnet_tree(void) __attribute__ ((__malloc__));
 -extern void free_subnet_tree(avl_tree_t *);
 +extern splay_tree_t *new_subnet_tree(void) __attribute__ ((__malloc__));
 +extern void free_subnet_tree(splay_tree_t *);
  extern void subnet_add(struct node_t *, subnet_t *);
  extern void subnet_del(struct node_t *, subnet_t *);
  extern void subnet_update(struct node_t *, subnet_t *, bool);
@@@ -82,7 -80,7 +80,7 @@@ extern subnet_t *lookup_subnet(const st
  extern subnet_t *lookup_subnet_mac(const mac_t *);
  extern subnet_t *lookup_subnet_ipv4(const ipv4_t *);
  extern subnet_t *lookup_subnet_ipv6(const ipv6_t *);
 -extern void dump_subnets(void);
 +extern int dump_subnets(struct evbuffer *);
  extern void subnet_cache_flush(void);
  
  #endif                                                        /* __TINC_SUBNET_H__ */
diff --combined src/tincd.c
@@@ -2,6 -2,8 +2,8 @@@
      tincd.c -- the main file for tincd
      Copyright (C) 1998-2005 Ivo Timmermans
                    2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+                   2008      Max Rijevski <maksuf@gmail.com>
+                   2009      Michael Tokarev <mjt@tls.msk.ru>
  
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      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.
  */
  
  #include "system.h"
  #include <sys/mman.h>
  #endif
  
 -#include <openssl/rand.h>
 -#include <openssl/rsa.h>
 -#include <openssl/pem.h>
 -#include <openssl/evp.h>
 -#include <openssl/engine.h>
 -
  #include LZO1X_H
  
  #ifndef HAVE_MINGW
  #endif
  
  #include <getopt.h>
 -#include "pidfile.h"
  
  #include "conf.h"
 +#include "control.h"
 +#include "crypto.h"
  #include "device.h"
  #include "logger.h"
  #include "net.h"
@@@ -62,6 -67,12 +62,6 @@@ bool show_help = false
  /* If nonzero, print the version on standard output and exit.  */
  bool show_version = false;
  
 -/* If nonzero, it will attempt to kill a running tincd and exit. */
 -int kill_tincd = 0;
 -
 -/* If nonzero, generate public/private keypair for this host/net. */
 -int generate_keys = 0;
 -
  /* If nonzero, use null ciphers and skip all key exchanges. */
  bool bypass_security = false;
  
@@@ -78,7 -89,7 +78,7 @@@ static const char *switchuser = NULL
  bool use_logfile = false;
  
  char *identname = NULL;                               /* program name for syslog */
 -char *pidfilename = NULL;                     /* pid file location */
 +char *controlsocketname = NULL;                       /* control socket location */
  char *logfilename = NULL;                     /* log file location */
  char **g_argv;                                        /* a copy of the cmdline arguments */
  
@@@ -86,17 -97,19 +86,17 @@@ static int status
  
  static struct option const long_options[] = {
        {"config", required_argument, NULL, 'c'},
 -      {"kill", optional_argument, NULL, 'k'},
        {"net", required_argument, NULL, 'n'},
        {"help", no_argument, NULL, 1},
        {"version", no_argument, NULL, 2},
        {"no-detach", no_argument, NULL, 'D'},
 -      {"generate-keys", optional_argument, NULL, 'K'},
        {"debug", optional_argument, NULL, 'd'},
        {"bypass-security", no_argument, NULL, 3},
        {"mlock", no_argument, NULL, 'L'},
        {"chroot", no_argument, NULL, 'R'},
        {"user", required_argument, NULL, 'U'},
        {"logfile", optional_argument, NULL, 4},
 -      {"pidfile", required_argument, NULL, 5},
 +      {"controlsocket", required_argument, NULL, 5},
        {NULL, 0, NULL, 0}
  };
  
@@@ -105,34 -118,34 +105,32 @@@ 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");
        }
  }
  
- static bool parse_options(int argc, char **argv)
- {
+ static bool parse_options(int argc, char **argv) {
        int r;
        int option_index = 0;
  
 -      while((r = getopt_long(argc, argv, "c:DLd::k::n:K::RU:", long_options, &option_index)) != EOF) {
 +      while((r = getopt_long(argc, argv, "c:DLd::n:RU:", long_options, &option_index)) != EOF) {
                switch (r) {
                        case 0:                         /* long option */
                                break;
  
                        case 'L':                               /* no detach */
  #ifndef HAVE_MLOCKALL
-                               logger(LOG_ERR, _("%s not supported on this platform"), "mlockall()");
+                               logger(LOG_ERR, "%s not supported on this platform", "mlockall()");
                                return false;
  #else
                                do_mlock = true;
                                        debug_level++;
                                break;
  
 -                      case 'k':                               /* kill old tincds */
 -#ifndef HAVE_MINGW
 -                              if(optarg) {
 -                                      if(!strcasecmp(optarg, "HUP"))
 -                                              kill_tincd = SIGHUP;
 -                                      else if(!strcasecmp(optarg, "TERM"))
 -                                              kill_tincd = SIGTERM;
 -                                      else if(!strcasecmp(optarg, "KILL"))
 -                                              kill_tincd = SIGKILL;
 -                                      else if(!strcasecmp(optarg, "USR1"))
 -                                              kill_tincd = SIGUSR1;
 -                                      else if(!strcasecmp(optarg, "USR2"))
 -                                              kill_tincd = SIGUSR2;
 -                                      else if(!strcasecmp(optarg, "WINCH"))
 -                                              kill_tincd = SIGWINCH;
 -                                      else if(!strcasecmp(optarg, "INT"))
 -                                              kill_tincd = SIGINT;
 -                                      else if(!strcasecmp(optarg, "ALRM"))
 -                                              kill_tincd = SIGALRM;
 -                                      else {
 -                                              kill_tincd = atoi(optarg);
 -
 -                                              if(!kill_tincd) {
 -                                                      fprintf(stderr, "Invalid argument `%s'; SIGNAL must be a number or one of HUP, TERM, KILL, USR1, USR2, WINCH, INT or ALRM.\n",
 -                                                                      optarg);
 -                                                      usage(true);
 -                                                      return false;
 -                                              }
 -                                      }
 -                              } else
 -                                      kill_tincd = SIGTERM;
 -#else
 -                                      kill_tincd = 1;
 -#endif
 -                              break;
 -
                        case 'n':                               /* net name given */
                                netname = xstrdup(optarg);
                                break;
  
 -                      case 'K':                               /* generate public/private keypair */
 -                              if(optarg) {
 -                                      generate_keys = atoi(optarg);
 -
 -                                      if(generate_keys < 512) {
 -                                              fprintf(stderr, "Invalid argument `%s'; BITS must be a number equal to or greater than 512.\n",
 -                                                              optarg);
 -                                              usage(true);
 -                                              return false;
 -                                      }
 -
 -                                      generate_keys &= ~7;    /* Round it to bytes */
 -                              } else
 -                                      generate_keys = 2048;
 -                              break;
 -
                        case 'R':                               /* chroot to NETNAME dir */
                                do_chroot = true;
                                break;
                                        logfilename = xstrdup(optarg);
                                break;
  
 -                      case 5:                                 /* write PID to a file */
 -                              pidfilename = xstrdup(optarg);
 +                      case 5:                                 /* open control socket here */
 +                              controlsocketname = xstrdup(optarg);
                                break;
  
                        case '?':
        return true;
  }
  
 -/* This function prettyprints the key generation process */
 -
 -static void indicator(int a, int b, void *p) {
 -      switch (a) {
 -              case 0:
 -                      fprintf(stderr, ".");
 -                      break;
 -
 -              case 1:
 -                      fprintf(stderr, "+");
 -                      break;
 -
 -              case 2:
 -                      fprintf(stderr, "-");
 -                      break;
 -
 -              case 3:
 -                      switch (b) {
 -                              case 0:
 -                                      fprintf(stderr, " p\n");
 -                                      break;
 -
 -                              case 1:
 -                                      fprintf(stderr, " q\n");
 -                                      break;
 -
 -                              default:
 -                                      fprintf(stderr, "?");
 -                      }
 -                      break;
 -
 -              default:
 -                      fprintf(stderr, "?");
 -      }
 -}
 -
 -/*
 -  Generate a public/private RSA keypair, and ask for a file to store
 -  them in.
 -*/
 -static bool keygen(int bits) {
 -      RSA *rsa_key;
 -      FILE *f;
 -      char *name = NULL;
 -      char *filename;
 -
 -      get_config_string(lookup_config(config_tree, "Name"), &name);
 -
 -      if(name && !check_id(name)) {
 -              fprintf(stderr, "Invalid name for myself!\n");
 -              return false;
 -      }
 -
 -      fprintf(stderr, "Generating %d bits keys:\n", bits);
 -      rsa_key = RSA_generate_key(bits, 0x10001, indicator, NULL);
 -
 -      if(!rsa_key) {
 -              fprintf(stderr, "Error during key generation!\n");
 -              return false;
 -      } else
 -              fprintf(stderr, "Done.\n");
 -
 -      xasprintf(&filename, "%s/rsa_key.priv", confbase);
 -      f = ask_and_open(filename, "private RSA key");
 -
 -      if(!f)
 -              return false;
 -
 -      if(disable_old_keys(f))
 -              fprintf(stderr, "Warning: old key(s) found and disabled.\n");
 -  
 -#ifdef HAVE_FCHMOD
 -      /* Make it unreadable for others. */
 -      fchmod(fileno(f), 0600);
 -#endif
 -              
 -      PEM_write_RSAPrivateKey(f, rsa_key, NULL, NULL, 0, NULL, NULL);
 -      fclose(f);
 -      free(filename);
 -
 -      if(name)
 -              xasprintf(&filename, "%s/hosts/%s", confbase, name);
 -      else
 -              xasprintf(&filename, "%s/rsa_key.pub", confbase);
 -
 -      f = ask_and_open(filename, "public RSA key");
 -
 -      if(!f)
 -              return false;
 -
 -      if(disable_old_keys(f))
 -              fprintf(stderr, "Warning: old key(s) found and disabled.\n");
 -
 -      PEM_write_RSAPublicKey(f, rsa_key);
 -      fclose(f);
 -      free(filename);
 -      if(name)
 -              free(name);
 -
 -      return true;
 -}
 -
  /*
    Set all files and paths according to netname
  */
- static void make_names(void)
- {
+ static void make_names(void) {
  #ifdef HAVE_MINGW
        HKEY key;
        char installdir[1024] = "";
 -      long len = sizeof(installdir);
 +      long len = sizeof installdir;
  #endif
  
        if(netname)
        }
  #endif
  
 -      if(!pidfilename)
 -              xasprintf(&pidfilename, LOCALSTATEDIR "/run/%s.pid", identname);
 +      if(!controlsocketname)
 +              xasprintf(&controlsocketname, "%s/run/%s.control/socket", LOCALSTATEDIR, identname);
  
        if(!logfilename)
                xasprintf(&logfilename, LOCALSTATEDIR "/log/%s.log", identname);
                if(!confbase)
                        xasprintf(&confbase, CONFDIR "/tinc/%s", netname);
                else
-                       logger(LOG_INFO, _("Both netname and configuration directory given, using the latter..."));
+                       logger(LOG_INFO, "Both netname and configuration directory given, using the latter...");
        } else {
                if(!confbase)
                        xasprintf(&confbase, CONFDIR "/tinc");
  static void free_names() {
        if (identname) free(identname);
        if (netname) free(netname);
 -      if (pidfilename) free(pidfilename);
 +      if (controlsocketname) free(controlsocketname);
        if (logfilename) free(logfilename);
        if (confbase) free(confbase);
  }
  static bool drop_privs() {
  #ifdef HAVE_MINGW
        if (switchuser) {
-               logger(LOG_ERR, _("%s not supported on this platform"), "-U");
+               logger(LOG_ERR, "%s not supported on this platform", "-U");
                return false;
        }
        if (do_chroot) {
-               logger(LOG_ERR, _("%s not supported on this platform"), "-R");
+               logger(LOG_ERR, "%s not supported on this platform", "-R");
                return false;
        }
  #else
        if (switchuser) {
                struct passwd *pw = getpwnam(switchuser);
                if (!pw) {
-                       logger(LOG_ERR, _("unknown user `%s'"), switchuser);
+                       logger(LOG_ERR, "unknown user `%s'", switchuser);
                        return false;
                }
                uid = pw->pw_uid;
                if (initgroups(switchuser, pw->pw_gid) != 0 ||
                    setgid(pw->pw_gid) != 0) {
-                       logger(LOG_ERR, _("System call `%s' failed: %s"),
+                       logger(LOG_ERR, "System call `%s' failed: %s",
                               "initgroups", strerror(errno));
                        return false;
                }
        if (do_chroot) {
                tzset();        /* for proper timestamps in logs */
                if (chroot(confbase) != 0 || chdir("/") != 0) {
-                       logger(LOG_ERR, _("System call `%s' failed: %s"),
+                       logger(LOG_ERR, "System call `%s' failed: %s",
                               "chroot", strerror(errno));
                        return false;
                }
        }
        if (switchuser)
                if (setuid(uid) != 0) {
-                       logger(LOG_ERR, _("System call `%s' failed: %s"),
+                       logger(LOG_ERR, "System call `%s' failed: %s",
                               "setuid", strerror(errno));
                        return false;
                }
  # define setpriority(level) nice(level)
  #endif
  
- int main(int argc, char **argv)
- {
+ int main(int argc, char **argv) {
        program_name = argv[0];
  
-       setlocale(LC_ALL, "");
-       bindtextdomain(PACKAGE, LOCALEDIR);
-       textdomain(PACKAGE);
        if(!parse_options(argc, argv))
                return 1;
        
        make_names();
  
        if(show_version) {
-               printf(_("%s version %s (built %s %s, protocol %d)\n"), PACKAGE,
+               printf("%s version %s (built %s %s, protocol %d)\n", PACKAGE,
                           VERSION, __DATE__, __TIME__, PROT_CURRENT);
-               printf(_("Copyright (C) 1998-2009 Ivo Timmermans, Guus Sliepen and others.\n"
+               printf("Copyright (C) 1998-2009 Ivo Timmermans, Guus Sliepen and others.\n"
                                "See the AUTHORS file for a complete list.\n\n"
                                "tinc comes with ABSOLUTELY NO WARRANTY.  This is free software,\n"
                                "and you are welcome to redistribute it under certain conditions;\n"
-                               "see the file COPYING for details.\n"));
+                               "see the file COPYING for details.\n");
  
                return 0;
        }
                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);
  
        /* Slllluuuuuuurrrrp! */
  
 -      RAND_load_file("/dev/urandom", 1024);
 -
 -      ENGINE_load_builtin_engines();
 -      ENGINE_register_all_complete();
 -
 -      OpenSSL_add_all_algorithms();
 -
 -      if(generate_keys) {
 -              read_server_config();
 -              return !keygen(generate_keys);
 -      }
 +      srand(time(NULL));
 +      crypto_init();
  
        if(!read_server_config())
                return 1;
  
        if(lzo_init() != LZO_E_OK) {
-               logger(LOG_ERR, _("Error initializing LZO compressor!"));
+               logger(LOG_ERR, "Error initializing LZO compressor!");
                return 1;
        }
  
  #ifdef HAVE_MINGW
        if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
-               logger(LOG_ERR, _("System call `%s' failed: %s"), "WSAStartup", winerror(GetLastError()));
+               logger(LOG_ERR, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
                return 1;
        }
  
                return 1;
  }
  
- int main2(int argc, char **argv)
- {
+ int main2(int argc, char **argv) {
        InitializeCriticalSection(&mutex);
        EnterCriticalSection(&mutex);
  #endif
         * This has to be done after daemon()/fork() so it works for child.
         * No need to do that in parent as it's very short-lived. */
        if(do_mlock && mlockall(MCL_CURRENT | MCL_FUTURE) != 0) {
-               logger(LOG_ERR, _("System call `%s' failed: %s"), "mlockall",
+               logger(LOG_ERR, "System call `%s' failed: %s", "mlockall",
                   strerror(errno));
                return 1;
        }
                  else if(!strcasecmp(priority, "High"))
                          setpriority(HIGH_PRIORITY_CLASS);
                  else {
-                         logger(LOG_ERR, _("Invalid priority `%s`!"), priority);
+                         logger(LOG_ERR, "Invalid priority `%s`!", priority);
                          goto end;
                  }
          }
        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();
diff --combined src/uml_socket/device.c
      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: device.c 1374 2004-03-21 14:21:22Z guus $
+     You should have received a copy of the GNU General Public License along
+     with this program; if not, write to the Free Software Foundation, Inc.,
+     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
  
  #include "system.h"
@@@ -67,17 -65,15 +65,15 @@@ bool setup_device(void) 
        } name;
        struct timeval tv;
  
-       cp();
        if(!get_config_string(lookup_config(config_tree, "Device"), &device))
                xasprintf(&device, LOCALSTATEDIR "/run/%s.umlsocket", identname);
  
        get_config_string(lookup_config(config_tree, "Interface"), &iface);
  
-       device_info = _("UML network socket");
+       device_info = "UML network socket";
  
        if((write_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
-               logger(LOG_ERR, _("Could not open write %s: %s"), device_info, strerror(errno));
+               logger(LOG_ERR, "Could not open write %s: %s", device_info, strerror(errno));
                running = false;
                return false;
        }
        setsockopt(write_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
  
        if(fcntl(write_fd, F_SETFL, O_NONBLOCK) < 0) {
-               logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", strerror(errno));
+               logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
                running = false;
                return false;
        }
  
        if((data_fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
-               logger(LOG_ERR, _("Could not open data %s: %s"), device_info, strerror(errno));
+               logger(LOG_ERR, "Could not open data %s: %s", device_info, strerror(errno));
                running = false;
                return false;
        }
@@@ -99,7 -95,7 +95,7 @@@
        setsockopt(data_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
  
        if(fcntl(data_fd, F_SETFL, O_NONBLOCK) < 0) {
-               logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", strerror(errno));
+               logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
                running = false;
                return false;
        }
        memcpy(&data_sun.sun_path, &name, sizeof name);
        
        if(bind(data_fd, (struct sockaddr *)&data_sun, sizeof data_sun) < 0) {
-               logger(LOG_ERR, _("Could not bind data %s: %s"), device_info, strerror(errno));
+               logger(LOG_ERR, "Could not bind data %s: %s", device_info, strerror(errno));
                running = false;
                return false;
        }
  
        if((listen_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
-               logger(LOG_ERR, _("Could not open %s: %s"), device_info,
+               logger(LOG_ERR, "Could not open %s: %s", device_info,
                           strerror(errno));
                return false;
        }
        setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
  
        if(fcntl(listen_fd, F_SETFL, O_NONBLOCK) < 0) {
-               logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", strerror(errno));
+               logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
                return false;
        }
  
        listen_sun.sun_family = AF_UNIX;
        strncpy(listen_sun.sun_path, device, sizeof listen_sun.sun_path);
        if(bind(listen_fd, (struct sockaddr *)&listen_sun, sizeof listen_sun) < 0) {
-               logger(LOG_ERR, _("Could not bind %s to %s: %s"), device_info, device, strerror(errno));
+               logger(LOG_ERR, "Could not bind %s to %s: %s", device_info, device, strerror(errno));
                return false;
        }
  
        if(listen(listen_fd, 1) < 0) {
-               logger(LOG_ERR, _("Could not listen on %s %s: %s"), device_info, device, strerror(errno));
+               logger(LOG_ERR, "Could not listen on %s %s: %s", device_info, device, strerror(errno));
                return false;
        }
  
        device_fd = listen_fd;
        state = 0;
  
-       logger(LOG_INFO, _("%s is a %s"), device, device_info);
+       logger(LOG_INFO, "%s is a %s", device, device_info);
  
        if(routing_mode == RMODE_ROUTER)
                overwrite_mac = true;
  }
  
  void close_device(void) {
-       cp();
        if(listen_fd >= 0)
                close(listen_fd);
  
  }
  
  bool read_packet(vpn_packet_t *packet) {
 -      int lenin;
 +      int inlen;
  
-       cp();
        switch(state) {
                case 0: {
                        struct sockaddr sa;
  
                        request_fd = accept(listen_fd, &sa, &salen);
                        if(request_fd < 0) {
-                               logger(LOG_ERR, _("Could not accept connection to %s %s: %s"), device_info, device, strerror(errno));
+                               logger(LOG_ERR, "Could not accept connection to %s %s: %s", device_info, device, strerror(errno));
                                return false;
                        }
  
                        if(fcntl(listen_fd, F_SETFL, O_NONBLOCK) < 0) {
-                               logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", strerror(errno));
+                               logger(LOG_ERR, "System call `%s' failed: %s", "fcntl", strerror(errno));
                                running = false;
                                return false;
                        }
                }
  
                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;
                        }
  
                        if(request.magic != 0xfeedface || request.version != 3 || request.type != REQ_NEW_CONTROL) {
-                               logger(LOG_ERR, _("Unknown magic %x, version %d, request type %d from %s %s"),
+                               logger(LOG_ERR, "Unknown magic %x, version %d, request type %d from %s %s",
                                                request.magic, request.version, request.type, device_info, device);
                                running = false;
                                return false;
                        }
  
                        if(connect(write_fd, &request.sock, sizeof request.sock) < 0) {
-                               logger(LOG_ERR, _("Could not bind write %s: %s"), device_info, strerror(errno));
+                               logger(LOG_ERR, "Could not bind write %s: %s", device_info, strerror(errno));
                                running = false;
                                return false;
                        }
                        write(request_fd, &data_sun, sizeof data_sun);
                        device_fd = data_fd;
  
-                       logger(LOG_INFO, _("Connection with UML established"));
+                       logger(LOG_INFO, "Connection with UML established");
  
                        state = 2;
                        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;
                        }
  
 -                      packet->len = lenin;
 +                      packet->len = inlen;
  
                        device_total_in += packet->len;
  
-                       ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
+                       ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
                                           device_info);
  
                        return true;
  }
  
  bool write_packet(vpn_packet_t *packet) {
-       cp();
        if(state != 2) {
-               ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Dropping packet of %d bytes to %s: not connected to UML yet"),
+               ifdebug(TRAFFIC) logger(LOG_DEBUG, "Dropping packet of %d bytes to %s: not connected to UML yet",
                                packet->len, device_info);
                return false;
        }
  
-       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(write(write_fd, packet->data, packet->len) < 0) {
                if(errno != EINTR && errno != EAGAIN) {
-                       logger(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device, strerror(errno));
+                       logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
                        running = false;
                }
  
  }
  
  void dump_device_stats(void) {
-       cp();
-       logger(LOG_DEBUG, _("Statistics for %s %s:"), device_info, device);
-       logger(LOG_DEBUG, _(" total bytes in:  %10d"), device_total_in);
-       logger(LOG_DEBUG, _(" total bytes out: %10d"), device_total_out);
+       logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
+       logger(LOG_DEBUG, " total bytes in:  %10d", device_total_in);
+       logger(LOG_DEBUG, " total bytes out: %10d", device_total_out);
  }