Merge branch 'master' into 1.1
authorGuus Sliepen <guus@tinc-vpn.org>
Fri, 12 Nov 2010 15:15:29 +0000 (16:15 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Fri, 12 Nov 2010 15:15:29 +0000 (16:15 +0100)
Conflicts:
doc/tincd.8.in
lib/pidfile.c
src/graph.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/protocol_auth.c
src/protocol_key.c
src/tincd.c

28 files changed:
1  2 
doc/tinc.texi
doc/tincd.8.in
have.h
src/bsd/device.c
src/conf.c
src/conf.h
src/connection.c
src/connection.h
src/cygwin/device.c
src/getopt.c
src/linux/device.c
src/logger.c
src/memcmp.c
src/mingw/device.c
src/net.c
src/net.h
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/process.c
src/process.h
src/protocol_auth.c
src/protocol_edge.c
src/protocol_key.c
src/raw_socket/device.c
src/solaris/device.c
src/tincd.c
src/uml_socket/device.c

diff --cc doc/tinc.texi
Simple merge
diff --cc doc/tincd.8.in
Simple merge
diff --cc have.h
index 89454feba1e92cf46db611f3d3271b42ebb45002,923e76ab3e0f9a96e6fb047c287585b5df5b169f..21c16efa8be933233e9c1666521fa3a0b8057e57
--- 1/have.h
--- 2/have.h
+++ b/have.h
  #ifndef __TINC_HAVE_H__
  #define __TINC_HAVE_H__
  
+ #ifdef HAVE_MINGW
+ #ifdef WITH_WINDOWS2000
+ #define WINVER Windows2000
+ #else
+ #define WINVER WindowsXP
+ #endif
++#define WIN32_LEAN_AND_MEAN
+ #endif
  #include <stdio.h>
  #include <stdlib.h>
  #include <stdarg.h>
Simple merge
diff --cc src/conf.c
index d5bc9165804209608d30ced5bf589128e3b946ce,0727953127e141ac633fc1e8e79bbaa911ab4b95..faff003b260807b258701aa656119eb25d882a3b
@@@ -22,7 -23,8 +23,8 @@@
  
  #include "system.h"
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
+ #include "connection.h"
  #include "conf.h"
  #include "logger.h"
  #include "netutl.h"                           /* for str2address */
@@@ -50,15 -59,15 +59,15 @@@ static int config_compare(const config_
        if(result)
                return result;
        else
-               return strcmp(a->file, b->file);
+               return a->file ? strcmp(a->file, b->file) : 0;
  }
  
 -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) {
 +      *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) {
 +      splay_delete_tree(*config_tree);
        *config_tree = NULL;
  }
  
@@@ -87,10 -96,10 +96,10 @@@ config_t *lookup_config(splay_tree_t *c
        config_t cfg, *found;
  
        cfg.variable = variable;
-       cfg.file = "";
+       cfg.file = NULL;
        cfg.line = 0;
  
 -      found = avl_search_closest_greater(config_tree, &cfg);
 +      found = splay_search_closest_greater(config_tree, &cfg);
  
        if(!found)
                return NULL;
@@@ -237,7 -285,7 +285,7 @@@ config_t *parse_config_line(char *line
    Parse a configuration file and put the results in the configuration tree
    starting at *base.
  */
- int read_config_file(splay_tree_t *config_tree, const char *fname) {
 -bool read_config_file(avl_tree_t *config_tree, const char *fname) {
++bool read_config_file(splay_tree_t *config_tree, const char *fname) {
        FILE *fp;
        char buffer[MAX_STRING_SIZE];
        char *line;
        return result;
  }
  
 -void read_config_options(avl_tree_t *config_tree, const char *prefix) {
++void read_config_options(splay_tree_t *config_tree, const char *prefix) {
+       list_node_t *node, *next;
+       size_t prefix_len = prefix ? strlen(prefix) : 0;
+       for(node = cmdline_conf->tail; node; node = next) {
+               config_t *cfg = (config_t *)node->data;
+               next = node->prev;
+               if(!prefix && strchr(cfg->variable, '.'))
+                       continue;
+               if(prefix && (strncmp(prefix, cfg->variable, prefix_len) || cfg->variable[prefix_len] != '.'))
+                       continue;
+               config_add(config_tree, cfg);
+               node->data = NULL;
+               list_unlink_node(cmdline_conf, node);
+       }
+ }
  bool read_server_config() {
        char *fname;
        bool x;
        return x;
  }
  
 -FILE *ask_and_open(const char *filename, const char *what) {
 -      FILE *r;
 -      char *directory;
 -      char line[PATH_MAX];
 -      const 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 = 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, line, sizeof line);
 -
 -              if(!fn) {
 -                      fprintf(stderr, "Error while reading stdin: %s\n",
 -                                      strerror(errno));
 -                      return NULL;
 -              }
 -
 -              if(!strlen(fn))
 -                      /* User just pressed enter. */
 -                      fn = 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(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));
 -              return NULL;
 -      }
 -
 -      return r;
 -}
 -
+ bool read_connection_config(connection_t *c) {
+       char *fname;
+       bool x;
+       read_config_options(c->config_tree, c->name);
+       xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
+       x = read_config_file(c->config_tree, fname);
+       free(fname);
+       return x;
+ }
  bool disable_old_keys(FILE *f) {
        char buf[100];
        long pos;
diff --cc src/conf.h
index be70c24c32c8ce4d4adeb1dbcde8e8c652e4ad6a,3eae4ad7227e96117280926260436785ec155131..cc57e82b4a11bfc27d949912b88d3025e775fc89
@@@ -21,7 -21,8 +21,8 @@@
  #ifndef __TINC_CONF_H__
  #define __TINC_CONF_H__
  
 -#include "avl_tree.h"
 +#include "splay_tree.h"
+ #include "list.h"
  
  typedef struct config_t {
        char *variable;
@@@ -40,23 -41,27 +41,27 @@@ extern int maxtimeout
  extern bool bypass_security;
  extern char *confbase;
  extern char *netname;
+ extern list_t *cmdline_conf;
  
 -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(splay_tree_t *, const char *);
+ extern config_t *parse_config_line(char *, const char *, int);
 -extern bool read_config_file(avl_tree_t *, const char *);
 -extern void read_config_options(avl_tree_t *, const char *);
++extern bool read_config_file(splay_tree_t *, const char *);
++extern void read_config_options(splay_tree_t *, const char *);
  extern bool read_server_config(void);
 -extern FILE *ask_and_open(const char *, const char *);
+ extern bool read_connection_config(struct connection_t *);
 +extern FILE *ask_and_open(const char *, const char *, const char *);
  extern bool is_safe_path(const char *);
  extern bool disable_old_keys(FILE *);
  
index 18c03c7e8c808377e843f10e77b836296b876f36,ac946abe12c53c3c914dfda6b0bbabd593dec339..fecb48d42d141d37a1830e039fd91e8d629736d9
@@@ -89,31 -109,21 +89,20 @@@ void connection_add(connection_t *c) 
  }
  
  void connection_del(connection_t *c) {
 -      avl_delete(connection_tree, c);
 +      splay_delete(connection_tree, c);
  }
  
 -void dump_connections(void) {
 -      avl_node_t *node;
 +bool dump_connections(connection_t *cdump) {
 +      splay_node_t *node;
        connection_t *c;
  
 -      logger(LOG_DEBUG, "Connections:");
 -
        for(node = connection_tree->head; node; node = node->next) {
                c = node->data;
 -              logger(LOG_DEBUG, " %s at %s options %x 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);
 +              send_request(cdump, "%d %d %s at %s options %x socket %d status %04x",
 +                              CONTROL, REQ_DUMP_CONNECTIONS,
 +                              c->name, c->hostname, c->options, c->socket,
 +                              bitfield_to_int(&c->status, sizeof c->status));
        }
  
 -      logger(LOG_DEBUG, "End of connections.");
 +      return send_request(cdump, "%d %d", CONTROL, REQ_DUMP_CONNECTIONS);
  }
- bool read_connection_config(connection_t *c) {
-       char *fname;
-       bool x;
-       xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
-       x = read_config_file(c->config_tree, fname);
-       free(fname);
-       return x;
- }
index 0f2b1d6a44d86ac0b72f453245203e1a399d98f6,05e8b4bae165b79041934fac21015eb6657fb846..0fc49ef38d4fe19228d191d0db37b5707474d302
@@@ -99,7 -110,6 +99,6 @@@ 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 bool dump_connections(struct connection_t *);
- extern bool read_connection_config(connection_t *);
  
  #endif                                                        /* __TINC_CONNECTION_H__ */
Simple merge
diff --cc src/getopt.c
index b2f88b42305f174aa1ebe0668501e6a8da401ac3,0000000000000000000000000000000000000000..a6782ed667b46fccfb2a01b76ed18b5d4dcff591
mode 100644,000000..100644
--- /dev/null
@@@ -1,1042 -1,0 +1,1048 @@@
-                  if (argv[optind - 1][1] == '-')
-                   /* --option */
-                   fprintf (stderr,
-                    "%s: option `--%s' doesn't allow an argument\n",
-                    argv[0], pfound->name);
-                  else
-                   /* +option or -option */
-                   fprintf (stderr,
-                    "%s: option `%c%s' doesn't allow an argument\n",
-                    argv[0], argv[optind - 1][0], pfound->name);
 +/* Getopt for GNU.
 +   NOTE: getopt is now part of the C library, so if you don't know what
 +   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
 +   before changing it!
 +
 +   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97
 +      Free Software Foundation, Inc.
 +
 +NOTE: The canonical source of this file is maintained with the GNU C Library.
 +Bugs can be reported to bug-glibc@prep.ai.mit.edu.
 +
 +This program is free software; you can redistribute it and/or modify it
 +under the terms of the GNU General Public License as published by the
 +Free Software Foundation; either version 2, or (at your option) any
 +later version.
 +
 +This program is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +GNU General Public License for more details.
 +
 +You should have received a copy of the GNU General Public License along
 +with this program; if not, write to the Free Software Foundation, Inc.,
 +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 +*/
 +\f
 +/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
 +   Ditto for AIX 3.2 and <stdlib.h>.  */
 +#ifndef _NO_PROTO
 +#define _NO_PROTO
 +#endif
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#if !defined (__STDC__) || !__STDC__
 +/* This is a separate conditional since some stdc systems
 +   reject `defined (const)'.  */
 +#ifndef const
 +#define const
 +#endif
 +#endif
 +
 +#include <stdio.h>
 +
++#ifdef HAVE_STRING_H
++#include <string.h>
++#endif
++
 +/* Comment out all this code if we are using the GNU C Library, and are not
 +   actually compiling the library itself.  This code is part of the GNU C
 +   Library, but also included in many other GNU distributions.  Compiling
 +   and linking in this code is a waste when using the GNU C library
 +   (especially if it is a shared library).  Rather than having every GNU
 +   program understand `configure --with-gnu-libc' and omit the object files,
 +   it is simpler to just do this in the source for each such file.  */
 +
 +#define GETOPT_INTERFACE_VERSION 2
 +#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
 +#include <gnu-versions.h>
 +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
 +#define ELIDE_CODE
 +#endif
 +#endif
 +
 +#ifndef ELIDE_CODE
 +
 +
 +/* This needs to come after some library #include
 +   to get __GNU_LIBRARY__ defined.  */
 +#ifdef        __GNU_LIBRARY__
 +/* Don't include stdlib.h for non-GNU C libraries because some of them
 +   contain conflicting prototypes for getopt.  */
 +#include <stdlib.h>
 +#include <unistd.h>
 +#endif        /* GNU C library.  */
 +
 +#ifdef VMS
 +#include <unixlib.h>
 +#if HAVE_STRING_H - 0
 +#include <string.h>
 +#endif
 +#endif
 +
 +#if defined (WIN32) && !defined (__CYGWIN32__)
 +/* It's not Unix, really.  See?  Capital letters.  */
 +#include <windows.h>
 +#define getpid() GetCurrentProcessId()
 +#endif
 +
 +/* This version of `getopt' appears to the caller like standard Unix `getopt'
 +   but it behaves differently for the user, since it allows the user
 +   to intersperse the options with the other arguments.
 +
 +   As `getopt' works, it permutes the elements of ARGV so that,
 +   when it is done, all the options precede everything else.  Thus
 +   all application programs are extended to handle flexible argument order.
 +
 +   Setting the environment variable POSIXLY_CORRECT disables permutation.
 +   Then the behavior is completely standard.
 +
 +   GNU application programs can use a third alternative mode in which
 +   they can distinguish the relative order of options and other arguments.  */
 +
 +#include "getopt.h"
 +
 +/* For communication from `getopt' to the caller.
 +   When `getopt' finds an option that takes an argument,
 +   the argument value is returned here.
 +   Also, when `ordering' is RETURN_IN_ORDER,
 +   each non-option ARGV-element is returned here.  */
 +
 +char *optarg = NULL;
 +
 +/* Index in ARGV of the next element to be scanned.
 +   This is used for communication to and from the caller
 +   and for communication between successive calls to `getopt'.
 +
 +   On entry to `getopt', zero means this is the first call; initialize.
 +
 +   When `getopt' returns -1, this is the index of the first of the
 +   non-option elements that the caller should itself scan.
 +
 +   Otherwise, `optind' communicates from one call to the next
 +   how much of ARGV has been scanned so far.  */
 +
 +/* 1003.2 says this must be 1 before any call.  */
 +int optind = 1;
 +
 +/* Formerly, initialization of getopt depended on optind==0, which
 +   causes problems with re-calling getopt as programs generally don't
 +   know that. */
 +
 +int __getopt_initialized = 0;
 +
 +/* The next char to be scanned in the option-element
 +   in which the last option character we returned was found.
 +   This allows us to pick up the scan where we left off.
 +
 +   If this is zero, or a null string, it means resume the scan
 +   by advancing to the next ARGV-element.  */
 +
 +static char *nextchar;
 +
 +/* Callers store zero here to inhibit the error message
 +   for unrecognized options.  */
 +
 +int opterr = 1;
 +
 +/* Set to an option character which was unrecognized.
 +   This must be initialized on some systems to avoid linking in the
 +   system's own getopt implementation.  */
 +
 +int optopt = '?';
 +
 +/* Describe how to deal with options that follow non-option ARGV-elements.
 +
 +   If the caller did not specify anything,
 +   the default is REQUIRE_ORDER if the environment variable
 +   POSIXLY_CORRECT is defined, PERMUTE otherwise.
 +
 +   REQUIRE_ORDER means don't recognize them as options;
 +   stop option processing when the first non-option is seen.
 +   This is what Unix does.
 +   This mode of operation is selected by either setting the environment
 +   variable POSIXLY_CORRECT, or using `+' as the first character
 +   of the list of option characters.
 +
 +   PERMUTE is the default.  We permute the contents of ARGV as we scan,
 +   so that eventually all the non-options are at the end.  This allows options
 +   to be given in any order, even with programs that were not written to
 +   expect this.
 +
 +   RETURN_IN_ORDER is an option available to programs that were written
 +   to expect options and other ARGV-elements in any order and that care about
 +   the ordering of the two.  We describe each non-option ARGV-element
 +   as if it were the argument of an option with character code 1.
 +   Using `-' as the first character of the list of option characters
 +   selects this mode of operation.
 +
 +   The special argument `--' forces an end of option-scanning regardless
 +   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
 +   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */
 +
 +static enum
 +{
 +  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
 +} ordering;
 +
 +/* Value of POSIXLY_CORRECT environment variable.  */
 +static char *posixly_correct;
 +\f
 +#ifdef        __GNU_LIBRARY__
 +/* We want to avoid inclusion of string.h with non-GNU libraries
 +   because there are many ways it can cause trouble.
 +   On some systems, it contains special magic macros that don't work
 +   in GCC.  */
 +#include <string.h>
 +#define       my_index        strchr
 +#else
 +
 +/* Avoid depending on library functions or files
 +   whose names are inconsistent.  */
 +
 +char *getenv ();
 +
 +static char *
 +my_index (str, chr)
 +     const char *str;
 +     int chr;
 +{
 +  while (*str)
 +    {
 +      if (*str == chr)
 +      return (char *) str;
 +      str++;
 +    }
 +  return 0;
 +}
 +
 +/* If using GCC, we can safely declare strlen this way.
 +   If not using GCC, it is ok not to declare it.  */
 +#ifdef __GNUC__
 +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
 +   That was relevant to code that was here before.  */
 +#if !defined (__STDC__) || !__STDC__
 +/* gcc with -traditional declares the built-in strlen to return int,
 +   and has done so at least since version 2.4.5. -- rms.  */
 +extern int strlen (const char *);
 +#endif /* not __STDC__ */
 +#endif /* __GNUC__ */
 +
 +#endif /* not __GNU_LIBRARY__ */
 +\f
 +/* Handle permutation of arguments.  */
 +
 +/* Describe the part of ARGV that contains non-options that have
 +   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
 +   `last_nonopt' is the index after the last of them.  */
 +
 +static int first_nonopt;
 +static int last_nonopt;
 +
 +#ifdef _LIBC
 +/* Bash 2.0 gives us an environment variable containing flags
 +   indicating ARGV elements that should not be considered arguments.  */
 +
 +/* Defined in getopt_init.c  */
 +extern char *__getopt_nonoption_flags;
 +
 +static int nonoption_flags_max_len;
 +static int nonoption_flags_len;
 +
 +static int original_argc;
 +static char *const *original_argv;
 +
 +extern pid_t __libc_pid;
 +
 +/* Make sure the environment variable bash 2.0 puts in the environment
 +   is valid for the getopt call we must make sure that the ARGV passed
 +   to getopt is that one passed to the process.  */
 +static void
 +__attribute__ ((__unused__))
 +store_args_and_env (int argc, char *const *argv)
 +{
 +  /* XXX This is no good solution.  We should rather copy the args so
 +     that we can compare them later.  But we must not use malloc(3).  */
 +  original_argc = argc;
 +  original_argv = argv;
 +}
 +text_set_element (__libc_subinit, store_args_and_env);
 +
 +# define SWAP_FLAGS(ch1, ch2) \
 +  if (nonoption_flags_len > 0)                                                      \
 +    {                                                                       \
 +      char __tmp = __getopt_nonoption_flags[ch1];                           \
 +      __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2];        \
 +      __getopt_nonoption_flags[ch2] = __tmp;                                \
 +    }
 +#else /* !_LIBC */
 +# define SWAP_FLAGS(ch1, ch2)
 +#endif        /* _LIBC */
 +
 +/* Exchange two adjacent subsequences of ARGV.
 +   One subsequence is elements [first_nonopt,last_nonopt)
 +   which contains all the non-options that have been skipped so far.
 +   The other is elements [last_nonopt,optind), which contains all
 +   the options processed since those non-options were skipped.
 +
 +   `first_nonopt' and `last_nonopt' are relocated so that they describe
 +   the new indices of the non-options in ARGV after they are moved.  */
 +
 +#if defined (__STDC__) && __STDC__
 +static void exchange (char **);
 +#endif
 +
 +static void
 +exchange (argv)
 +     char **argv;
 +{
 +  int bottom = first_nonopt;
 +  int middle = last_nonopt;
 +  int top = optind;
 +  char *tem;
 +
 +  /* Exchange the shorter segment with the far end of the longer segment.
 +     That puts the shorter segment into the right place.
 +     It leaves the longer segment in the right place overall,
 +     but it consists of two parts that need to be swapped next.  */
 +
 +#ifdef _LIBC
 +  /* First make sure the handling of the `__getopt_nonoption_flags'
 +     string can work normally.  Our top argument must be in the range
 +     of the string.  */
 +  if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
 +    {
 +      /* We must extend the array.  The user plays games with us and
 +       presents new arguments.  */
 +      char *new_str = malloc (top + 1);
 +      if (new_str == NULL)
 +      nonoption_flags_len = nonoption_flags_max_len = 0;
 +      else
 +      {
 +        memcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len);
 +        memset (&new_str[nonoption_flags_max_len], '\0',
 +                top + 1 - nonoption_flags_max_len);
 +        nonoption_flags_max_len = top + 1;
 +        __getopt_nonoption_flags = new_str;
 +      }
 +    }
 +#endif
 +
 +  while (top > middle && middle > bottom)
 +    {
 +      if (top - middle > middle - bottom)
 +      {
 +        /* Bottom segment is the short one.  */
 +        int len = middle - bottom;
 +        register int i;
 +
 +        /* Swap it with the top part of the top segment.  */
 +        for (i = 0; i < len; i++)
 +          {
 +            tem = argv[bottom + i];
 +            argv[bottom + i] = argv[top - (middle - bottom) + i];
 +            argv[top - (middle - bottom) + i] = tem;
 +            SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
 +          }
 +        /* Exclude the moved bottom segment from further swapping.  */
 +        top -= len;
 +      }
 +      else
 +      {
 +        /* Top segment is the short one.  */
 +        int len = top - middle;
 +        register int i;
 +
 +        /* Swap it with the bottom part of the bottom segment.  */
 +        for (i = 0; i < len; i++)
 +          {
 +            tem = argv[bottom + i];
 +            argv[bottom + i] = argv[middle + i];
 +            argv[middle + i] = tem;
 +            SWAP_FLAGS (bottom + i, middle + i);
 +          }
 +        /* Exclude the moved top segment from further swapping.  */
 +        bottom += len;
 +      }
 +    }
 +
 +  /* Update records for the slots the non-options now occupy.  */
 +
 +  first_nonopt += (optind - last_nonopt);
 +  last_nonopt = optind;
 +}
 +
 +/* Initialize the internal data when the first call is made.  */
 +
 +#if defined (__STDC__) && __STDC__
 +static const char *_getopt_initialize (int, char *const *, const char *);
 +#endif
 +static const char *
 +_getopt_initialize (argc, argv, optstring)
 +     int argc;
 +     char *const *argv;
 +     const char *optstring;
 +{
 +  /* Start processing options with ARGV-element 1 (since ARGV-element 0
 +     is the program name); the sequence of previously skipped
 +     non-option ARGV-elements is empty.  */
 +
 +  first_nonopt = last_nonopt = optind;
 +
 +  nextchar = NULL;
 +
 +  posixly_correct = getenv ("POSIXLY_CORRECT");
 +
 +  /* Determine how to handle the ordering of options and nonoptions.  */
 +
 +  if (optstring[0] == '-')
 +    {
 +      ordering = RETURN_IN_ORDER;
 +      ++optstring;
 +    }
 +  else if (optstring[0] == '+')
 +    {
 +      ordering = REQUIRE_ORDER;
 +      ++optstring;
 +    }
 +  else if (posixly_correct != NULL)
 +    ordering = REQUIRE_ORDER;
 +  else
 +    ordering = PERMUTE;
 +
 +#ifdef _LIBC
 +  if (posixly_correct == NULL
 +      && argc == original_argc && argv == original_argv)
 +    {
 +      if (nonoption_flags_max_len == 0)
 +      {
 +        if (__getopt_nonoption_flags == NULL
 +            || __getopt_nonoption_flags[0] == '\0')
 +          nonoption_flags_max_len = -1;
 +        else
 +          {
 +            const char *orig_str = __getopt_nonoption_flags;
 +            int len = nonoption_flags_max_len = strlen (orig_str);
 +            if (nonoption_flags_max_len < argc)
 +              nonoption_flags_max_len = argc;
 +            __getopt_nonoption_flags =
 +              (char *) malloc (nonoption_flags_max_len);
 +            if (__getopt_nonoption_flags == NULL)
 +              nonoption_flags_max_len = -1;
 +            else
 +              {
 +                memcpy (__getopt_nonoption_flags, orig_str, len);
 +                memset (&__getopt_nonoption_flags[len], '\0',
 +                        nonoption_flags_max_len - len);
 +              }
 +          }
 +      }
 +      nonoption_flags_len = nonoption_flags_max_len;
 +    }
 +  else
 +    nonoption_flags_len = 0;
 +#endif
 +
 +  return optstring;
 +}
 +\f
 +/* Scan elements of ARGV (whose length is ARGC) for option characters
 +   given in OPTSTRING.
 +
 +   If an element of ARGV starts with '-', and is not exactly "-" or "--",
 +   then it is an option element.  The characters of this element
 +   (aside from the initial '-') are option characters.  If `getopt'
 +   is called repeatedly, it returns successively each of the option characters
 +   from each of the option elements.
 +
 +   If `getopt' finds another option character, it returns that character,
 +   updating `optind' and `nextchar' so that the next call to `getopt' can
 +   resume the scan with the following option character or ARGV-element.
 +
 +   If there are no more option characters, `getopt' returns -1.
 +   Then `optind' is the index in ARGV of the first ARGV-element
 +   that is not an option.  (The ARGV-elements have been permuted
 +   so that those that are not options now come last.)
 +
 +   OPTSTRING is a string containing the legitimate option characters.
 +   If an option character is seen that is not listed in OPTSTRING,
 +   return '?' after printing an error message.  If you set `opterr' to
 +   zero, the error message is suppressed but we still return '?'.
 +
 +   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
 +   so the following text in the same ARGV-element, or the text of the following
 +   ARGV-element, is returned in `optarg'.  Two colons mean an option that
 +   wants an optional arg; if there is text in the current ARGV-element,
 +   it is returned in `optarg', otherwise `optarg' is set to zero.
 +
 +   If OPTSTRING starts with `-' or `+', it requests different methods of
 +   handling the non-option ARGV-elements.
 +   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
 +
 +   Long-named options begin with `--' instead of `-'.
 +   Their names may be abbreviated as long as the abbreviation is unique
 +   or is an exact match for some defined option.  If they have an
 +   argument, it follows the option name in the same ARGV-element, separated
 +   from the option name by a `=', or else the in next ARGV-element.
 +   When `getopt' finds a long-named option, it returns 0 if that option's
 +   `flag' field is nonzero, the value of the option's `val' field
 +   if the `flag' field is zero.
 +
 +   The elements of ARGV aren't really const, because we permute them.
 +   But we pretend they're const in the prototype to be compatible
 +   with other systems.
 +
 +   LONGOPTS is a vector of `struct option' terminated by an
 +   element containing a name which is zero.
 +
 +   LONGIND returns the index in LONGOPT of the long-named option found.
 +   It is only valid when a long-named option has been found by the most
 +   recent call.
 +
 +   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
 +   long-named options.  */
 +
 +int
 +_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
 +     int argc;
 +     char *const *argv;
 +     const char *optstring;
 +     const struct option *longopts;
 +     int *longind;
 +     int long_only;
 +{
 +  optarg = NULL;
 +
 +  if (optind == 0 || !__getopt_initialized)
 +    {
 +      if (optind == 0)
 +      optind = 1;     /* Don't scan ARGV[0], the program name.  */
 +      optstring = _getopt_initialize (argc, argv, optstring);
 +      __getopt_initialized = 1;
 +    }
 +
 +  /* Test whether ARGV[optind] points to a non-option argument.
 +     Either it does not have option syntax, or there is an environment flag
 +     from the shell indicating it is not an option.  The later information
 +     is only used when the used in the GNU libc.  */
 +#ifdef _LIBC
 +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'              \
 +                   || (optind < nonoption_flags_len                         \
 +                       && __getopt_nonoption_flags[optind] == '1'))
 +#else
 +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
 +#endif
 +
 +  if (nextchar == NULL || *nextchar == '\0')
 +    {
 +      /* Advance to the next ARGV-element.  */
 +
 +      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
 +       moved back by the user (who may also have changed the arguments).  */
 +      if (last_nonopt > optind)
 +      last_nonopt = optind;
 +      if (first_nonopt > optind)
 +      first_nonopt = optind;
 +
 +      if (ordering == PERMUTE)
 +      {
 +        /* If we have just processed some options following some non-options,
 +           exchange them so that the options come first.  */
 +
 +        if (first_nonopt != last_nonopt && last_nonopt != optind)
 +          exchange ((char **) argv);
 +        else if (last_nonopt != optind)
 +          first_nonopt = optind;
 +
 +        /* Skip any additional non-options
 +           and extend the range of non-options previously skipped.  */
 +
 +        while (optind < argc && NONOPTION_P)
 +          optind++;
 +        last_nonopt = optind;
 +      }
 +
 +      /* The special ARGV-element `--' means premature end of options.
 +       Skip it like a null option,
 +       then exchange with previous non-options as if it were an option,
 +       then skip everything else like a non-option.  */
 +
 +      if (optind != argc && !strcmp (argv[optind], "--"))
 +      {
 +        optind++;
 +
 +        if (first_nonopt != last_nonopt && last_nonopt != optind)
 +          exchange ((char **) argv);
 +        else if (first_nonopt == last_nonopt)
 +          first_nonopt = optind;
 +        last_nonopt = argc;
 +
 +        optind = argc;
 +      }
 +
 +      /* If we have done all the ARGV-elements, stop the scan
 +       and back over any non-options that we skipped and permuted.  */
 +
 +      if (optind == argc)
 +      {
 +        /* Set the next-arg-index to point at the non-options
 +           that we previously skipped, so the caller will digest them.  */
 +        if (first_nonopt != last_nonopt)
 +          optind = first_nonopt;
 +        return -1;
 +      }
 +
 +      /* If we have come to a non-option and did not permute it,
 +       either stop the scan or describe it to the caller and pass it by.  */
 +
 +      if (NONOPTION_P)
 +      {
 +        if (ordering == REQUIRE_ORDER)
 +          return -1;
 +        optarg = argv[optind++];
 +        return 1;
 +      }
 +
 +      /* We have found another option-ARGV-element.
 +       Skip the initial punctuation.  */
 +
 +      nextchar = (argv[optind] + 1
 +                + (longopts != NULL && argv[optind][1] == '-'));
 +    }
 +
 +  /* Decode the current option-ARGV-element.  */
 +
 +  /* Check whether the ARGV-element is a long option.
 +
 +     If long_only and the ARGV-element has the form "-f", where f is
 +     a valid short option, don't consider it an abbreviated form of
 +     a long option that starts with f.  Otherwise there would be no
 +     way to give the -f short option.
 +
 +     On the other hand, if there's a long option "fubar" and
 +     the ARGV-element is "-fu", do consider that an abbreviation of
 +     the long option, just like "--fu", and not "-f" with arg "u".
 +
 +     This distinction seems to be the most useful approach.  */
 +
 +  if (longopts != NULL
 +      && (argv[optind][1] == '-'
 +        || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
 +    {
 +      char *nameend;
 +      const struct option *p;
 +      const struct option *pfound = NULL;
 +      int exact = 0;
 +      int ambig = 0;
 +      int indfound = -1;
 +      int option_index;
 +
 +      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
 +      /* Do nothing.  */ ;
 +
 +      /* Test all long options for either exact match
 +       or abbreviated matches.  */
 +      for (p = longopts, option_index = 0; p->name; p++, option_index++)
 +      if (!strncmp (p->name, nextchar, nameend - nextchar))
 +        {
 +          if ((unsigned int) (nameend - nextchar)
 +              == (unsigned int) strlen (p->name))
 +            {
 +              /* Exact match found.  */
 +              pfound = p;
 +              indfound = option_index;
 +              exact = 1;
 +              break;
 +            }
 +          else if (pfound == NULL)
 +            {
 +              /* First nonexact match found.  */
 +              pfound = p;
 +              indfound = option_index;
 +            }
 +          else
 +            /* Second or later nonexact match found.  */
 +            ambig = 1;
 +        }
 +
 +      if (ambig && !exact)
 +      {
 +        if (opterr)
 +          fprintf (stderr, "%s: option `%s' is ambiguous\n",
 +                   argv[0], argv[optind]);
 +        nextchar += strlen (nextchar);
 +        optind++;
 +        optopt = 0;
 +        return '?';
 +      }
 +
 +      if (pfound != NULL)
 +      {
 +        option_index = indfound;
 +        optind++;
 +        if (*nameend)
 +          {
 +            /* Don't test has_arg with >, because some C compilers don't
 +               allow it to be used on enums.  */
 +            if (pfound->has_arg)
 +              optarg = nameend + 1;
 +            else
 +              {
 +                if (opterr)
++                  {
++                   if (argv[optind - 1][1] == '-')
++                    /* --option */
++                    fprintf (stderr,
++                     "%s: option `--%s' doesn't allow an argument\n",
++                     argv[0], pfound->name);
++                   else
++                    /* +option or -option */
++                    fprintf (stderr,
++                     "%s: option `%c%s' doesn't allow an argument\n",
++                     argv[0], argv[optind - 1][0], pfound->name);
++                  }
 +
 +                nextchar += strlen (nextchar);
 +
 +                optopt = pfound->val;
 +                return '?';
 +              }
 +          }
 +        else if (pfound->has_arg == 1)
 +          {
 +            if (optind < argc)
 +              optarg = argv[optind++];
 +            else
 +              {
 +                if (opterr)
 +                  fprintf (stderr,
 +                         "%s: option `%s' requires an argument\n",
 +                         argv[0], argv[optind - 1]);
 +                nextchar += strlen (nextchar);
 +                optopt = pfound->val;
 +                return optstring[0] == ':' ? ':' : '?';
 +              }
 +          }
 +        nextchar += strlen (nextchar);
 +        if (longind != NULL)
 +          *longind = option_index;
 +        if (pfound->flag)
 +          {
 +            *(pfound->flag) = pfound->val;
 +            return 0;
 +          }
 +        return pfound->val;
 +      }
 +
 +      /* Can't find it as a long option.  If this is not getopt_long_only,
 +       or the option starts with '--' or is not a valid short
 +       option, then it's an error.
 +       Otherwise interpret it as a short option.  */
 +      if (!long_only || argv[optind][1] == '-'
 +        || my_index (optstring, *nextchar) == NULL)
 +      {
 +        if (opterr)
 +          {
 +            if (argv[optind][1] == '-')
 +              /* --option */
 +              fprintf (stderr, "%s: unrecognized option `--%s'\n",
 +                       argv[0], nextchar);
 +            else
 +              /* +option or -option */
 +              fprintf (stderr, "%s: unrecognized option `%c%s'\n",
 +                       argv[0], argv[optind][0], nextchar);
 +          }
 +        nextchar = (char *) "";
 +        optind++;
 +        optopt = 0;
 +        return '?';
 +      }
 +    }
 +
 +  /* Look at and handle the next short option-character.  */
 +
 +  {
 +    char c = *nextchar++;
 +    char *temp = my_index (optstring, c);
 +
 +    /* Increment `optind' when we start to process its last character.  */
 +    if (*nextchar == '\0')
 +      ++optind;
 +
 +    if (temp == NULL || c == ':')
 +      {
 +      if (opterr)
 +        {
 +          if (posixly_correct)
 +            /* 1003.2 specifies the format of this message.  */
 +            fprintf (stderr, "%s: illegal option -- %c\n",
 +                     argv[0], c);
 +          else
 +            fprintf (stderr, "%s: invalid option -- %c\n",
 +                     argv[0], c);
 +        }
 +      optopt = c;
 +      return '?';
 +      }
 +    /* Convenience. Treat POSIX -W foo same as long option --foo */
 +    if (temp[0] == 'W' && temp[1] == ';')
 +      {
 +      char *nameend;
 +      const struct option *p;
 +      const struct option *pfound = NULL;
 +      int exact = 0;
 +      int ambig = 0;
 +      int indfound = 0;
 +      int option_index;
 +
 +      /* This is an option that requires an argument.  */
 +      if (*nextchar != '\0')
 +        {
 +          optarg = nextchar;
 +          /* If we end this ARGV-element by taking the rest as an arg,
 +             we must advance to the next element now.  */
 +          optind++;
 +        }
 +      else if (optind == argc)
 +        {
 +          if (opterr)
 +            {
 +              /* 1003.2 specifies the format of this message.  */
 +              fprintf (stderr, "%s: option requires an argument -- %c\n",
 +                       argv[0], c);
 +            }
 +          optopt = c;
 +          if (optstring[0] == ':')
 +            c = ':';
 +          else
 +            c = '?';
 +          return c;
 +        }
 +      else
 +        /* We already incremented `optind' once;
 +           increment it again when taking next ARGV-elt as argument.  */
 +        optarg = argv[optind++];
 +
 +      /* optarg is now the argument, see if it's in the
 +         table of longopts.  */
 +
 +      for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
 +        /* Do nothing.  */ ;
 +
 +      /* Test all long options for either exact match
 +         or abbreviated matches.  */
 +      for (p = longopts, option_index = 0; p->name; p++, option_index++)
 +        if (!strncmp (p->name, nextchar, nameend - nextchar))
 +          {
 +            if ((unsigned int) (nameend - nextchar) == strlen (p->name))
 +              {
 +                /* Exact match found.  */
 +                pfound = p;
 +                indfound = option_index;
 +                exact = 1;
 +                break;
 +              }
 +            else if (pfound == NULL)
 +              {
 +                /* First nonexact match found.  */
 +                pfound = p;
 +                indfound = option_index;
 +              }
 +            else
 +              /* Second or later nonexact match found.  */
 +              ambig = 1;
 +          }
 +      if (ambig && !exact)
 +        {
 +          if (opterr)
 +            fprintf (stderr, "%s: option `-W %s' is ambiguous\n",
 +                     argv[0], argv[optind]);
 +          nextchar += strlen (nextchar);
 +          optind++;
 +          return '?';
 +        }
 +      if (pfound != NULL)
 +        {
 +          option_index = indfound;
 +          if (*nameend)
 +            {
 +              /* Don't test has_arg with >, because some C compilers don't
 +                 allow it to be used on enums.  */
 +              if (pfound->has_arg)
 +                optarg = nameend + 1;
 +              else
 +                {
 +                  if (opterr)
 +                    fprintf (stderr,
 +                             "%s: option `-W %s' doesn't allow an argument\n",
 +                             argv[0], pfound->name);
 +
 +                  nextchar += strlen (nextchar);
 +                  return '?';
 +                }
 +            }
 +          else if (pfound->has_arg == 1)
 +            {
 +              if (optind < argc)
 +                optarg = argv[optind++];
 +              else
 +                {
 +                  if (opterr)
 +                    fprintf (stderr,
 +                             "%s: option `%s' requires an argument\n",
 +                             argv[0], argv[optind - 1]);
 +                  nextchar += strlen (nextchar);
 +                  return optstring[0] == ':' ? ':' : '?';
 +                }
 +            }
 +          nextchar += strlen (nextchar);
 +          if (longind != NULL)
 +            *longind = option_index;
 +          if (pfound->flag)
 +            {
 +              *(pfound->flag) = pfound->val;
 +              return 0;
 +            }
 +          return pfound->val;
 +        }
 +        nextchar = NULL;
 +        return 'W';   /* Let the application handle it.   */
 +      }
 +    if (temp[1] == ':')
 +      {
 +      if (temp[2] == ':')
 +        {
 +          /* This is an option that accepts an argument optionally.  */
 +          if (*nextchar != '\0')
 +            {
 +              optarg = nextchar;
 +              optind++;
 +            }
 +          else
 +            optarg = NULL;
 +          nextchar = NULL;
 +        }
 +      else
 +        {
 +          /* This is an option that requires an argument.  */
 +          if (*nextchar != '\0')
 +            {
 +              optarg = nextchar;
 +              /* If we end this ARGV-element by taking the rest as an arg,
 +                 we must advance to the next element now.  */
 +              optind++;
 +            }
 +          else if (optind == argc)
 +            {
 +              if (opterr)
 +                {
 +                  /* 1003.2 specifies the format of this message.  */
 +                  fprintf (stderr,
 +                         "%s: option requires an argument -- %c\n",
 +                         argv[0], c);
 +                }
 +              optopt = c;
 +              if (optstring[0] == ':')
 +                c = ':';
 +              else
 +                c = '?';
 +            }
 +          else
 +            /* We already incremented `optind' once;
 +               increment it again when taking next ARGV-elt as argument.  */
 +            optarg = argv[optind++];
 +          nextchar = NULL;
 +        }
 +      }
 +    return c;
 +  }
 +}
 +
 +int
 +getopt (argc, argv, optstring)
 +     int argc;
 +     char *const *argv;
 +     const char *optstring;
 +{
 +  return _getopt_internal (argc, argv, optstring,
 +                         (const struct option *) 0,
 +                         (int *) 0,
 +                         0);
 +}
 +
 +#endif        /* Not ELIDE_CODE.  */
 +\f
 +#ifdef TEST
 +
 +/* Compile with -DTEST to make an executable for use in testing
 +   the above definition of `getopt'.  */
 +
 +int
 +main (argc, argv)
 +     int argc;
 +     char **argv;
 +{
 +  int c;
 +  int digit_optind = 0;
 +
 +  while (1)
 +    {
 +      int this_option_optind = optind ? optind : 1;
 +
 +      c = getopt (argc, argv, "abc:d:0123456789");
 +      if (c == -1)
 +      break;
 +
 +      switch (c)
 +      {
 +      case '0':
 +      case '1':
 +      case '2':
 +      case '3':
 +      case '4':
 +      case '5':
 +      case '6':
 +      case '7':
 +      case '8':
 +      case '9':
 +        if (digit_optind != 0 && digit_optind != this_option_optind)
 +          printf ("digits occur in two different argv-elements.\n");
 +        digit_optind = this_option_optind;
 +        printf ("option %c\n", c);
 +        break;
 +
 +      case 'a':
 +        printf ("option a\n");
 +        break;
 +
 +      case 'b':
 +        printf ("option b\n");
 +        break;
 +
 +      case 'c':
 +        printf ("option c with value `%s'\n", optarg);
 +        break;
 +
 +      case '?':
 +        break;
 +
 +      default:
 +        printf ("?? getopt returned character code 0%o ??\n", c);
 +      }
 +    }
 +
 +  if (optind < argc)
 +    {
 +      printf ("non-option ARGV-elements: ");
 +      while (optind < argc)
 +      printf ("%s ", argv[optind++]);
 +      printf ("\n");
 +    }
 +
 +  exit (0);
 +}
 +
 +#endif /* TEST */
Simple merge
diff --cc src/logger.c
index 35a6a38ae1d5bced37f15151c1d928dec7abb05e,bc20438cc83cc3f07c13ad9115b5fc1699e8a9bb..4c0d2312939c43330e7e29a07a94e845fa5e5291
@@@ -85,8 -85,8 +85,8 @@@ void logger(int priority, const char *f
  #ifdef HAVE_MINGW
                        {
                                char message[4096];
-                               char *messages[] = {message};
+                               const 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
diff --cc src/memcmp.c
index 9d8083385f4d4bf15e480fa2d8ab5f1558ca317f,0000000000000000000000000000000000000000..8103e1a7ff53f097faca1ec5e94089a676a83e9e
mode 100644,000000..100644
--- /dev/null
@@@ -1,391 -1,0 +1,391 @@@
-   long int srcp1 = (long int) &a;
-   long int srcp2 = (long int) &b;
 +/* Copyright (C) 1991, 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
 +   Contributed by Torbjorn Granlund (tege@sics.se).
 +
 +   NOTE: The canonical source of this file is maintained with the GNU C Library.
 +   Bugs can be reported to bug-glibc@prep.ai.mit.edu.
 +
 +   This program is free software; you can redistribute it and/or modify it
 +   under the terms of the GNU General Public License as published by the
 +   Free Software Foundation; either version 2, or (at your option) any
 +   later version.
 +
 +   This program is distributed in the hope that it will be useful,
 +   but WITHOUT ANY WARRANTY; without even the implied warranty of
 +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +   GNU General Public License for more details.
 +
 +   You should have received a copy of the GNU General Public License along
 +   with this program; if not, write to the Free Software Foundation, Inc.,
 +   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 +*/
 +
 +#ifdef HAVE_CONFIG_H
 +# include "config.h"
 +#endif
 +
 +#undef        __ptr_t
 +#if defined __cplusplus || (defined __STDC__ && __STDC__)
 +# define __ptr_t      void *
 +#else /* Not C++ or ANSI C.  */
 +# undef       const
 +# define const
 +# define __ptr_t      char *
 +#endif /* C++ or ANSI C.  */
 +
 +#ifndef __P
 +# if defined __GNUC__ || (defined __STDC__ && __STDC__)
 +#  define __P(args) args
 +# else
 +#  define __P(args) ()
 +# endif  /* GCC.  */
 +#endif  /* Not __P.  */
 +
 +#if defined HAVE_STRING_H || defined _LIBC
 +# include <string.h>
 +#endif
 +
 +#undef memcmp
 +
 +#ifdef _LIBC
 +
 +# include <memcopy.h>
 +
 +#else /* Not in the GNU C library.  */
 +
 +# include <sys/types.h>
 +
 +/* Type to use for aligned memory operations.
 +   This should normally be the biggest type supported by a single load
 +   and store.  Must be an unsigned type.  */
 +# define op_t unsigned long int
 +# define OPSIZ        (sizeof(op_t))
 +
 +/* Threshold value for when to enter the unrolled loops.  */
 +# define OP_T_THRES   16
 +
 +/* Type to use for unaligned operations.  */
 +typedef unsigned char byte;
 +
 +# ifndef WORDS_BIGENDIAN
 +#  define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))
 +# else
 +#  define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2)))
 +# endif
 +
 +#endif        /* In the GNU C library.  */
 +
 +#ifdef WORDS_BIGENDIAN
 +# define CMP_LT_OR_GT(a, b) ((a) > (b) ? 1 : -1)
 +#else
 +# define CMP_LT_OR_GT(a, b) memcmp_bytes ((a), (b))
 +#endif
 +
 +/* BE VERY CAREFUL IF YOU CHANGE THIS CODE!  */
 +
 +/* The strategy of this memcmp is:
 +
 +   1. Compare bytes until one of the block pointers is aligned.
 +
 +   2. Compare using memcmp_common_alignment or
 +      memcmp_not_common_alignment, regarding the alignment of the other
 +      block after the initial byte operations.  The maximum number of
 +      full words (of type op_t) are compared in this way.
 +
 +   3. Compare the few remaining bytes.  */
 +
 +#ifndef WORDS_BIGENDIAN
 +/* memcmp_bytes -- Compare A and B bytewise in the byte order of the machine.
 +   A and B are known to be different.
 +   This is needed only on little-endian machines.  */
 +
 +static int memcmp_bytes __P((op_t, op_t));
 +
 +# ifdef  __GNUC__
 +__inline
 +# endif
 +static int
 +memcmp_bytes (a, b)
 +     op_t a, b;
 +{
- static int memcmp_common_alignment __P((long, long, size_t));
++  intptr_t srcp1 = (intptr_t) &a;
++  intptr_t srcp2 = (intptr_t) &b;
 +  op_t a0, b0;
 +
 +  do
 +    {
 +      a0 = ((byte *) srcp1)[0];
 +      b0 = ((byte *) srcp2)[0];
 +      srcp1 += 1;
 +      srcp2 += 1;
 +    }
 +  while (a0 == b0);
 +  return a0 - b0;
 +}
 +#endif
 +
-      long int srcp1;
-      long int srcp2;
++static int memcmp_common_alignment __P((intptr_t, intptr_t, size_t));
 +
 +/* memcmp_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN `op_t'
 +   objects (not LEN bytes!).  Both SRCP1 and SRCP2 should be aligned for
 +   memory operations on `op_t's.  */
 +#ifdef        __GNUC__
 +__inline
 +#endif
 +static int
 +memcmp_common_alignment (srcp1, srcp2, len)
- static int memcmp_not_common_alignment __P((long, long, size_t));
++     intptr_t srcp1;
++     intptr_t srcp2;
 +     size_t len;
 +{
 +  op_t a0, a1;
 +  op_t b0, b1;
 +
 +  switch (len % 4)
 +    {
 +    default: /* Avoid warning about uninitialized local variables.  */
 +    case 2:
 +      a0 = ((op_t *) srcp1)[0];
 +      b0 = ((op_t *) srcp2)[0];
 +      srcp1 -= 2 * OPSIZ;
 +      srcp2 -= 2 * OPSIZ;
 +      len += 2;
 +      goto do1;
 +    case 3:
 +      a1 = ((op_t *) srcp1)[0];
 +      b1 = ((op_t *) srcp2)[0];
 +      srcp1 -= OPSIZ;
 +      srcp2 -= OPSIZ;
 +      len += 1;
 +      goto do2;
 +    case 0:
 +      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
 +      return 0;
 +      a0 = ((op_t *) srcp1)[0];
 +      b0 = ((op_t *) srcp2)[0];
 +      goto do3;
 +    case 1:
 +      a1 = ((op_t *) srcp1)[0];
 +      b1 = ((op_t *) srcp2)[0];
 +      srcp1 += OPSIZ;
 +      srcp2 += OPSIZ;
 +      len -= 1;
 +      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
 +      goto do0;
 +      /* Fall through.  */
 +    }
 +
 +  do
 +    {
 +      a0 = ((op_t *) srcp1)[0];
 +      b0 = ((op_t *) srcp2)[0];
 +      if (a1 != b1)
 +      return CMP_LT_OR_GT (a1, b1);
 +
 +    do3:
 +      a1 = ((op_t *) srcp1)[1];
 +      b1 = ((op_t *) srcp2)[1];
 +      if (a0 != b0)
 +      return CMP_LT_OR_GT (a0, b0);
 +
 +    do2:
 +      a0 = ((op_t *) srcp1)[2];
 +      b0 = ((op_t *) srcp2)[2];
 +      if (a1 != b1)
 +      return CMP_LT_OR_GT (a1, b1);
 +
 +    do1:
 +      a1 = ((op_t *) srcp1)[3];
 +      b1 = ((op_t *) srcp2)[3];
 +      if (a0 != b0)
 +      return CMP_LT_OR_GT (a0, b0);
 +
 +      srcp1 += 4 * OPSIZ;
 +      srcp2 += 4 * OPSIZ;
 +      len -= 4;
 +    }
 +  while (len != 0);
 +
 +  /* This is the right position for do0.  Please don't move
 +     it into the loop.  */
 + do0:
 +  if (a1 != b1)
 +    return CMP_LT_OR_GT (a1, b1);
 +  return 0;
 +}
 +
-      long int srcp1;
-      long int srcp2;
++static int memcmp_not_common_alignment __P((intptr_t, intptr_t, size_t));
 +
 +/* memcmp_not_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN
 +   `op_t' objects (not LEN bytes!).  SRCP2 should be aligned for memory
 +   operations on `op_t', but SRCP1 *should be unaligned*.  */
 +#ifdef        __GNUC__
 +__inline
 +#endif
 +static int
 +memcmp_not_common_alignment (srcp1, srcp2, len)
-   long int srcp1 = (long int) s1;
-   long int srcp2 = (long int) s2;
++     intptr_t srcp1;
++     intptr_t srcp2;
 +     size_t len;
 +{
 +  op_t a0, a1, a2, a3;
 +  op_t b0, b1, b2, b3;
 +  op_t x;
 +  int shl, shr;
 +
 +  /* Calculate how to shift a word read at the memory operation
 +     aligned srcp1 to make it aligned for comparison.  */
 +
 +  shl = 8 * (srcp1 % OPSIZ);
 +  shr = 8 * OPSIZ - shl;
 +
 +  /* Make SRCP1 aligned by rounding it down to the beginning of the `op_t'
 +     it points in the middle of.  */
 +  srcp1 &= -OPSIZ;
 +
 +  switch (len % 4)
 +    {
 +    default: /* Avoid warning about uninitialized local variables.  */
 +    case 2:
 +      a1 = ((op_t *) srcp1)[0];
 +      a2 = ((op_t *) srcp1)[1];
 +      b2 = ((op_t *) srcp2)[0];
 +      srcp1 -= 1 * OPSIZ;
 +      srcp2 -= 2 * OPSIZ;
 +      len += 2;
 +      goto do1;
 +    case 3:
 +      a0 = ((op_t *) srcp1)[0];
 +      a1 = ((op_t *) srcp1)[1];
 +      b1 = ((op_t *) srcp2)[0];
 +      srcp2 -= 1 * OPSIZ;
 +      len += 1;
 +      goto do2;
 +    case 0:
 +      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
 +      return 0;
 +      a3 = ((op_t *) srcp1)[0];
 +      a0 = ((op_t *) srcp1)[1];
 +      b0 = ((op_t *) srcp2)[0];
 +      srcp1 += 1 * OPSIZ;
 +      goto do3;
 +    case 1:
 +      a2 = ((op_t *) srcp1)[0];
 +      a3 = ((op_t *) srcp1)[1];
 +      b3 = ((op_t *) srcp2)[0];
 +      srcp1 += 2 * OPSIZ;
 +      srcp2 += 1 * OPSIZ;
 +      len -= 1;
 +      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
 +      goto do0;
 +      /* Fall through.  */
 +    }
 +
 +  do
 +    {
 +      a0 = ((op_t *) srcp1)[0];
 +      b0 = ((op_t *) srcp2)[0];
 +      x = MERGE(a2, shl, a3, shr);
 +      if (x != b3)
 +      return CMP_LT_OR_GT (x, b3);
 +
 +    do3:
 +      a1 = ((op_t *) srcp1)[1];
 +      b1 = ((op_t *) srcp2)[1];
 +      x = MERGE(a3, shl, a0, shr);
 +      if (x != b0)
 +      return CMP_LT_OR_GT (x, b0);
 +
 +    do2:
 +      a2 = ((op_t *) srcp1)[2];
 +      b2 = ((op_t *) srcp2)[2];
 +      x = MERGE(a0, shl, a1, shr);
 +      if (x != b1)
 +      return CMP_LT_OR_GT (x, b1);
 +
 +    do1:
 +      a3 = ((op_t *) srcp1)[3];
 +      b3 = ((op_t *) srcp2)[3];
 +      x = MERGE(a1, shl, a2, shr);
 +      if (x != b2)
 +      return CMP_LT_OR_GT (x, b2);
 +
 +      srcp1 += 4 * OPSIZ;
 +      srcp2 += 4 * OPSIZ;
 +      len -= 4;
 +    }
 +  while (len != 0);
 +
 +  /* This is the right position for do0.  Please don't move
 +     it into the loop.  */
 + do0:
 +  x = MERGE(a2, shl, a3, shr);
 +  if (x != b3)
 +    return CMP_LT_OR_GT (x, b3);
 +  return 0;
 +}
 +
 +int
 +rpl_memcmp (s1, s2, len)
 +     const __ptr_t s1;
 +     const __ptr_t s2;
 +     size_t len;
 +{
 +  op_t a0;
 +  op_t b0;
++  intptr_t srcp1 = (intptr_t) s1;
++  intptr_t srcp2 = (intptr_t) s2;
 +  op_t res;
 +
 +  if (len >= OP_T_THRES)
 +    {
 +      /* There are at least some bytes to compare.  No need to test
 +       for LEN == 0 in this alignment loop.  */
 +      while (srcp2 % OPSIZ != 0)
 +      {
 +        a0 = ((byte *) srcp1)[0];
 +        b0 = ((byte *) srcp2)[0];
 +        srcp1 += 1;
 +        srcp2 += 1;
 +        res = a0 - b0;
 +        if (res != 0)
 +          return res;
 +        len -= 1;
 +      }
 +
 +      /* SRCP2 is now aligned for memory operations on `op_t'.
 +       SRCP1 alignment determines if we can do a simple,
 +       aligned compare or need to shuffle bits.  */
 +
 +      if (srcp1 % OPSIZ == 0)
 +      res = memcmp_common_alignment (srcp1, srcp2, len / OPSIZ);
 +      else
 +      res = memcmp_not_common_alignment (srcp1, srcp2, len / OPSIZ);
 +      if (res != 0)
 +      return res;
 +
 +      /* Number of bytes remaining in the interval [0..OPSIZ-1].  */
 +      srcp1 += len & -OPSIZ;
 +      srcp2 += len & -OPSIZ;
 +      len %= OPSIZ;
 +    }
 +
 +  /* There are just a few bytes to compare.  Use byte memory operations.  */
 +  while (len != 0)
 +    {
 +      a0 = ((byte *) srcp1)[0];
 +      b0 = ((byte *) srcp2)[0];
 +      srcp1 += 1;
 +      srcp2 += 1;
 +      res = a0 - b0;
 +      if (res != 0)
 +      return res;
 +      len -= 1;
 +    }
 +
 +  return 0;
 +}
 +
 +#ifdef weak_alias
 +# undef bcmp
 +weak_alias (memcmp, bcmp)
 +#endif
Simple merge
diff --cc src/net.c
index 0e5823641de349b1bb2321623be9820e0a37891c,08e3cad3ee1bf03a950748209703c47cdc943b7e..7d44d17c378f0bbbf2821bd6b4432dd43f5d6705
+++ b/src/net.c
  #include "subnet.h"
  #include "xalloc.h"
  
 -bool do_purge = false;
 -volatile bool running = false;
 -
 -time_t now = 0;
+ int contradicting_add_edge = 0;
+ int contradicting_del_edge = 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;
@@@ -187,30 -257,82 +190,43 @@@ static void timeout_handler(int fd, sho
                                }
                        }
                }
 -
 -              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;
 -      static int errors = 0;
 -
 -      /* check input from kernel */
 -      if(device_fd >= 0 && FD_ISSET(device_fd, readset)) {
 -              if(read_packet(&packet)) {
 -                      errors = 0;
 -                      packet.priority = 0;
 -                      route(myself, &packet);
 -              } else {
 -                      usleep(errors * 50000);
 -                      errors++;
 -                      if(errors > 10) {
 -                              logger(LOG_ERR, "Too many errors from %s, exiting!", device);
 -                              running = false;
 -                      }
 -              }
        }
  
 -      /* check meta connections */
 -      for(node = connection_tree->head; node; node = node->next) {
 -              c = node->data;
++      if(contradicting_del_edge && contradicting_add_edge) {
++              logger(LOG_WARNING, "Possible node with same Name as us!");
 -              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, (void *)&result, &len);
++              if(rand() % 3 == 0) {
++                      logger(LOG_ERR, "Shutting down, check configuration of all nodes for duplicate Names!");
++                      event_loopexit(NULL);
++                      return;
++              }
 -                              if(!result)
 -                                      finish_connecting(c);
 -                              else {
 -                                      ifdebug(CONNECTIONS) logger(LOG_DEBUG,
 -                                                         "Error while connecting to %s (%s): %s",
 -                                                         c->name, c->hostname, sockstrerror(result));
 -                                      closesocket(c->socket);
 -                                      do_outgoing_connection(c);
 -                                      continue;
 -                              }
 -                      }
++              contradicting_add_edge = 0;
++              contradicting_del_edge = 0;
++      }
 -                      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",
 +                                         c->name, c->hostname, sockstrerror(result));
 +                      closesocket(c->socket);
 +                      do_outgoing_connection(c);
 +                      return;
                }
        }
  
        }
  }
  
 -/*
 -  this is where it all happens...
 -*/
 -int main_loop(void) {
 -      fd_set readset, writeset;
 -      struct timeval tv;
 -      int r, maxfd;
 -      time_t last_ping_check, last_config_check, last_graph_dump;
 -      event_t *event;
 -
 -      last_ping_check = now;
 -      last_config_check = now;
 -      last_graph_dump = now;
 -      
 -      srand(now);
 -
 -      running = true;
 +static void sigterm_handler(int signal, short events, void *data) {
 +      logger(LOG_NOTICE, "Got %s signal", strsignal(signal));
 +      event_loopexit(NULL);
 +}
  
 -      while(running) {
 -              now = time(NULL);
 +static void sighup_handler(int signal, short events, void *data) {
 +      logger(LOG_NOTICE, "Got %s signal", strsignal(signal));
 +      reload_configuration();
 +}
  
 -      //      tv.tv_sec = 1 + (rand() & 7);   /* Approx. 5 seconds, randomized to prevent global synchronisation effects */
 -              tv.tv_sec = 1;
 -              tv.tv_usec = 0;
 +int reload_configuration(void) {
 +      connection_t *c;
 +      splay_node_t *node, *next;
 +      char *fname;
 +      struct stat s;
 +      static time_t last_config_check = 0;
  
 -              maxfd = build_fdset(&readset, &writeset);
 +      /* Reread our own configuration file */
  
 -#ifdef HAVE_MINGW
 -              LeaveCriticalSection(&mutex);
 -#endif
 -              r = select(maxfd + 1, &readset, &writeset, NULL, &tv);
 -#ifdef HAVE_MINGW
 -              EnterCriticalSection(&mutex);
 -#endif
 +      exit_configuration(&config_tree);
 +      init_configuration(&config_tree);
  
 -              if(r < 0) {
 -                      if(!sockwouldblock(sockerrno)) {
 -                              logger(LOG_ERR, "Error while waiting for input: %s", sockstrerror(sockerrno));
 -                              dump_connections();
 -                              return 1;
 -                      }
 -              }
 -
 -              if(r > 0)
 -                      check_network_activity(&readset, &writeset);
 +      if(!read_server_config()) {
 +              logger(LOG_ERR, "Unable to reread configuration file, exitting.");
 +              event_loopexit(NULL);
 +              return EINVAL;
 +      }
  
 -              if(do_purge) {
 -                      purge();
 -                      do_purge = 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);
 +      }
  
 -              /* 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();
 -
 -                      /* Should we regenerate our key? */
 -
 -                      if(keyexpires < now) {
 -                              avl_node_t *node;
 -                              node_t *n;
 +      last_config_check = time(NULL);
  
 -                              ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys");
 +      /* If StrictSubnet is set, expire deleted Subnets and read new ones in */
  
 -                              for(node = node_tree->head; node; node = node->next) {
 -                                      n = node->data;
 -                                      if(n->inkey) {
 -                                              free(n->inkey);
 -                                              n->inkey = NULL;
 -                                      }
 -                              }
 +      if(strictsubnets) {
 +              subnet_t *subnet;
  
 -                              send_key_changed(broadcast, myself);
 -                              keyexpires = now + keylifetime;
 -                      }
 -                      if(contradicting_del_edge && contradicting_add_edge) {
 -                              logger(LOG_WARNING, "Possible node with same Name as us!");
 -
 -                              if(rand() % 3 == 0) {
 -                                      logger(LOG_ERR, "Shutting down, check configuration of all nodes for duplicate Names!");
 -                                      running = false;
 -                                      break;
 -                              }
 -
 -                              contradicting_add_edge = 0;
 -                              contradicting_del_edge = 0;
 -                      }
 +              for(node = subnet_tree->head; node; node = node->next) {
 +                      subnet = node->data;
 +                      subnet->expires = 1;
                }
  
 -              if(sigalrm) {
 -                      avl_node_t *node;
 -                      logger(LOG_INFO, "Flushing event queue");
 -                      expire_events();
 -                      for(node = connection_tree->head; node; node = node->next) {
 -                              connection_t *c = node->data;
 -                              send_ping(c);
 +              load_all_subnets();
 +
 +              for(node = subnet_tree->head; node; node = next) {
 +                      next = node->next;
 +                      subnet = node->data;
 +                      if(subnet->expires == 1) {
 +                              send_del_subnet(broadcast, subnet);
 +                              if(subnet->owner->status.reachable)
 +                                      subnet_update(subnet->owner, subnet, false);
 +                              subnet_del(subnet->owner, subnet);
 +                      } else if(subnet->expires == -1) {
 +                              subnet->expires = 0;
 +                      } else {
 +                              send_add_subnet(broadcast, subnet);
 +                              if(subnet->owner->status.reachable)
 +                                      subnet_update(subnet->owner, subnet, true);
                        }
 -                      sigalrm = false;
 -              }
 -
 -              while((event = get_expired_event())) {
 -                      event->handler(event->data);
 -                      free_event(event);
                }
 +      }
  
 -              if(sighup) {
 -                      connection_t *c;
 -                      avl_node_t *node, *next;
 -                      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;
 -                      }
 -
 -                      /* Cancel non-active outgoing connections */
 -
 -                      for(node = connection_tree->head; node; node = next) {
 -                              next = node->next;
 -                              c = node->data;
 -
 -                              c->outgoing = NULL;
 -
 -                              if(c->status.connecting) {
 -                                      terminate_connection(c, false);
 -                                      connection_del(c);
 -                              }
 -                      }
 -
 -                      /* Wipe list of outgoing connections */
 -
 -                      for(list_node_t *node = outgoing_list->head; node; node = node->next) {
 -                              outgoing_t *outgoing = node->data;
 -
 -                              if(outgoing->event)
 -                                      event_del(outgoing->event);
 -                      }
 -
 -                      list_delete_list(outgoing_list);
 -
 -                      /* 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);
 -                      }
 +      /* Try to make outgoing connections */
 +      
 +      try_outgoing_connections();
  
 -                      last_config_check = now;
 +      return 0;
 +}
  
 -                      /* If StrictSubnet is set, expire deleted Subnets and read new ones in */
 +void retry(void) {
 +      connection_t *c;
 +      splay_node_t *node;
  
 -                      if(strictsubnets) {
 -                              subnet_t *subnet;
 +      for(node = connection_tree->head; node; node = node->next) {
 +              c = node->data;
 +              
 +              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);
 +              }
 +      }
 +}
  
 -                              for(node = subnet_tree->head; node; node = node->next) {
 -                                      subnet = node->data;
 -                                      subnet->expires = 1;
 -                              }
 +/*
 +  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;
  
 -                              load_all_subnets();
 -
 -                              for(node = subnet_tree->head; node; node = next) {
 -                                      next = node->next;
 -                                      subnet = node->data;
 -                                      if(subnet->expires == 1) {
 -                                              send_del_subnet(broadcast, subnet);
 -                                              if(subnet->owner->status.reachable)
 -                                                      subnet_update(subnet->owner, subnet, false);
 -                                              subnet_del(subnet->owner, subnet);
 -                                      } else if(subnet->expires == -1) {
 -                                              subnet->expires = 0;
 -                                      } else {
 -                                              send_add_subnet(broadcast, subnet);
 -                                              if(subnet->owner->status.reachable)
 -                                                      subnet_update(subnet->owner, subnet, true);
 -                                      }
 -                              }
 -                      }
 +      timeout_set(&timeout_event, timeout_handler, &timeout_event);
 +      event_add(&timeout_event, &(struct timeval){pingtimeout, 0});
  
 -                      /* Try to make outgoing connections */
 -                      
 -                      try_outgoing_connections();
 -              }
 -              
 -              /* Dump graph if wanted every 60 seconds*/
 +#ifdef SIGHUP
 +      signal_set(&sighup_event, SIGHUP, sighup_handler, NULL);
 +      signal_add(&sighup_event, NULL);
 +#endif
 +#ifdef SIGTERM
 +      signal_set(&sigterm_event, SIGTERM, sigterm_handler, NULL);
 +      signal_add(&sigterm_event, NULL);
 +#endif
 +#ifdef SIGQUIT
 +      signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL);
 +      signal_add(&sigquit_event, NULL);
 +#endif
  
 -              if(last_graph_dump + 60 < now) {
 -                      dump_graph();
 -                      last_graph_dump = now;
 -              }
 +      if(event_loop(0) < 0) {
 +              logger(LOG_ERR, "Error while waiting for input: %s", strerror(errno));
 +              return 1;
        }
  
 +      signal_del(&sighup_event);
 +      signal_del(&sigterm_event);
 +      signal_del(&sigquit_event);
 +      event_del(&timeout_event);
 +
        return 0;
  }
diff --cc src/net.h
index cd97e301e3e8f85c30d21c0df5f2e69a3de960cb,eae979cd1b72c59bf2d1a5b74a9792fb480842cd..f53c27a411896d5cc58ffcb30fc76bf72a350af5
+++ b/src/net.h
@@@ -111,9 -109,14 +111,11 @@@ 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;
+ extern int contradicting_add_edge;
+ extern int contradicting_del_edge;
  
  /* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */
  #include "connection.h"
index 46d4e1a0df5314f22d767f038d9e39cb02e3f126,44ab55d42c8a550f1fddad9a36c88aec0c813377..b444bc9310277605e4bec46108f25bd578eeba0f
@@@ -355,8 -365,10 +356,10 @@@ static void send_udppacket(node_t *n, v
        int nextpkt = 0;
        vpn_packet_t *outpkt;
        int origlen;
 -      int outlen, outpad;
 +      size_t outlen;
+ #if defined(SOL_IP) && defined(IP_TOS)
        static int priority = 0;
+ #endif
        int origpriority;
        int sock;
  
diff --cc src/net_setup.c
index 198da3df93419e7760d58d98a11c8dca14b17923,f4e56378889c09c1d008cf51e05cb05fdb43b48c..9c188957afa449c5fca8849f69d0884893cae642
@@@ -71,32 -107,59 +71,32 @@@ bool read_rsa_public_key(connection_t *
                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);
  
 +      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;
  
 -      if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) {
 -              if(!get_config_string(lookup_config(config_tree, "PublicKey"), &pubkey)) {
 +      /* First, check for simple PrivateKey statement */
 +
 +      if(get_config_string(lookup_config(config_tree, "PrivateKey"), &d)) {
-               if(!get_config_string(lookup_config(myself->connection->config_tree, "PublicKey"), &n)) {
++              if(!get_config_string(lookup_config(config_tree, "PublicKey"), &n)) {
                        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;
        }
  
@@@ -386,36 -423,65 +376,36 @@@ bool setup_myself(void) 
  
        /* Generate packet encryption key */
  
-       if(!get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher))
 -      if(get_config_string
 -         (lookup_config(config_tree, "Cipher"), &cipher)) {
 -              if(!strcasecmp(cipher, "none")) {
 -                      myself->incipher = NULL;
 -              } else {
 -                      myself->incipher = EVP_get_cipherbyname(cipher);
++      if(!get_config_string(lookup_config(config_tree, "Cipher"), &cipher))
 +              cipher = xstrdup("blowfish");
  
 -                      if(!myself->incipher) {
 -                              logger(LOG_ERR, "Unrecognized cipher type!");
 -                              return false;
 -                      }
 -              }
 -      } else
 -              myself->incipher = EVP_bf_cbc();
 -
 -      if(myself->incipher)
 -              myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len;
 -      else
 -              myself->inkeylength = 1;
 -
 -      myself->connection->outcipher = EVP_bf_ofb();
 +      if(!cipher_open_by_name(&myself->incipher, cipher)) {
 +              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(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("sha1");
  
 -                      if(!myself->indigest) {
 -                              logger(LOG_ERR, "Unrecognized digest type!");
 -                              return false;
 -                      }
 -              }
 -      } else
 -              myself->indigest = EVP_sha1();
 -
 -      myself->connection->outdigest = EVP_sha1();
 -
 -      if(get_config_int(lookup_config(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);
++      get_config_int(lookup_config(config_tree, "MACLength"), &maclength);
 +
 +      if(maclength < 0) {
 +              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!");
 +              return false;
 +      }
  
        /* Compression */
  
index 4fe65161d5b7595e097772320229128a9880100a,762c0a224d0561976079c803fcd85a8fcc3f9cd6..44d7f77159c5d586ceb8fdb62438e5f6c5593538
@@@ -69,12 -70,12 +69,12 @@@ static void configure_tcp(connection_t 
  
  #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, (void *)&option, sizeof(option));
++      setsockopt(c->socket, SOL_TCP, TCP_NODELAY, (void *)&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, (void *)&option, sizeof(option));
++      setsockopt(c->socket, SOL_IP, IP_TOS, (void *)&option, sizeof option);
  #endif
  }
  
@@@ -180,7 -181,7 +180,7 @@@ int setup_listen_socket(const sockaddr_
        /* Optimize TCP settings */
  
        option = 1;
-       setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof option);
 -      setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option));
++      setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&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, (void *)&ifr, sizeof(ifr))) {
++              if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof ifr)) {
                        closesocket(nfd);
                        logger(LOG_ERR, "Can't bind to interface %s: %s", iface,
                                   strerror(sockerrno));
@@@ -258,7 -259,7 +258,7 @@@ int setup_vpn_in_socket(const sockaddr_
  #endif
  
        option = 1;
-       setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof option);
 -      setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option));
++      setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option);
  
  #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
        if(sa->sa.sa_family == AF_INET6)
diff --cc src/process.c
index 09fd63e1071a0da957a44d9eff04acb1f16b72b1,f2fff1dc6d0446c0ab36c66921b74e26995dcc99..77454f755d05dc46481ee8cf7ca735d407302e90
@@@ -37,11 -37,18 +37,13 @@@ bool do_detach = true
  bool sigalrm = false;
  
  extern char *identname;
 -extern char *pidfilename;
  extern char **g_argv;
  extern bool use_logfile;
 -extern volatile bool running;
  
+ #ifndef HAVE_MINGW
  sigset_t emptysigset;
+ #endif
  
 -static int saved_debug_level = -1;
 -
  static void memory_full(int size) {
        logger(LOG_ERR, "Memory exhausted (couldn't allocate %d bytes), exitting.", size);
        exit(1);
diff --cc src/process.h
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc src/tincd.c
index 21623647fb1eb0be7876a74c49fa16d19263494b,3dab9a01157b5751c14a65f24fc3d82ae94ea94f..c4750da20c0c8b6991285a4ceeb25cea4778dd29
@@@ -119,26 -129,33 +122,31 @@@ static void usage(bool status) 
                                program_name);
        else {
                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"
 -                              "  -o [HOST.]KEY=VALUE        Set global/host configuration value.\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"
 +                              "      --controlcookie=FILENAME  Write control socket cookie to FILENAME.\n"
 +                              "      --bypass-security         Disables meta protocol security, for debugging.\n"
++                              "  -o [HOST.]KEY=VALUE           Set global/host configuration value.\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");
        }
  }
  
  static bool parse_options(int argc, char **argv) {
+       config_t *cfg;
        int r;
        int option_index = 0;
+       int lineno = 0;
  
-       while((r = getopt_long(argc, argv, "c:DLd::n:RU:", long_options, &option_index)) != EOF) {
+       cmdline_conf = list_alloc((list_action_t)free_config);
 -      while((r = getopt_long(argc, argv, "c:DLd::k::n:o:K::RU:", long_options, &option_index)) != EOF) {
++      while((r = getopt_long(argc, argv, "c:DLd::n:o:RU:", long_options, &option_index)) != EOF) {
                switch (r) {
                        case 0:                         /* long option */
                                break;
                                        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);
+                               /* netname "." is special: a "top-level name" */
+                               netname = strcmp(optarg, ".") != 0 ?
+                                               xstrdup(optarg) : NULL;
+                               break;
+                       case 'o':                               /* option */
+                               cfg = parse_config_line(optarg, NULL, ++lineno);
+                               if (!cfg)
+                                       return false;
+                               list_insert_tail(cmdline_conf, cfg);
                                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;
Simple merge