Code

Merge branch 'collectd-4.6'
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sat, 11 Apr 2009 07:37:30 +0000 (09:37 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sat, 11 Apr 2009 07:37:30 +0000 (09:37 +0200)
1  2 
configure.in
src/exec.c
src/network.c

diff --combined configure.in
index 3540a3e2b18c1305a8b5dd395bd81ef3487377f4,2344cdb57e65b8bb09970a873f754a096bfb2ae5..f0c43121990012b19cae6be48cd5bac488b2b650
@@@ -1187,166 -1187,6 +1187,166 @@@ AC_DEFINE_UNQUOTED(COLLECT_LIBESMTP, [$
  AM_CONDITIONAL(BUILD_WITH_LIBESMTP, test "x$with_libesmtp" = "xyes")
  # }}}
  
 +# --with-libganglia {{{
 +AC_ARG_WITH(libganglia, [AS_HELP_STRING([--with-libganglia@<:@=PREFIX@:>@], [Path to libganglia.])],
 +[
 + if test -f "$withval" && test -x "$withval"
 + then
 +       with_libganglia_config="$withval"
 +       with_libganglia="yes"
 + else if test -f "$withval/bin/ganglia-config" && test -x "$withval/bin/ganglia-config"
 + then
 +       with_libganglia_config="$withval/bin/ganglia-config"
 +       with_libganglia="yes"
 + else if test -d "$withval"
 + then
 +       GANGLIA_CPPFLAGS="-I$withval/include"
 +       GANGLIA_LDFLAGS="-L$withval/lib"
 +       with_libganglia="yes"
 + else
 +       with_libganglia_config="ganglia-config"
 +       with_libganglia="$withval"
 + fi; fi; fi
 +],
 +[
 + with_libganglia_config="ganglia-config"
 + with_libganglia="yes"
 +])
 +
 +if test "x$with_libganglia" = "xyes" && test "x$with_libganglia_config" != "x"
 +then
 +      if test "x$GANGLIA_CPPFLAGS" = "x"
 +      then
 +              GANGLIA_CPPFLAGS=`"$with_libganglia_config" --cflags 2>/dev/null`
 +      fi
 +
 +      if test "x$GANGLIA_LDFLAGS" = "x"
 +      then
 +              GANGLIA_LDFLAGS=`"$with_libganglia_config" --ldflags 2>/dev/null`
 +      fi
 +
 +      if test "x$GANGLIA_LIBS" = "x"
 +      then
 +              GANGLIA_LIBS=`"$with_libganglia_config" --libs 2>/dev/null`
 +      fi
 +fi
 +
 +SAVE_CPPFLAGS="$CPPFLAGS"
 +SAVE_LDFLAGS="$LDFLAGS"
 +CPPFLAGS="$CPPFLAGS $GANGLIA_CPPFLAGS"
 +LDFLAGS="$LDFLAGS $GANGLIA_LDFLAGS"
 +
 +if test "x$with_libganglia" = "xyes"
 +then
 +      AC_CHECK_HEADERS(gm_protocol.h,
 +      [
 +              AC_DEFINE(HAVE_GM_PROTOCOL_H, 1,
 +                        [Define to 1 if you have the <gm_protocol.h> header file.])
 +      ], [with_libganglia="no (gm_protocol.h not found)"])
 +fi
 +
 +if test "x$with_libganglia" = "xyes"
 +then
 +      AC_CHECK_LIB(ganglia, xdr_Ganglia_value_msg,
 +      [
 +              AC_DEFINE(HAVE_LIBGANGLIA, 1,
 +                        [Define to 1 if you have the ganglia library (-lganglia).])
 +      ], [with_libganglia="no (symbol xdr_Ganglia_value_msg not found)"])
 +fi
 +
 +CPPFLAGS="$SAVE_CPPFLAGS"
 +LDFLAGS="$SAVE_LDFLAGS"
 +
 +AC_SUBST(GANGLIA_CPPFLAGS)
 +AC_SUBST(GANGLIA_LDFLAGS)
 +AC_SUBST(GANGLIA_LIBS)
 +AM_CONDITIONAL(BUILD_WITH_LIBGANGLIA, test "x$with_libganglia" = "xyes")
 +# }}}
 +
 +# --with-libgcrypt {{{
 +GCRYPT_CPPFLAGS="$GCRYPT_CPPFLAGS"
 +GCRYPT_LDFLAGS="$GCRYPT_LDFLAGS"
 +GCRYPT_LIBS="$GCRYPT_LIBS"
 +AC_ARG_WITH(libgcrypt, [AS_HELP_STRING([--with-libgcrypt@<:@=PREFIX@:>@], [Path to libgcrypt.])],
 +[
 + if test -f "$withval" && test -x "$withval"
 + then
 +       with_libgcrypt_config="$withval"
 +       with_libgcrypt="yes"
 + else if test -f "$withval/bin/gcrypt-config" && test -x "$withval/bin/gcrypt-config"
 + then
 +       with_libgcrypt_config="$withval/bin/gcrypt-config"
 +       with_libgcrypt="yes"
 + else if test -d "$withval"
 + then
 +       GCRYPT_CPPFLAGS="$GCRYPT_CPPFLAGS -I$withval/include"
 +       GCRYPT_LDFLAGS="$GCRYPT_LDFLAGS -L$withval/lib"
 +       with_libgcrypt="yes"
 + else
 +       with_libgcrypt_config="gcrypt-config"
 +       with_libgcrypt="$withval"
 + fi; fi; fi
 +],
 +[
 + with_libgcrypt_config="libgcrypt-config"
 + with_libgcrypt="yes"
 +])
 +
 +if test "x$with_libgcrypt" = "xyes" && test "x$with_libgcrypt_config" != "x"
 +then
 +      if test "x$GCRYPT_CPPFLAGS" = "x"
 +      then
 +              GCRYPT_CPPFLAGS=`"$with_libgcrypt_config" --cflags 2>/dev/null`
 +      fi
 +
 +      if test "x$GCRYPT_LDFLAGS" = "x"
 +      then
 +              gcrypt_exec_prefix=`"$with_libgcrypt_config" --exec-prefix 2>/dev/null`
 +              GCRYPT_LDFLAGS="-L$gcrypt_exec_prefix/lib"
 +      fi
 +
 +      if test "x$GCRYPT_LIBS" = "x"
 +      then
 +              GCRYPT_LIBS=`"$with_libgcrypt_config" --libs 2>/dev/null`
 +      fi
 +fi
 +
 +SAVE_CPPFLAGS="$CPPFLAGS"
 +SAVE_LDFLAGS="$LDFLAGS"
 +CPPFLAGS="$CPPFLAGS $GCRYPT_CPPFLAGS"
 +LDFLAGS="$LDFLAGS $GCRYPT_LDFLAGS"
 +
 +if test "x$with_libgcrypt" = "xyes"
 +then
 +      if test "x$GCRYPT_CPPFLAGS" != "x"
 +      then
 +              AC_MSG_NOTICE([gcrypt CPPFLAGS: $GCRYPT_CPPFLAGS])
 +      fi
 +      AC_CHECK_HEADERS(gcrypt.h,
 +              [with_libgcrypt="yes"],
 +              [with_libgcrypt="no (gcrypt.h not found)"])
 +fi
 +
 +if test "x$with_libgcrypt" = "xyes"
 +then
 +      if test "x$GCRYPT_LDFLAGS" != "x"
 +      then
 +              AC_MSG_NOTICE([gcrypt LDFLAGS: $GCRYPT_LDFLAGS])
 +      fi
 +      AC_CHECK_LIB(gcrypt, gcry_md_hash_buffer,
 +              [with_libgcrypt="yes"],
 +              [with_libgcrypt="no (symbol gcry_md_hash_buffer not found)"])
 +fi
 +
 +CPPFLAGS="$SAVE_CPPFLAGS"
 +LDFLAGS="$SAVE_LDFLAGS"
 +
 +AC_SUBST(GCRYPT_CPPFLAGS)
 +AC_SUBST(GCRYPT_LDFLAGS)
 +AC_SUBST(GCRYPT_LIBS)
 +AM_CONDITIONAL(BUILD_WITH_LIBGCRYPT, test "x$with_libgcrypt" = "xyes")
 +# }}}
 +
  # --with-libiptc {{{
  with_own_libiptc="no"
  AC_ARG_WITH(libiptc, [AS_HELP_STRING([--with-libiptc@<:@=PREFIX@:>@], [Path to libiptc.])],
  fi
  # }}}
  
 +# --with-java {{{
 +with_java_home="$JAVA_HOME"
 +with_java_vmtype="client"
 +with_java_cflags=""
 +with_java_libs=""
 +AC_ARG_WITH(java, [AS_HELP_STRING([--with-java@<:@=PREFIX@:>@], [Path to Java home.])],
 +[
 +      if test "x$withval" = "xno"
 +      then
 +              with_java="no"
 +      else if test "x$withval" = "xyes"
 +      then
 +              with_java="yes"
 +      else
 +              with_java_home="$withval"
 +              with_java="yes"
 +      fi; fi
 +],
 +[with_java="yes"])
 +if test "x$with_java" = "xyes"
 +then
 +      if test -d "$with_java_home"
 +      then
 +              if test -d "$with_java_home/include"
 +              then
 +                      JAVA_CPPFLAGS="$JAVA_CPPFLAGS -I$with_java_home/include"
 +              else
 +                      JAVA_CPPFLAGS="$JAVA_CPPFLAGS -I$with_java_home"
 +              fi
 +              
 +              if test -d "$with_java_home/lib"
 +              then
 +                      JAVA_LDFLAGS="$JAVA_LDFLAGS -L$with_java_home/lib"
 +              else
 +                      JAVA_LDFLAGS="$JAVA_LDFLAGS -L$with_java_home"
 +              fi
 +      else if test "x$with_java_home" != "x"
 +      then
 +              AC_MSG_WARN([JAVA_HOME: No such directory: $with_java_home])
 +      fi; fi
 +fi
 +
 +if test "x$JAVA_CPPFLAGS" != "x"
 +then
 +      AC_MSG_NOTICE([Building with JAVA_CPPFLAGS set to: $JAVA_CPPFLAGS])
 +fi
 +if test "x$JAVA_CFLAGS" != "x"
 +then
 +      AC_MSG_NOTICE([Building with JAVA_CFLAGS set to: $JAVA_CFLAGS])
 +fi
 +if test "x$JAVA_LDFLAGS" != "x"
 +then
 +      AC_MSG_NOTICE([Building with JAVA_LDFLAGS set to: $JAVA_LDFLAGS])
 +fi
 +
 +SAVE_CPPFLAGS="$CPPFLAGS"
 +SAVE_CFLAGS="$CFLAGS"
 +SAVE_LDFLAGS="$LDFLAGS"
 +CPPFLAGS="$CPPFLAGS $JAVA_CPPFLAGS"
 +CFLAGS="$CFLAGS $JAVA_CFLAGS"
 +LDFLAGS="$LDFLAGS $JAVA_LDFLAGS"
 +
 +if test "x$with_java" = "xyes"
 +then
 +      AC_CHECK_HEADERS(jni.h, [], [with_java="no (jni.h not found)"])
 +fi
 +if test "x$with_java" = "xyes"
 +then
 +      AC_CHECK_LIB(jvm, JNI_CreateJavaVM,
 +      [with_java="yes"],
 +      [with_java="no (libjvm not found)"],
 +      [$JAVA_LIBS])
 +fi
 +if test "x$with_java" = "xyes"
 +then
 +      JAVA_LIBS="$JAVA_LIBS -ljvm"
 +      AC_MSG_NOTICE([Building with JAVA_LIBS set to: $JAVA_LIBS])
 +fi
 +
 +CPPFLAGS="$SAVE_CPPFLAGS"
 +CFLAGS="$SAVE_CFLAGS"
 +LDFLAGS="$SAVE_LDFLAGS"
 +
 +AC_SUBST(JAVA_CPPFLAGS)
 +AC_SUBST(JAVA_CFLAGS)
 +AC_SUBST(JAVA_LDFLAGS)
 +AC_SUBST(JAVA_LIBS)
 +AM_CONDITIONAL(BUILD_WITH_JAVA, test "x$with_java" = "xyes")
 +# }}}
 +
 +# --with-libmemcached {{{
 +with_libmemcached_cppflags=""
 +with_libmemcached_ldflags=""
 +AC_ARG_WITH(libmemcached, [AS_HELP_STRING([--with-libmemcached@<:@=PREFIX@:>@], [Path to libmemcached.])],
 +[
 +      if test "x$withval" != "xno" && test "x$withval" != "xyes"
 +      then
 +              with_libmemcached_cppflags="-I$withval/include"
 +              with_libmemcached_ldflags="-L$withval/lib"
 +              with_libmemcached="yes"
 +      else
 +              with_libmemcached="$withval"
 +      fi
 +],
 +[
 +      with_libmemcached="yes"
 +])
 +if test "x$with_libmemcached" = "xyes"
 +then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libmemcached_cppflags"
 +
 +      AC_CHECK_HEADERS(libmemcached/memcached.h, [with_libmemcached="yes"], [with_libmemcached="no (libmemcached/memcached.h not found)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +fi
 +if test "x$with_libmemcached" = "xyes"
 +then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      SAVE_LDFLAGS="$LDFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libmemcached_cppflags"
 +      LDFLAGS="$LDFLAGS $with_libmemcached_ldflags"
 +
 +      AC_CHECK_LIB(memcached, memcached_create, [with_libmemcached="yes"], [with_libmemcached="no (Symbol 'memcached_create' not found)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +      LDFLAGS="$SAVE_LDFLAGS"
 +fi
 +if test "x$with_libmemcached" = "xyes"
 +then
 +      BUILD_WITH_LIBMEMCACHED_CPPFLAGS="$with_libmemcached_cppflags"
 +      BUILD_WITH_LIBMEMCACHED_LDFLAGS="$with_libmemcached_ldflags"
 +      BUILD_WITH_LIBMEMCACHED_LIBS="-lmemcached"
 +      AC_SUBST(BUILD_WITH_LIBMEMCACHED_CPPFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBMEMCACHED_LDFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBMEMCACHED_LIBS)
 +      AC_DEFINE(HAVE_LIBMEMCACHED, 1, [Define if libmemcached is present and usable.])
 +fi
 +AM_CONDITIONAL(BUILD_WITH_LIBMEMCACHED, test "x$with_libmemcached" = "xyes")
 +# }}}
 +
  # --with-libmysql {{{
  with_mysql_config="mysql_config"
  with_mysql_cflags=""
  # }}}
  
  # --with-liboping {{{
 -with_own_liboping="no"
 -liboping_LDFLAGS="$LDFLAGS"
 -liboping_CPPFLAGS="$CPPFLAGS"
  AC_ARG_WITH(liboping, [AS_HELP_STRING([--with-liboping@<:@=PREFIX@:>@], [Path to liboping.])],
  [
 -      if test "x$withval" != "xno" && test "x$withval" != "xyes"
 + if test "x$withval" = "xyes"
 + then
 +       with_liboping="yes"
 + else if test "x$withval" = "xno"
 + then
 +       with_liboping="no"
 + else
 +       with_liboping="yes"
 +       LIBOPING_CPPFLAGS="$LIBOPING_CPPFLAGS -I$withval/include"
 +       LIBOPING_LDFLAGS="$LIBOPING_LDFLAGS -L$withval/lib"
 + fi; fi
 +],
 +[with_liboping="yes"])
 +
 +SAVE_CPPFLAGS="$CPPFLAGS"
 +SAVE_LDFLAGS="$LDFLAGS"
 +
 +CPPFLAGS="$CPPFLAGS $LIBOPING_CPPFLAGS"
 +LDFLAGS="$LDFLAGS $LIBOPING_LDFLAGS"
 +
 +if test "x$with_liboping" = "xyes"
 +then
 +      if test "x$LIBOPING_CPPFLAGS" != "x"
        then
 -              if test -d "$withval/lib"
 -              then
 -                      liboping_LDFLAGS="$LDFLAGS -L$withval/lib"
 -              fi
 -              if test -d "$withval/include"
 -              then
 -                      liboping_CPPFLAGS="$CPPFLAGS -I$withval/include"
 -              fi
 +              AC_MSG_NOTICE([liboping CPPFLAGS: $LIBOPING_CPPFLAGS])
        fi
 -      if test "x$withval" = "xno"
 -      then
 -              with_liboping="no"
 -              with_own_liboping="no"
 -      else if test "x$withval" = "xyes"
 +      AC_CHECK_HEADERS(oping.h,
 +      [with_liboping="yes"],
 +      [with_liboping="no ('oping.h' not found)"])
 +fi
 +if test "x$with_liboping" = "xyes"
 +then
 +      if test "x$LIBOPING_LDFLAGS" != "x"
        then
 -              with_liboping="yes"
 -      fi; fi
 -],
 -[
 -      with_liboping="yes"
 -])
 +              AC_MSG_NOTICE([liboping LDFLAGS: $LIBOPING_LDFLAGS])
 +      fi
 +      AC_CHECK_LIB(oping, ping_construct,
 +      [with_liboping="yes"],
 +      [with_liboping="no (symbol 'ping_construct' not found)"])
 +fi
 +
 +CPPFLAGS="$SAVE_CPPFLAGS"
 +LDFLAGS="$SAVE_LDFLAGS"
  
  if test "x$with_liboping" = "xyes"
  then
 -      save_LDFLAGS="$LDFLAGS"
 -      save_CPPFLAGS="$CPPFLAGS"
 -      LDFLAGS="$liboping_LDFLAGS"
 -      CPPFLAGS="$liboping_CPPFLAGS"
 -      AC_CHECK_LIB(oping, ping_construct,
 -      [
 -              with_liboping="yes"
 -              with_own_liboping="no"
 -      ],
 -      [
 -              with_liboping="yes"
 -              with_own_liboping="yes"
 -              LDFLAGS="$save_LDFLAGS"
 -              CPPFLAGS="$save_CPPFLAGS"
 -      ])
 +      BUILD_WITH_LIBOPING_CPPFLAGS="$LIBOPING_CPPFLAGS"
 +      BUILD_WITH_LIBOPING_LDFLAGS="$LIBOPING_LDFLAGS"
 +      AC_SUBST(BUILD_WITH_LIBOPING_CPPFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBOPING_LDFLAGS)
  fi
  AM_CONDITIONAL(BUILD_WITH_LIBOPING, test "x$with_liboping" = "xyes")
 -AM_CONDITIONAL(BUILD_WITH_OWN_LIBOPING, test "x$with_own_liboping" = "xyes")
  # }}}
  
  # --with-oracle {{{
@@@ -2108,8 -1802,9 +2108,9 @@@ if test "x$with_libperl" = "xyes" 
  then
    SAVE_CFLAGS=$CFLAGS
    SAVE_LDFLAGS=$LDFLAGS
-   PERL_CFLAGS=`$perl_interpreter -MExtUtils::Embed -e ccopts`
-   PERL_LDFLAGS=`$perl_interpreter -MExtUtils::Embed -e ldopts`
+ dnl ARCHFLAGS="" -> disable multi -arch on OSX (see Config_heavy.pl:fetch_string)
+   PERL_CFLAGS=`ARCHFLAGS="" $perl_interpreter -MExtUtils::Embed -e ccopts`
+   PERL_LDFLAGS=`ARCHFLAGS="" $perl_interpreter -MExtUtils::Embed -e ldopts`
    CFLAGS="$CFLAGS $PERL_CFLAGS"
    LDFLAGS="$LDFLAGS $PERL_LDFLAGS"
  
                [with_libpq="yes"],
                [with_libpq="no (symbol 'PQconnectdb' not found)"])
  
 +      AC_CHECK_LIB(pq, PQserverVersion,
 +              [with_libpq="yes"],
 +              [with_libpq="no (symbol 'PQserverVersion' not found)"])
 +
        LDFLAGS="$SAVE_LDFLAGS"
  fi
  if test "x$with_libpq" = "xyes"
@@@ -3167,15 -2858,12 +3168,15 @@@ plugin_multimeter="no
  plugin_nfs="no"
  plugin_perl="no"
  plugin_processes="no"
 +plugin_protocols="no"
  plugin_serial="no"
  plugin_swap="no"
  plugin_tape="no"
  plugin_tcpconns="no"
 +plugin_ted="no"
  plugin_thermal="no"
  plugin_users="no"
 +plugin_uptime="no"
  plugin_vmem="no"
  plugin_vserver="no"
  plugin_wireless="no"
        plugin_memory="yes"
        plugin_nfs="yes"
        plugin_processes="yes"
 +      plugin_protocols="yes"
        plugin_serial="yes"
        plugin_swap="yes"
        plugin_tcpconns="yes"
        plugin_thermal="yes"
 +      plugin_uptime="yes"
        plugin_vmem="yes"
        plugin_vserver="yes"
        plugin_wireless="yes"
  fi
  
  # Solaris
 +if test "x$with_kstat" = "xyes"
 +then
 +      plugin_uptime="yes"
 +fi
 +
  if test "x$with_devinfo$with_kstat" = "xyesyes"
  then
        plugin_cpu="yes"
@@@ -3273,7 -2954,6 +3274,7 @@@ if test "x$have_sysctl" = "xyes
  then
        plugin_cpu="yes"
        plugin_swap="yes"
 +      plugin_uptime="yes"
  fi
  if test "x$have_sysctlbyname" = "xyes"
  then
  if test "x$have_termios_h" = "xyes"
  then
        plugin_multimeter="yes"
 +      plugin_ted="yes"
  fi
  
  if test "x$have_thread_info" = "xyes"
@@@ -3378,14 -3057,12 +3379,14 @@@ AC_PLUGIN([email],       [yes]
  AC_PLUGIN([entropy],     [$plugin_entropy],    [Entropy statistics])
  AC_PLUGIN([exec],        [yes],                [Execution of external programs])
  AC_PLUGIN([filecount],   [yes],                [Count files in directories])
 +AC_PLUGIN([gmond],       [$with_libganglia],   [Ganglia plugin])
  AC_PLUGIN([hddtemp],     [yes],                [Query hddtempd])
  AC_PLUGIN([interface],   [$plugin_interface],  [Interface traffic statistics])
  AC_PLUGIN([ipmi],        [$plugin_ipmi],       [IPMI sensor statistics])
  AC_PLUGIN([iptables],    [$with_libiptc],      [IPTables rule counters])
  AC_PLUGIN([ipvs],        [$plugin_ipvs],       [IPVS connection statistics])
  AC_PLUGIN([irq],         [$plugin_irq],        [IRQ statistics])
 +AC_PLUGIN([java],        [$with_java],         [Embed the Java Virtual Machine])
  AC_PLUGIN([libvirt],     [$plugin_libvirt],    [Virtual machine statistics])
  AC_PLUGIN([load],        [$plugin_load],       [System load])
  AC_PLUGIN([logfile],     [yes],                [File logging plugin])
@@@ -3393,7 -3070,6 +3394,7 @@@ AC_PLUGIN([match_regex], [yes]
  AC_PLUGIN([match_timediff], [yes],             [The timediff match])
  AC_PLUGIN([match_value], [yes],                [The value match])
  AC_PLUGIN([mbmon],       [yes],                [Query mbmond])
 +AC_PLUGIN([memcachec],   [$with_libmemcached], [memcachec statistics])
  AC_PLUGIN([memcached],   [yes],                [memcached statistics])
  AC_PLUGIN([memory],      [$plugin_memory],     [Memory usage])
  AC_PLUGIN([multimeter],  [$plugin_multimeter], [Read multimeter values])
@@@ -3414,7 -3090,6 +3415,7 @@@ AC_PLUGIN([ping],        [$with_libopin
  AC_PLUGIN([postgresql],  [$with_libpq],        [PostgreSQL database statistics])
  AC_PLUGIN([powerdns],    [yes],                [PowerDNS statistics])
  AC_PLUGIN([processes],   [$plugin_processes],  [Process statistics])
 +AC_PLUGIN([protocols],   [$plugin_protocols],  [Protocol (IP, TCP, ...) statistics])
  AC_PLUGIN([rrdcached],   [$librrd_rrdc_update], [RRDTool output plugin])
  AC_PLUGIN([rrdtool],     [$with_librrd],       [RRDTool output plugin])
  AC_PLUGIN([sensors],     [$with_libsensors],   [lm_sensors statistics])
@@@ -3422,7 -3097,6 +3423,7 @@@ AC_PLUGIN([serial],      [$plugin_seria
  AC_PLUGIN([snmp],        [$with_libnetsnmp],   [SNMP querying plugin])
  AC_PLUGIN([swap],        [$plugin_swap],       [Swap usage statistics])
  AC_PLUGIN([syslog],      [$have_syslog],       [Syslog logging plugin])
 +AC_PLUGIN([table],       [yes],                [Parsing of tabular data])
  AC_PLUGIN([tail],        [yes],                [Parsing of logfiles])
  AC_PLUGIN([tape],        [$plugin_tape],       [Tape drive statistics])
  AC_PLUGIN([target_notification], [yes],        [The notification target])
@@@ -3430,10 -3104,8 +3431,10 @@@ AC_PLUGIN([target_replace], [yes]
  AC_PLUGIN([target_set],  [yes],                [The set target])
  AC_PLUGIN([tcpconns],    [$plugin_tcpconns],   [TCP connection statistics])
  AC_PLUGIN([teamspeak2],  [yes],                [TeamSpeak2 server statistics])
 +AC_PLUGIN([ted],         [$plugin_ted],        [Read The Energy Detective values])
  AC_PLUGIN([thermal],     [$plugin_thermal],    [Linux ACPI thermal zone statistics])
  AC_PLUGIN([unixsock],    [yes],                [Unixsock communication plugin])
 +AC_PLUGIN([uptime],      [$plugin_uptime],     [Uptime statistics])
  AC_PLUGIN([users],       [$plugin_users],      [User statistics])
  AC_PLUGIN([uuid],        [yes],                [UUID as hostname plugin])
  AC_PLUGIN([vmem],        [$plugin_vmem],       [Virtual memory statistics])
@@@ -3441,86 -3113,6 +3442,86 @@@ AC_PLUGIN([vserver],     [$plugin_vserv
  AC_PLUGIN([wireless],    [$plugin_wireless],   [Wireless statistics])
  AC_PLUGIN([xmms],        [$with_libxmms],      [XMMS statistics])
  
 +dnl Default configuration file
 +# Load either syslog or logfile
 +LOAD_PLUGIN_SYSLOG=""
 +LOAD_PLUGIN_LOGFILE=""
 +
 +AC_MSG_CHECKING([which default log plugin to load])
 +default_log_plugin="none"
 +if test "x$enable_syslog" = "xyes"
 +then
 +      default_log_plugin="syslog"
 +else
 +      LOAD_PLUGIN_SYSLOG="##"
 +fi
 +
 +if test "x$enable_logfile" = "xyes"
 +then
 +      if test "x$default_log_plugin" = "xnone"
 +      then
 +              default_log_plugin="logfile"
 +      else
 +              LOAD_PLUGIN_LOGFILE="#"
 +      fi
 +else
 +      LOAD_PLUGIN_LOGFILE="##"
 +fi
 +AC_MSG_RESULT([$default_log_plugin])
 +
 +AC_SUBST(LOAD_PLUGIN_SYSLOG)
 +AC_SUBST(LOAD_PLUGIN_LOGFILE)
 +
 +DEFAULT_LOG_LEVEL="info"
 +if test "x$enable_debug" = "xyes"
 +then
 +      DEFAULT_LOG_LEVEL="debug"
 +fi
 +AC_SUBST(DEFAULT_LOG_LEVEL)
 +
 +# Load only one of rrdtool, network, csv in the default config.
 +LOAD_PLUGIN_RRDTOOL=""
 +LOAD_PLUGIN_NETWORK=""
 +LOAD_PLUGIN_CSV=""
 +
 +AC_MSG_CHECKING([which default write plugin to load])
 +default_write_plugin="none"
 +if test "x$enable_rrdtool" = "xyes"
 +then
 +      default_write_plugin="rrdtool"
 +else
 +      LOAD_PLUGIN_RRDTOOL="##"
 +fi
 +
 +if test "x$enable_network" = "xyes"
 +then
 +      if test "x$default_write_plugin" = "xnone"
 +      then
 +              default_write_plugin="network"
 +      else
 +              LOAD_PLUGIN_NETWORK="#"
 +      fi
 +else
 +      LOAD_PLUGIN_NETWORK="##"
 +fi
 +
 +if test "x$enable_csv" = "xyes"
 +then
 +      if test "x$default_write_plugin" = "xnone"
 +      then
 +              default_write_plugin="csv"
 +      else
 +              LOAD_PLUGIN_CSV="#"
 +      fi
 +else
 +      LOAD_PLUGIN_CSV="##"
 +fi
 +AC_MSG_RESULT([$default_write_plugin])
 +
 +AC_SUBST(LOAD_PLUGIN_RRDTOOL)
 +AC_SUBST(LOAD_PLUGIN_NETWORK)
 +AC_SUBST(LOAD_PLUGIN_CSV)
 +
  dnl ip_vs.h
  if test "x$ac_system" = "xLinux" \
        && test "x$have_net_ip_vs_h$have_ip_vs_h" = "xnono"
@@@ -3575,7 -3167,7 +3576,7 @@@ AC_SUBST(LCC_VERSION_STRING
  
  AC_CONFIG_FILES(src/libcollectdclient/lcc_features.h)
  
 -AC_OUTPUT(Makefile src/Makefile src/collectd.conf src/libiptc/Makefile src/libcollectdclient/Makefile src/libcollectdclient/libcollectdclient.pc src/liboconfig/Makefile src/liboping/Makefile bindings/Makefile)
 +AC_OUTPUT(Makefile src/Makefile src/collectd.conf src/libiptc/Makefile src/libcollectdclient/Makefile src/libcollectdclient/libcollectdclient.pc src/liboconfig/Makefile bindings/Makefile)
  
  if test "x$with_librrd" = "xyes" \
        && test "x$librrd_threadsafe" != "xyes"
@@@ -3583,6 -3175,12 +3584,6 @@@ the
        with_librrd="yes (warning: librrd is not thread-safe)"
  fi
  
 -if test "x$with_liboping" = "xyes" \
 -      && test "x$with_own_liboping" = "xyes"
 -then
 -      with_liboping="yes (shipped version)"
 -fi
 -
  if test "x$with_libiptc" = "xyes" -a "x$with_own_libiptc" = "xyes"
  then
        with_libiptc="yes (shipped version)"
@@@ -3610,7 -3208,6 +3611,7 @@@ Configuration
      libesmtp  . . . . . . $with_libesmtp
      libiokit  . . . . . . $with_libiokit
      libiptc . . . . . . . $with_libiptc
 +    libjvm  . . . . . . . $with_java
      libkstat  . . . . . . $with_kstat
      libkvm  . . . . . . . $with_libkvm
      libmysql  . . . . . . $with_libmysql
      entropy . . . . . . . $enable_entropy
      exec  . . . . . . . . $enable_exec
      filecount . . . . . . $enable_filecount
 +    gmond . . . . . . . . $enable_gmond
      hddtemp . . . . . . . $enable_hddtemp
      interface . . . . . . $enable_interface
      ipmi  . . . . . . . . $enable_ipmi
      iptables  . . . . . . $enable_iptables
      ipvs  . . . . . . . . $enable_ipvs
      irq . . . . . . . . . $enable_irq
 +    java  . . . . . . . . $enable_java
      libvirt . . . . . . . $enable_libvirt
      load  . . . . . . . . $enable_load
      logfile . . . . . . . $enable_logfile
      match_timediff  . . . $enable_match_timediff
      match_value . . . . . $enable_match_value
      mbmon . . . . . . . . $enable_mbmon
 +    memcachec . . . . . . $enable_memcachec
      memcached . . . . . . $enable_memcached
      memory  . . . . . . . $enable_memory
      multimeter  . . . . . $enable_multimeter
      postgresql  . . . . . $enable_postgresql
      powerdns  . . . . . . $enable_powerdns
      processes . . . . . . $enable_processes
 +    protocols . . . . . . $enable_protocols
      rrdcached . . . . . . $enable_rrdcached
      rrdtool . . . . . . . $enable_rrdtool
      sensors . . . . . . . $enable_sensors
      snmp  . . . . . . . . $enable_snmp
      swap  . . . . . . . . $enable_swap
      syslog  . . . . . . . $enable_syslog
 +    table . . . . . . . . $enable_table
      tail  . . . . . . . . $enable_tail
      tape  . . . . . . . . $enable_tape
      target_notification . $enable_target_notification
      target_set  . . . . . $enable_target_set
      tcpconns  . . . . . . $enable_tcpconns
      teamspeak2  . . . . . $enable_teamspeak2
 +    ted . . . . . . . . . $enable_ted
      thermal . . . . . . . $enable_thermal
      unixsock  . . . . . . $enable_unixsock
 +    uptime  . . . . . . . $enable_uptime
      users . . . . . . . . $enable_users
      uuid  . . . . . . . . $enable_uuid
      vmem  . . . . . . . . $enable_vmem
diff --combined src/exec.c
index cdcf6adebdba0f886aa2515cb92e7ac9b21a92d7,c2d42ee0bbcc19f4268ab568ea45971ba70b92df..82aeb29d43d701d08f82459c4995b415a57eb7d7
@@@ -585,7 -585,17 +585,17 @@@ static void *exec_read_one (void *arg) 
          if (errno == EAGAIN || errno == EINTR)  continue;
          break;
        }
-       else if (len == 0) break;  /* We've reached EOF */
+       else if (len == 0)
+       {
+       /* We've reached EOF */
+       NOTICE ("exec plugin: Program `%s' has closed STDERR.",
+           pl->exec);
+       close (fd_err);
+       FD_CLR (fd_err, &fdset);
+       highest_fd = fd;
+       fd_err = -1;
+       continue;
+       }
  
        pbuffer_err[len] = '\0';
  
      copy = fdset;
    }
  
+   DEBUG ("exec plugin: exec_read_one: Waiting for `%s' to exit.", pl->exec);
    if (waitpid (pl->pid, &status, 0) > 0)
      pl->status = status;
  
    pthread_mutex_unlock (&pl_lock);
  
    close (fd);
-   close (fd_err);
+   if (fd_err >= 0)
+     close (fd_err);
  
    pthread_exit ((void *) 0);
    return (NULL);
@@@ -761,8 -773,7 +773,8 @@@ static int exec_read (void) /* {{{ *
    return (0);
  } /* int exec_read }}} */
  
 -static int exec_notification (const notification_t *n)
 +static int exec_notification (const notification_t *n,
 +    user_data_t __attribute__((unused)) *user_data)
  {
    program_list_t *pl;
    program_list_and_notification_t *pln;
    } /* for (pl) */
  
    return (0);
 -} /* int exec_notification */
 +} /* }}} int exec_notification */
  
  static int exec_shutdown (void) /* {{{ */
  {
@@@ -835,8 -846,7 +847,8 @@@ void module_register (void
    plugin_register_complex_config ("exec", exec_config);
    plugin_register_init ("exec", exec_init);
    plugin_register_read ("exec", exec_read);
 -  plugin_register_notification ("exec", exec_notification);
 +  plugin_register_notification ("exec", exec_notification,
 +      /* user_data = */ NULL);
    plugin_register_shutdown ("exec", exec_shutdown);
  } /* void module_register */
  
diff --combined src/network.c
index bbe6b6fd7f58600be4f60982ba1605a58e6837ab,902f270e5336b09d3e59d611cafb2c07443ea0f7..51b9922d2f87fdd573c1ec0de05ef3d1c41c981e
@@@ -1,6 -1,6 +1,6 @@@
  /**
   * collectd - src/network.c
 - * Copyright (C) 2005-2008  Florian octo Forster
 + * Copyright (C) 2005-2009  Florian octo Forster
   *
   * 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
  # include <poll.h>
  #endif
  
 +#if HAVE_GCRYPT_H
 +# include <gcrypt.h>
 +#endif
 +
  /* 1500 - 40 - 8  =  Ethernet packet - IPv6 header - UDP header */
  /* #define BUFF_SIZE 1452 */
  
  # endif
  #endif /* !IP_ADD_MEMBERSHIP */
  
 +/* Buffer size to allocate. */
  #define BUFF_SIZE 1024
  
 +/*
 + * Maximum size required for encryption / signing:
 + * Type/length:       4
 + * Hash/orig length: 32
 + * Padding (up to):  16
 + * --------------------
 + *                   52
 + */
 +#define BUFF_SIG_SIZE 52
 +
  /*
   * Private data types
   */
@@@ -82,16 -67,6 +82,16 @@@ typedef struct socken
        int                      fd;
        struct sockaddr_storage *addr;
        socklen_t                addrlen;
 +
 +#define SECURITY_LEVEL_NONE     0
 +#if HAVE_GCRYPT_H
 +# define SECURITY_LEVEL_SIGN    1
 +# define SECURITY_LEVEL_ENCRYPT 2
 +      int security_level;
 +      char *shared_secret;
 +      gcry_cipher_hd_t cypher;
 +#endif /* HAVE_GCRYPT_H */
 +
        struct sockent          *next;
  } sockent_t;
  
@@@ -161,27 -136,10 +161,27 @@@ struct part_values_
  };
  typedef struct part_values_s part_values_t;
  
 +struct part_signature_sha256_s
 +{
 +  part_header_t head;
 +  char hash[32];
 +};
 +typedef struct part_signature_sha256_s part_signature_sha256_t;
 +
 +struct part_encryption_aes256_s
 +{
 +  part_header_t head;
 +  uint16_t orig_length;
 +  uint16_t random;
 +  char hash[28];
 +};
 +typedef struct part_encryption_aes256_s part_encryption_aes256_t;
 +
  struct receive_list_entry_s
  {
    char data[BUFF_SIZE];
    int  data_len;
 +  int  fd;
    struct receive_list_entry_s *next;
  };
  typedef struct receive_list_entry_s receive_list_entry_t;
  /*
   * Private variables
   */
 -static const char *config_keys[] =
 -{
 -      "CacheFlush",
 -      "Listen",
 -      "Server",
 -      "TimeToLive",
 -      "Forward"
 -};
 -static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 -
  static int network_config_ttl = 0;
  static int network_config_forward = 0;
  
@@@ -199,29 -167,20 +199,29 @@@ static receive_list_entry_t *receive_li
  static pthread_mutex_t       receive_list_lock = PTHREAD_MUTEX_INITIALIZER;
  static pthread_cond_t        receive_list_cond = PTHREAD_COND_INITIALIZER;
  
 -static struct pollfd *listen_sockets = NULL;
 -static int listen_sockets_num = 0;
 -
 -static int listen_loop = 0;
 -static pthread_t receive_thread_id = 0;
 -static pthread_t dispatch_thread_id = 0;
 -
 -static char         send_buffer[BUFF_SIZE];
 -static char        *send_buffer_ptr;
 -static int          send_buffer_fill;
 -static value_list_t send_buffer_vl = VALUE_LIST_STATIC;
 -static pthread_mutex_t send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
 -
 -static c_avl_tree_t      *cache_tree = NULL;
 +static sockent_t     *listen_sockets = NULL;
 +static struct pollfd *listen_sockets_pollfd = NULL;
 +static int            listen_sockets_num = 0;
 +
 +/* The receive and dispatch threads will run as long as `listen_loop' is set to
 + * zero. */
 +static int       listen_loop = 0;
 +static int       receive_thread_running = 0;
 +static pthread_t receive_thread_id;
 +static int       dispatch_thread_running = 0;
 +static pthread_t dispatch_thread_id;
 +
 +/* Buffer in which to-be-sent network packets are constructed. */
 +static char             send_buffer[BUFF_SIZE];
 +static char            *send_buffer_ptr;
 +static int              send_buffer_fill;
 +static value_list_t     send_buffer_vl = VALUE_LIST_STATIC;
 +static pthread_mutex_t  send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
 +
 +/* In this cache we store all the values we received, so we can send out only
 + * those values which were *not* received via the network plugin, too. This is
 + * used for the `Forward false' option. */
 +static c_avl_tree_t    *cache_tree = NULL;
  static pthread_mutex_t  cache_lock = PTHREAD_MUTEX_INITIALIZER;
  static time_t           cache_flush_last = 0;
  static int              cache_flush_interval = 1800;
@@@ -337,6 -296,9 +337,6 @@@ static int cache_check (const value_lis
  
        pthread_mutex_unlock (&cache_lock);
  
 -      DEBUG ("network plugin: cache_check: key = %s; time = %i; retval = %i",
 -                      key, (int) vl->time, retval);
 -
        return (retval);
  } /* int cache_check */
  
@@@ -711,161 -673,15 +711,161 @@@ static int parse_part_string (void **re
        return (0);
  } /* int parse_part_string */
  
 -static int parse_packet (void *buffer, int buffer_len)
 +#if HAVE_GCRYPT_H
 +static int parse_part_sign_sha256 (sockent_t *se, /* {{{ */
 +    void **ret_buffer, int *ret_buffer_len)
 +{
 +  char *buffer = *ret_buffer;
 +  size_t buffer_len = (size_t) *ret_buffer_len;
 +
 +  part_signature_sha256_t ps_received;
 +  part_signature_sha256_t ps_expected;
 +
 +  if (se->shared_secret == NULL)
 +  {
 +    NOTICE ("network plugin: Received signed network packet but can't verify "
 +        "it because no shared secret has been configured. Will accept it.");
 +    return (0);
 +  }
 +
 +  if (buffer_len < sizeof (ps_received))
 +    return (-ENOMEM);
 +
 +  memcpy (&ps_received, buffer, sizeof (ps_received));
 +
 +  memset (&ps_expected, 0, sizeof (ps_expected));
 +  ps_expected.head.type = htons (TYPE_SIGN_SHA256);
 +  ps_expected.head.length = htons (sizeof (ps_expected));
 +  sstrncpy (ps_expected.hash, se->shared_secret, sizeof (ps_expected.hash));
 +  memcpy (buffer, &ps_expected, sizeof (ps_expected));
 +
 +  gcry_md_hash_buffer (GCRY_MD_SHA256, ps_expected.hash, buffer, buffer_len);
 +
 +  *ret_buffer += sizeof (ps_received);
 +
 +  if (memcmp (ps_received.hash, ps_expected.hash,
 +        sizeof (ps_received.hash)) == 0)
 +    return (0);
 +  else /* hashes do not match. */
 +    return (1);
 +} /* }}} int parse_part_sign_sha256 */
 +/* #endif HAVE_GCRYPT_H */
 +
 +#else /* if !HAVE_GCRYPT_H */
 +static int parse_part_sign_sha256 (sockent_t *se, /* {{{ */
 +    void **ret_buffer, int *ret_buffer_len)
 +{
 +  INFO ("network plugin: Received signed packet, but the network "
 +      "plugin was not linked with libgcrypt, so I cannot "
 +      "verify the signature. The packet will be accepted.");
 +  return (0);
 +} /* }}} int parse_part_sign_sha256 */
 +#endif /* !HAVE_GCRYPT_H */
 +
 +#if HAVE_GCRYPT_H
 +static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */
 +              void **ret_buffer, int *ret_buffer_len)
 +{
 +  char *buffer = *ret_buffer;
 +  int   buffer_len = *ret_buffer_len;
 +  int   orig_buffer_len;
 +  part_encryption_aes256_t pea;
 +  char hash[28];
 +  gcry_error_t err;
 +
 +  if (se->cypher == NULL)
 +  {
 +    NOTICE ("network plugin: Unable to decrypt packet, because no cypher "
 +        "instance is present.");
 +    return (-1);
 +  }
 +
 +  /* Decrypt the packet in-place */
 +  err = gcry_cipher_decrypt (se->cypher,
 +      buffer + sizeof (pea.head), buffer_len - sizeof (pea.head),
 +      /* in = */ NULL, /* in len = */ 0);
 +  gcry_cipher_reset (se->cypher);
 +  if (err != 0)
 +  {
 +    ERROR ("network plugin: gcry_cipher_decrypt returned: %s",
 +        gcry_strerror (err));
 +    return (-1);
 +  }
 +
 +  /* Copy the header information to `pea' */
 +  memcpy (&pea, buffer, sizeof (pea));
 +  buffer += sizeof (pea);
 +  buffer_len -= sizeof (pea);
 +
 +  /* Check sanity of the original length */
 +  orig_buffer_len = ntohs (pea.orig_length);
 +  if (orig_buffer_len > buffer_len)
 +  {
 +    ERROR ("network plugin: Decryption failed: Invalid original length.");
 +    return (-1);
 +  }
 +
 +  /* Check hash sum */
 +  memset (hash, 0, sizeof (hash));
 +  gcry_md_hash_buffer (GCRY_MD_SHA224, hash, buffer, orig_buffer_len);
 +  
 +  if (memcmp (hash, pea.hash, sizeof (hash)) != 0)
 +  {
 +    ERROR ("network plugin: Decryption failed: Checksum mismatch.");
 +    return (-1);
 +  }
 +
 +  /* Update return values */
 +  *ret_buffer = buffer;
 +  *ret_buffer_len = orig_buffer_len;
 +
 +  return (0);
 +} /* }}} int parse_part_encr_aes256 */
 +/* #endif HAVE_GCRYPT_H */
 +
 +#else /* if !HAVE_GCRYPT_H */
 +static int parse_part_encr_aes256 (sockent_t *se, /* {{{ */
 +    void **ret_buffer, int *ret_buffer_len)
 +{
 +  INFO ("network plugin: Received encrypted packet, but the network "
 +      "plugin was not linked with libgcrypt, so I cannot "
 +      "decrypt it. The packet will be discarded.");
 +  return (-1);
 +} /* }}} int parse_part_encr_aes256 */
 +#endif /* !HAVE_GCRYPT_H */
 +
 +static int parse_packet (receive_list_entry_t *rle) /* {{{ */
  {
        int status;
  
 +      void *buffer;
 +      int buffer_len;
 +      sockent_t *se;
 +
        value_list_t vl = VALUE_LIST_INIT;
        notification_t n;
  
 -      DEBUG ("network plugin: parse_packet: buffer = %p; buffer_len = %i;",
 -                      buffer, buffer_len);
 +      int packet_was_encrypted = 0;
 +      int packet_was_signed = 0;
 +#if HAVE_GCRYPT_H
 +      int printed_ignore_warning = 0;
 +#endif /* HAVE_GCRYPT_H */
 +
 +      buffer = rle->data;
 +      buffer_len = rle->data_len;
 +
 +      /* Look for the correct `sockent_t' */
 +      se = listen_sockets;
 +      while ((se != NULL) && (se->fd != rle->fd))
 +              se = se->next;
 +
 +      if (se == NULL)
 +      {
 +              ERROR ("network plugin: Got packet from FD %i, but can't "
 +                              "find an appropriate socket entry.",
 +                              rle->fd);
 +              return (-1);
 +      }
  
        memset (&vl, '\0', sizeof (vl));
        memset (&n, '\0', sizeof (n));
                if (pkg_length < (2 * sizeof (uint16_t)))
                        break;
  
 -              if (pkg_type == TYPE_VALUES)
 +              if (pkg_type == TYPE_ENCR_AES256)
 +              {
 +                      status = parse_part_encr_aes256 (se, &buffer, &buffer_len);
 +                      if (status != 0)
 +                      {
 +                              ERROR ("network plugin: Decrypting AES256 "
 +                                              "part failed "
 +                                              "with status %i.", status);
 +                              break;
 +                      }
 +                      else
 +                      {
 +                              packet_was_encrypted = 1;
 +                      }
 +              }
 +#if HAVE_GCRYPT_H
 +              else if ((se->security_level == SECURITY_LEVEL_ENCRYPT)
 +                              && (packet_was_encrypted == 0))
 +              {
 +                      if (printed_ignore_warning == 0)
 +                      {
 +                              INFO ("network plugin: Unencrypted packet or "
 +                                              "part has been ignored.");
 +                              printed_ignore_warning = 1;
 +                      }
 +                      buffer = ((char *) buffer) + pkg_length;
 +                      continue;
 +              }
 +#endif /* HAVE_GCRYPT_H */
 +              else if (pkg_type == TYPE_SIGN_SHA256)
 +              {
 +                      status = parse_part_sign_sha256 (se, &buffer, &buffer_len);
 +                      if (status < 0)
 +                      {
 +                              ERROR ("network plugin: Verifying SHA-256 "
 +                                              "signature failed "
 +                                              "with status %i.", status);
 +                              break;
 +                      }
 +                      else if (status > 0)
 +                      {
 +                              ERROR ("network plugin: Ignoring packet with "
 +                                              "invalid SHA-256 signature.");
 +                              break;
 +                      }
 +                      else
 +                      {
 +                              packet_was_signed = 1;
 +                      }
 +              }
 +#if HAVE_GCRYPT_H
 +              else if ((se->security_level == SECURITY_LEVEL_SIGN)
 +                              && (packet_was_encrypted == 0)
 +                              && (packet_was_signed == 0))
 +              {
 +                      if (printed_ignore_warning == 0)
 +                      {
 +                              INFO ("network plugin: Unsigned packet or "
 +                                              "part has been ignored.");
 +                              printed_ignore_warning = 1;
 +                      }
 +                      buffer = ((char *) buffer) + pkg_length;
 +                      continue;
 +              }
 +#endif /* HAVE_GCRYPT_H */
 +              else if (pkg_type == TYPE_VALUES)
                {
                        status = parse_part_values (&buffer, &buffer_len,
                                        &vl.values, &vl.values_len);
        } /* while (buffer_len > sizeof (part_header_t)) */
  
        return (status);
 -} /* int parse_packet */
 +} /* }}} int parse_packet */
  
 -static void free_sockent (sockent_t *se)
 +static void free_sockent (sockent_t *se) /* {{{ */
  {
        sockent_t *next;
        while (se != NULL)
        {
                next = se->next;
 +
 +#if HAVE_GCRYPT_H
 +              if (se->cypher != NULL)
 +              {
 +                      gcry_cipher_close (se->cypher);
 +                      se->cypher = NULL;
 +              }
 +              free (se->shared_secret);
 +#endif /* HAVE_GCRYPT_H */
 +
                free (se->addr);
                free (se);
 +
                se = next;
        }
 -} /* void free_sockent */
 +} /* }}} void free_sockent */
  
  /*
   * int network_set_ttl
   */
  static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
  {
+       DEBUG ("network plugin: network_set_ttl: network_config_ttl = %i;",
+                       network_config_ttl);
        if ((network_config_ttl < 1) || (network_config_ttl > 255))
                return (-1);
  
-       DEBUG ("ttl = %i", network_config_ttl);
        if (ai->ai_family == AF_INET)
        {
                struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
        return (0);
  } /* int network_set_ttl */
  
 +#if HAVE_GCRYPT_H
 +static int network_set_encryption (sockent_t *se, /* {{{ */
 +              const char *shared_secret)
 +{
 +  char hash[32];
 +  gcry_error_t err;
 +
 +  se->shared_secret = sstrdup (shared_secret);
 +
 +  /*
 +   * We use CBC *without* an initialization vector: The cipher is reset after
 +   * each packet and we would have to re-set the IV each time. The first
 +   * encrypted block will contain the SHA-224 checksum anyway, so this should
 +   * be quite unpredictable. Also, there's a 2 byte field in the header that's
 +   * being filled with random numbers. So we only use CBC so the blocks
 +   * *within* one packet are chained.
 +   */
 +  err = gcry_cipher_open (&se->cypher,
 +      GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, /* flags = */ 0);
 +  if (err != 0)
 +  {
 +    ERROR ("network plugin: gcry_cipher_open returned: %s",
 +        gcry_strerror (err));
 +    return (-1);
 +  }
 +
 +  assert (se->shared_secret != NULL);
 +  gcry_md_hash_buffer (GCRY_MD_SHA256, hash,
 +      se->shared_secret, strlen (se->shared_secret));
 +
 +  err = gcry_cipher_setkey (se->cypher, hash, sizeof (hash));
 +  if (err != 0)
 +  {
 +    DEBUG ("network plugin: gcry_cipher_setkey returned: %s",
 +        gcry_strerror (err));
 +    gcry_cipher_close (se->cypher);
 +    se->cypher = NULL;
 +    return (-1);
 +  }
 +
 +  return (0);
 +} /* }}} int network_set_encryption */
 +#endif /* HAVE_GCRYPT_H */
 +
  static int network_bind_socket (const sockent_t *se, const struct addrinfo *ai)
  {
        int loop = 0;
        return (0);
  } /* int network_bind_socket */
  
 -static sockent_t *network_create_socket (const char *node,
 +#define CREATE_SOCKET_FLAGS_LISTEN    0x0001
 +static sockent_t *network_create_socket (const char *node, /* {{{ */
                const char *service,
 -              int listen)
 +              const char *shared_secret,
 +                int security_level,
 +              int flags)
  {
        struct addrinfo  ai_hints;
        struct addrinfo *ai_list, *ai_ptr;
        for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
        {
                sockent_t *se;
 +              int status;
  
                if ((se = (sockent_t *) malloc (sizeof (sockent_t))) == NULL)
                {
                        continue;
                }
  
 -              if (listen != 0)
 +              if ((flags & CREATE_SOCKET_FLAGS_LISTEN) != 0)
                {
 -                      if (network_bind_socket (se, ai_ptr) != 0)
 +                      status = network_bind_socket (se, ai_ptr);
 +                      if (status != 0)
                        {
                                close (se->fd);
                                free (se->addr);
                                continue;
                        }
                }
 -              else /* listen == 0 */
 +              else /* sending socket */
                {
                        network_set_ttl (se, ai_ptr);
                }
  
 +#if HAVE_GCRYPT_H
 +              se->security_level = security_level;
 +              se->shared_secret = NULL;
 +              se->cypher = NULL;
 +              if (shared_secret != NULL)
 +              {
 +                      status = network_set_encryption (se, shared_secret);
 +                      if ((status != 0) && (security_level <= SECURITY_LEVEL_SIGN))
 +                      {
 +                              WARNING ("network plugin: Starting cryptograp"
 +                                              "hic subsystem failed. Since "
 +                                              "security level `Sign' or "
 +                                              "`None' is configured I will "
 +                                              "continue.");
 +                      }
 +                      else if (status != 0)
 +                      {
 +                              ERROR ("network plugin: Starting cryptograp"
 +                                              "hic subsystem failed. "
 +                                              "Because the security level "
 +                                              "is set to `Encrypt' I will "
 +                                              "not continue!");
 +                              close (se->fd);
 +                              free (se->addr);
 +                              free (se);
 +                              continue;
 +                      }
 +              } /* if (shared_secret != NULL) */
 +#else
 +              /* Make compiler happy */
 +              security_level = 0;
 +              shared_secret = NULL;
 +#endif /* HAVE_GCRYPT_H */
 +
                if (se_tail == NULL)
                {
                        se_head = se;
                }
  
                /* We don't open more than one write-socket per node/service pair.. */
 -              if (listen == 0)
 +              if ((flags & CREATE_SOCKET_FLAGS_LISTEN) == 0)
                        break;
        }
  
        freeaddrinfo (ai_list);
  
        return (se_head);
 -} /* sockent_t *network_create_socket */
 +} /* }}} sockent_t *network_create_socket */
  
 -static sockent_t *network_create_default_socket (int listen)
 +static sockent_t *network_create_default_socket (int flags) /* {{{ */
  {
        sockent_t *se_ptr  = NULL;
        sockent_t *se_head = NULL;
        sockent_t *se_tail = NULL;
  
 -      se_ptr = network_create_socket (NET_DEFAULT_V6_ADDR,
 -                      NET_DEFAULT_PORT, listen);
 +      se_ptr = network_create_socket (NET_DEFAULT_V6_ADDR, NET_DEFAULT_PORT,
 +                      /* shared secret = */ NULL, SECURITY_LEVEL_NONE,
 +                        flags);
  
        /* Don't send to the same machine in IPv6 and IPv4 if both are available. */
 -      if ((listen == 0) && (se_ptr != NULL))
 +      if (((flags & CREATE_SOCKET_FLAGS_LISTEN) == 0) && (se_ptr != NULL))
                return (se_ptr);
  
        if (se_ptr != NULL)
                        se_tail = se_tail->next;
        }
  
 -      se_ptr = network_create_socket (NET_DEFAULT_V4_ADDR, NET_DEFAULT_PORT, listen);
 +      se_ptr = network_create_socket (NET_DEFAULT_V4_ADDR, NET_DEFAULT_PORT,
 +                      /* shared secret = */ NULL, SECURITY_LEVEL_NONE,
 +                        flags);
  
        if (se_tail == NULL)
                return (se_ptr);
  
        se_tail->next = se_ptr;
        return (se_head);
 -} /* sockent_t *network_create_default_socket */
 +} /* }}} sockent_t *network_create_default_socket */
  
 -static int network_add_listen_socket (const char *node, const char *service)
 +static int network_add_listen_socket (const char *node, /* {{{ */
 +    const char *service, const char *shared_secret, int security_level)
  {
        sockent_t *se;
        sockent_t *se_ptr;
        int se_num = 0;
  
 +        int flags;
 +
 +        flags = CREATE_SOCKET_FLAGS_LISTEN;
 +
        if (service == NULL)
                service = NET_DEFAULT_PORT;
  
        if (node == NULL)
 -              se = network_create_default_socket (1 /* listen == true */);
 +              se = network_create_default_socket (flags);
        else
 -              se = network_create_socket (node, service, 1 /* listen == true */);
 +              se = network_create_socket (node, service,
 +                    shared_secret, security_level, flags);
  
        if (se == NULL)
                return (-1);
        for (se_ptr = se; se_ptr != NULL; se_ptr = se_ptr->next)
                se_num++;
  
 -      listen_sockets = (struct pollfd *) realloc (listen_sockets,
 +      listen_sockets_pollfd = realloc (listen_sockets_pollfd,
                        (listen_sockets_num + se_num)
                        * sizeof (struct pollfd));
  
        for (se_ptr = se; se_ptr != NULL; se_ptr = se_ptr->next)
        {
 -              listen_sockets[listen_sockets_num].fd = se_ptr->fd;
 -              listen_sockets[listen_sockets_num].events = POLLIN | POLLPRI;
 -              listen_sockets[listen_sockets_num].revents = 0;
 +              listen_sockets_pollfd[listen_sockets_num].fd = se_ptr->fd;
 +              listen_sockets_pollfd[listen_sockets_num].events = POLLIN | POLLPRI;
 +              listen_sockets_pollfd[listen_sockets_num].revents = 0;
                listen_sockets_num++;
        } /* for (se) */
  
 -      free_sockent (se);
 +      se_ptr = listen_sockets;
 +      while ((se_ptr != NULL) && (se_ptr->next != NULL))
 +              se_ptr = se_ptr->next;
 +
 +      if (se_ptr == NULL)
 +              listen_sockets = se;
 +      else
 +              se_ptr->next = se;
 +
        return (0);
 -} /* int network_add_listen_socket */
 +} /* }}} int network_add_listen_socket */
  
 -static int network_add_sending_socket (const char *node, const char *service)
 +static int network_add_sending_socket (const char *node, /* {{{ */
 +    const char *service, const char *shared_secret, int security_level)
  {
        sockent_t *se;
        sockent_t *se_ptr;
                service = NET_DEFAULT_PORT;
  
        if (node == NULL)
 -              se = network_create_default_socket (0 /* listen == false */);
 +              se = network_create_default_socket (/* flags = */ 0);
        else
 -              se = network_create_socket (node, service, 0 /* listen == false */);
 +              se = network_create_socket (node, service,
 +                              shared_secret, security_level,
 +                                /* flags = */ 0);
  
        if (se == NULL)
                return (-1);
  
        se_ptr->next = se;
        return (0);
 -} /* int network_get_listen_socket */
 +} /* }}} int network_add_sending_socket */
  
  static void *dispatch_thread (void __attribute__((unused)) *arg)
  {
      if (ent == NULL)
        break;
  
 -    parse_packet (ent->data, ent->data_len);
 +    parse_packet (ent);
  
      sfree (ent);
    } /* while (42) */
  
    return (NULL);
 -} /* void *receive_thread */
 +} /* void *dispatch_thread */
  
  static int network_receive (void)
  {
        receive_list_entry_t *private_list_tail;
  
        if (listen_sockets_num == 0)
 -              network_add_listen_socket (NULL, NULL);
 +              network_add_listen_socket (/* node = */ NULL,
 +                              /* service = */ NULL,
 +                              /* shared secret = */ NULL,
 +                              /* encryption = */ 0);
  
        if (listen_sockets_num == 0)
        {
  
        while (listen_loop == 0)
        {
 -              status = poll (listen_sockets, listen_sockets_num, -1);
 +              status = poll (listen_sockets_pollfd, listen_sockets_num, -1);
  
                if (status <= 0)
                {
                {
                        receive_list_entry_t *ent;
  
 -                      if ((listen_sockets[i].revents & (POLLIN | POLLPRI)) == 0)
 +                      if ((listen_sockets_pollfd[i].revents
 +                                              & (POLLIN | POLLPRI)) == 0)
                                continue;
                        status--;
  
 -                      buffer_len = recv (listen_sockets[i].fd,
 +                      buffer_len = recv (listen_sockets_pollfd[i].fd,
                                        buffer, sizeof (buffer),
                                        0 /* no flags */);
                        if (buffer_len < 0)
                                return (-1);
                        }
  
 +                      /* TODO: Possible performance enhancement: Do not free
 +                       * these entries in the dispatch thread but put them in
 +                       * another list, so we don't have to allocate more and
 +                       * more of these structures. */
                        ent = malloc (sizeof (receive_list_entry_t));
                        if (ent == NULL)
                        {
                                return (-1);
                        }
                        memset (ent, 0, sizeof (receive_list_entry_t));
 +                      ent->fd = listen_sockets_pollfd[i].fd;
                        ent->next = NULL;
  
                        /* Hopefully this be optimized out by the compiler. It
                                pthread_cond_signal (&receive_list_cond);
                                pthread_mutex_unlock (&receive_list_lock);
                        }
 -              } /* for (listen_sockets) */
 +              } /* for (listen_sockets_pollfd) */
        } /* while (listen_loop == 0) */
  
        /* Make sure everything is dispatched before exiting. */
        }
  
        return (0);
 -}
 +} /* int network_receive */
  
  static void *receive_thread (void __attribute__((unused)) *arg)
  {
        return (network_receive () ? (void *) 1 : (void *) 0);
  } /* void *receive_thread */
  
 -static void network_send_buffer (const char *buffer, int buffer_len)
 +static void network_init_buffer (void)
  {
 -      sockent_t *se;
 -      int status;
 +      memset (send_buffer, 0, sizeof (send_buffer));
 +      send_buffer_ptr = send_buffer;
 +      send_buffer_fill = 0;
  
 -      DEBUG ("network plugin: network_send_buffer: buffer_len = %i", buffer_len);
 +      memset (&send_buffer_vl, 0, sizeof (send_buffer_vl));
 +} /* int network_init_buffer */
  
 -      for (se = sending_sockets; se != NULL; se = se->next)
 +static void networt_send_buffer_plain (const sockent_t *se, /* {{{ */
 +              const char *buffer, size_t buffer_size)
 +{
 +      int status;
 +
 +      while (42)
        {
 -              while (42)
 +              status = sendto (se->fd, buffer, buffer_size, 0 /* no flags */,
 +                              (struct sockaddr *) se->addr, se->addrlen);
 +              if (status < 0)
                {
 -                      status = sendto (se->fd, buffer, buffer_len, 0 /* no flags */,
 -                                      (struct sockaddr *) se->addr, se->addrlen);
 -                      if (status < 0)
 -                      {
 -                              char errbuf[1024];
 -                              if (errno == EINTR)
 -                                      continue;
 -                              ERROR ("network plugin: sendto failed: %s",
 -                                              sstrerror (errno, errbuf,
 -                                                      sizeof (errbuf)));
 -                              break;
 -                      }
 -
 +                      char errbuf[1024];
 +                      if (errno == EINTR)
 +                              continue;
 +                      ERROR ("network plugin: sendto failed: %s",
 +                                      sstrerror (errno, errbuf,
 +                                              sizeof (errbuf)));
                        break;
 -              } /* while (42) */
 -      } /* for (sending_sockets) */
 -} /* void network_send_buffer */
 +              }
 +
 +              break;
 +      } /* while (42) */
 +} /* }}} void networt_send_buffer_plain */
 +
 +#if HAVE_GCRYPT_H
 +static void networt_send_buffer_signed (const sockent_t *se, /* {{{ */
 +              const char *in_buffer, size_t in_buffer_size)
 +{
 +      part_signature_sha256_t ps;
 +      char buffer[sizeof (ps) + in_buffer_size];
 +      char hash[sizeof (ps.hash)];
 +
 +      /* Initialize the `ps' structure. */
 +      memset (&ps, 0, sizeof (ps));
 +      ps.head.type = htons (TYPE_SIGN_SHA256);
 +      ps.head.length = htons ((uint16_t) sizeof (ps));
 +      sstrncpy (ps.hash, se->shared_secret, sizeof (ps.hash));
 +
 +      /* Prepend the signature. */
 +      memcpy (buffer, &ps, sizeof (ps));
 +      memcpy (buffer + sizeof (ps), in_buffer, in_buffer_size);
 +
 +      /* Calculate the hash value. */
 +      gcry_md_hash_buffer (GCRY_MD_SHA256, hash, buffer, sizeof (buffer));
 +
 +      /* Copy the hash value into the buffer. */
 +      memcpy (ps.hash, hash, sizeof (ps.hash));
 +      memcpy (buffer, &ps, sizeof (ps));
 +
 +      networt_send_buffer_plain (se, buffer, sizeof (buffer));
 +} /* }}} void networt_send_buffer_signed */
 +
 +static void networt_send_buffer_encrypted (const sockent_t *se, /* {{{ */
 +              const char *in_buffer, size_t in_buffer_size)
 +{
 +  part_encryption_aes256_t pea;
 +  char buffer[sizeof (pea) + in_buffer_size + 16];
 +  size_t buffer_size;
 +  gcry_error_t err;
 +
 +  /* Round to the next multiple of 16, because AES has a block size of 128 bit.
 +   * the first four bytes of `pea' are not encrypted and must be subtracted. */
 +  buffer_size = (sizeof (pea) + in_buffer_size + 15 - sizeof (pea.head)) / 16;
 +  buffer_size = buffer_size * 16;
 +  buffer_size += sizeof (pea.head);
 +
 +  DEBUG ("network plugin: networt_send_buffer_encrypted: "
 +      "buffer_size = %zu;", buffer_size);
 +
 +  /* Initialize the header fields */
 +  memset (&pea, 0, sizeof (pea));
 +  pea.head.type = htons (TYPE_ENCR_AES256);
 +  pea.head.length = htons ((uint16_t) buffer_size);
 +  pea.orig_length = htons ((uint16_t) in_buffer_size);
 +
 +  /* Fill the extra field with random values. Some entropy in the encrypted
 +   * data is usually not a bad thing, I hope. */
 +  gcry_randomize (&pea.random, sizeof (pea.random), GCRY_STRONG_RANDOM);
 +
 +  /* Create hash of the payload */
 +  gcry_md_hash_buffer (GCRY_MD_SHA224, pea.hash, in_buffer, in_buffer_size);
 +
 +  /* Initialize the buffer */
 +  memset (buffer, 0, sizeof (buffer));
 +  memcpy (buffer, &pea, sizeof (pea));
 +  memcpy (buffer + sizeof (pea), in_buffer, in_buffer_size);
 +
 +  /* Encrypt the buffer in-place */
 +  err = gcry_cipher_encrypt (se->cypher,
 +      buffer + sizeof (pea.head), buffer_size - sizeof (pea.head),
 +      /* in = */ NULL, /* in len = */ 0);
 +  gcry_cipher_reset (se->cypher);
 +  if (err != 0)
 +  {
 +    ERROR ("network plugin: gcry_cipher_encrypt returned: %s",
 +        gcry_strerror (err));
 +    return;
 +  }
 +
 +  /* Send it out without further modifications */
 +  networt_send_buffer_plain (se, buffer, buffer_size);
 +} /* }}} void networt_send_buffer_encrypted */
 +#endif /* HAVE_GCRYPT_H */
 +
 +static void network_send_buffer (char *buffer, size_t buffer_len) /* {{{ */
 +{
 +  sockent_t *se;
  
 -static int add_to_buffer (char *buffer, int buffer_size,
 +  DEBUG ("network plugin: network_send_buffer: buffer_len = %zu", buffer_len);
 +
 +  for (se = sending_sockets; se != NULL; se = se->next)
 +  {
 +#if HAVE_GCRYPT_H
 +    if (se->security_level == SECURITY_LEVEL_ENCRYPT)
 +      networt_send_buffer_encrypted (se, buffer, buffer_len);
 +    else if (se->security_level == SECURITY_LEVEL_SIGN)
 +      networt_send_buffer_signed (se, buffer, buffer_len);
 +    else /* if (se->security_level == SECURITY_LEVEL_NONE) */
 +#endif /* HAVE_GCRYPT_H */
 +      networt_send_buffer_plain (se, buffer, buffer_len);
 +  } /* for (sending_sockets) */
 +} /* }}} void network_send_buffer */
 +
 +static int add_to_buffer (char *buffer, int buffer_size, /* {{{ */
                value_list_t *vl_def,
                const data_set_t *ds, const value_list_t *vl)
  {
                return (-1);
  
        return (buffer - buffer_orig);
 -} /* int add_to_buffer */
 +} /* }}} int add_to_buffer */
  
  static void flush_buffer (void)
  {
        DEBUG ("network plugin: flush_buffer: send_buffer_fill = %i",
                        send_buffer_fill);
  
 -      network_send_buffer (send_buffer, send_buffer_fill);
 -      send_buffer_ptr  = send_buffer;
 -      send_buffer_fill = 0;
 -      memset (&send_buffer_vl, 0, sizeof (send_buffer_vl));
 +      network_send_buffer (send_buffer, (size_t) send_buffer_fill);
 +      network_init_buffer ();
  }
  
 -static int network_write (const data_set_t *ds, const value_list_t *vl)
 +static int network_write (const data_set_t *ds, const value_list_t *vl,
 +              user_data_t __attribute__((unused)) *user_data)
  {
        int status;
  
        pthread_mutex_lock (&send_buffer_lock);
  
        status = add_to_buffer (send_buffer_ptr,
 -                      sizeof (send_buffer) - send_buffer_fill,
 +                      sizeof (send_buffer) - (send_buffer_fill + BUFF_SIG_SIZE),
                        &send_buffer_vl,
                        ds, vl);
        if (status >= 0)
                flush_buffer ();
  
                status = add_to_buffer (send_buffer_ptr,
 -                              sizeof (send_buffer) - send_buffer_fill,
 +                              sizeof (send_buffer) - (send_buffer_fill + BUFF_SIG_SIZE),
                                &send_buffer_vl,
                                ds, vl);
  
        return ((status < 0) ? -1 : 0);
  } /* int network_write */
  
 -static int network_config (const char *key, const char *val)
 +static int network_config_set_boolean (const oconfig_item_t *ci, /* {{{ */
 +    int *retval)
  {
 -      char *node;
 -      char *service;
 +  if ((ci->values_num != 1)
 +      || ((ci->values[0].type != OCONFIG_TYPE_BOOLEAN)
 +        && (ci->values[0].type != OCONFIG_TYPE_STRING)))
 +  {
 +    ERROR ("network plugin: The `%s' config option needs "
 +        "exactly one boolean argument.", ci->key);
 +    return (-1);
 +  }
  
 -      char *fields[3];
 -      int   fields_num;
 +  if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN)
 +  {
 +    if (ci->values[0].value.boolean)
 +      *retval = 1;
 +    else
 +      *retval = 0;
 +  }
 +  else
 +  {
 +    char *str = ci->values[0].value.string;
 +
 +    if ((strcasecmp ("true", str) == 0)
 +        || (strcasecmp ("yes", str) == 0)
 +        || (strcasecmp ("on", str) == 0))
 +      *retval = 1;
 +    else if ((strcasecmp ("false", str) == 0)
 +        || (strcasecmp ("no", str) == 0)
 +        || (strcasecmp ("off", str) == 0))
 +      *retval = 0;
 +    else
 +    {
 +      ERROR ("network plugin: Cannot parse string value `%s' of the `%s' "
 +          "option as boolean value.",
 +          str, ci->key);
 +      return (-1);
 +    }
 +  }
  
 -      if ((strcasecmp ("Listen", key) == 0)
 -                      || (strcasecmp ("Server", key) == 0))
 -      {
 -              char *val_cpy = strdup (val);
 -              if (val_cpy == NULL)
 -                      return (1);
 +  return (0);
 +} /* }}} int network_config_set_boolean */
  
 -              service = NET_DEFAULT_PORT;
 -              fields_num = strsplit (val_cpy, fields, 3);
 -              if ((fields_num != 1)
 -                              && (fields_num != 2))
 -              {
 -                      sfree (val_cpy);
 -                      return (1);
 -              }
 -              else if (fields_num == 2)
 -              {
 -                      if ((service = strchr (fields[1], '.')) != NULL)
 -                              *service = '\0';
 -                      service = fields[1];
 -              }
 -              node = fields[0];
 +static int network_config_set_ttl (const oconfig_item_t *ci) /* {{{ */
 +{
 +  int tmp;
 +  if ((ci->values_num != 1)
 +      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
 +  {
 +    WARNING ("network plugin: The `TimeToLive' config option needs exactly "
 +        "one numeric argument.");
 +    return (-1);
 +  }
  
 -              if (strcasecmp ("Listen", key) == 0)
 -                      network_add_listen_socket (node, service);
 -              else
 -                      network_add_sending_socket (node, service);
 +  tmp = (int) ci->values[0].value.number;
 +  if ((tmp > 0) && (tmp <= 255))
 +    network_config_ttl = tmp;
  
 -              sfree (val_cpy);
 -      }
 -      else if (strcasecmp ("TimeToLive", key) == 0)
 -      {
 -              int tmp = atoi (val);
 -              if ((tmp > 0) && (tmp < 256))
 -                      network_config_ttl = tmp;
 -              else
 -                      return (1);
 -      }
 -      else if (strcasecmp ("Forward", key) == 0)
 -      {
 -              if ((strcasecmp ("true", val) == 0)
 -                              || (strcasecmp ("yes", val) == 0)
 -                              || (strcasecmp ("on", val) == 0))
 -                      network_config_forward = 1;
 -              else
 -                      network_config_forward = 0;
 -      }
 -      else if (strcasecmp ("CacheFlush", key) == 0)
 -      {
 -              int tmp = atoi (val);
 -              if (tmp > 0)
 -                      cache_flush_interval = tmp;
 -              else return (1);
 -      }
 -      else
 -      {
 -              return (-1);
 -      }
 -      return (0);
 -} /* int network_config */
 +  return (0);
 +} /* }}} int network_config_set_ttl */
 +
 +#if HAVE_GCRYPT_H
 +static int network_config_set_security_level (oconfig_item_t *ci, /* {{{ */
 +    int *retval)
 +{
 +  char *str;
 +  if ((ci->values_num != 1)
 +      || (ci->values[0].type != OCONFIG_TYPE_STRING))
 +  {
 +    WARNING ("network plugin: The `SecurityLevel' config option needs exactly "
 +        "one string argument.");
 +    return (-1);
 +  }
 +
 +  str = ci->values[0].value.string;
 +  if (strcasecmp ("Encrypt", str) == 0)
 +    *retval = SECURITY_LEVEL_ENCRYPT;
 +  else if (strcasecmp ("Sign", str) == 0)
 +    *retval = SECURITY_LEVEL_SIGN;
 +  else if (strcasecmp ("None", str) == 0)
 +    *retval = SECURITY_LEVEL_NONE;
 +  else
 +  {
 +    WARNING ("network plugin: Unknown security level: %s.", str);
 +    return (-1);
 +  }
 +
 +  return (0);
 +} /* }}} int network_config_set_security_level */
 +#endif /* HAVE_GCRYPT_H */
 +
 +static int network_config_listen_server (const oconfig_item_t *ci) /* {{{ */
 +{
 +  char *node;
 +  char *service;
 +  char *shared_secret = NULL;
 +  int security_level = SECURITY_LEVEL_NONE;
 +  int i;
 +
 +  if ((ci->values_num < 1) || (ci->values_num > 2)
 +      || (ci->values[0].type != OCONFIG_TYPE_STRING)
 +      || ((ci->values_num > 1) && (ci->values[1].type != OCONFIG_TYPE_STRING)))
 +  {
 +    ERROR ("network plugin: The `%s' config option needs "
 +        "one or two string arguments.", ci->key);
 +    return (-1);
 +  }
 +
 +  node = ci->values[0].value.string;
 +  if (ci->values_num >= 2)
 +    service = ci->values[1].value.string;
 +  else
 +    service = NULL;
 +
 +  for (i = 0; i < ci->children_num; i++)
 +  {
 +    oconfig_item_t *child = ci->children + i;
 +
 +#if HAVE_GCRYPT_H
 +    if (strcasecmp ("Secret", child->key) == 0)
 +    {
 +      if ((child->values_num == 1)
 +          && (child->values[0].type == OCONFIG_TYPE_STRING))
 +        shared_secret = child->values[0].value.string;
 +      else
 +        ERROR ("network plugin: The `Secret' option needs exactly one string "
 +            "argument.");
 +    }
 +    else if (strcasecmp ("SecurityLevel", child->key) == 0)
 +      network_config_set_security_level (child, &security_level);
 +    else
 +#endif /* HAVE_GCRYPT_H */
 +    {
 +      WARNING ("network plugin: Option `%s' is not allowed here.",
 +          child->key);
 +    }
 +  }
 +
 +  if ((security_level > SECURITY_LEVEL_NONE) && (shared_secret == NULL))
 +  {
 +    ERROR ("network plugin: A security level higher than `none' was "
 +        "requested, but no shared key was given. Cowardly refusing to open "
 +        "this socket!");
 +    return (-1);
 +  }
 +
 +  if (strcasecmp ("Listen", ci->key) == 0)
 +    network_add_listen_socket (node, service, shared_secret, security_level);
 +  else
 +    network_add_sending_socket (node, service, shared_secret, security_level);
 +
 +  return (0);
 +} /* }}} int network_config_listen_server */
 +
 +static int network_config_set_cache_flush (const oconfig_item_t *ci) /* {{{ */
 +{
 +  int tmp;
 +  if ((ci->values_num != 1)
 +      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
 +  {
 +    WARNING ("network plugin: The `CacheFlush' config option needs exactly "
 +        "one numeric argument.");
 +    return (-1);
 +  }
  
 -static int network_notification (const notification_t *n)
 +  tmp = (int) ci->values[0].value.number;
 +  if (tmp > 0)
 +    network_config_ttl = tmp;
 +
 +  return (0);
 +} /* }}} int network_config_set_cache_flush */
 +
 +static int network_config (oconfig_item_t *ci) /* {{{ */
 +{
 +  int i;
 +
 +  for (i = 0; i < ci->children_num; i++)
 +  {
 +    oconfig_item_t *child = ci->children + i;
 +
 +    if ((strcasecmp ("Listen", child->key) == 0)
 +        || (strcasecmp ("Server", child->key) == 0))
 +      network_config_listen_server (child);
 +    else if (strcasecmp ("TimeToLive", child->key) == 0)
 +      network_config_set_ttl (child);
 +    else if (strcasecmp ("Forward", child->key) == 0)
 +      network_config_set_boolean (child, &network_config_forward);
 +    else if (strcasecmp ("CacheFlush", child->key) == 0)
 +      network_config_set_cache_flush (child);
 +    else
 +    {
 +      WARNING ("network plugin: Option `%s' is not allowed here.",
 +          child->key);
 +    }
 +  }
 +
 +  return (0);
 +} /* }}} int network_config */
 +
 +static int network_notification (const notification_t *n,
 +              user_data_t __attribute__((unused)) *user_data)
  {
    char  buffer[BUFF_SIZE];
    char *buffer_ptr = buffer;
@@@ -2312,27 -1708,16 +2313,27 @@@ static int network_shutdown (void
        listen_loop++;
  
        /* Kill the listening thread */
 -      if (receive_thread_id != (pthread_t) 0)
 +      if (receive_thread_running != 0)
        {
 +              INFO ("network plugin: Stopping receive thread.");
                pthread_kill (receive_thread_id, SIGTERM);
                pthread_join (receive_thread_id, NULL /* no return value */);
 -              receive_thread_id = (pthread_t) 0;
 +              memset (&receive_thread_id, 0, sizeof (receive_thread_id));
 +              receive_thread_running = 0;
        }
  
        /* Shutdown the dispatching thread */
 -      if (dispatch_thread_id != (pthread_t) 0)
 +      if (dispatch_thread_running != 0)
 +      {
 +              INFO ("network plugin: Stopping dispatch thread.");
 +              pthread_mutex_lock (&receive_list_lock);
                pthread_cond_broadcast (&receive_list_cond);
 +              pthread_mutex_unlock (&receive_list_lock);
 +              pthread_join (dispatch_thread_id, /* ret = */ NULL);
 +              dispatch_thread_running = 0;
 +      }
 +
 +      free_sockent (listen_sockets);
  
        if (send_buffer_fill > 0)
                flush_buffer ();
@@@ -2373,7 -1758,9 +2374,7 @@@ static int network_init (void
  
        plugin_register_shutdown ("network", network_shutdown);
  
 -      send_buffer_ptr  = send_buffer;
 -      send_buffer_fill = 0;
 -      memset (&send_buffer_vl, 0, sizeof (send_buffer_vl));
 +      network_init_buffer ();
  
        cache_tree = c_avl_create ((int (*) (const void *, const void *)) strcmp);
        cache_flush_last = time (NULL);
        /* setup socket(s) and so on */
        if (sending_sockets != NULL)
        {
 -              plugin_register_write ("network", network_write);
 -              plugin_register_notification ("network", network_notification);
 +              plugin_register_write ("network", network_write,
 +                              /* user_data = */ NULL);
 +              plugin_register_notification ("network", network_notification,
 +                              /* user_data = */ NULL);
        }
  
 -      if ((listen_sockets_num != 0) && (receive_thread_id == 0))
 +      /* If no threads need to be started, return here. */
 +      if ((listen_sockets_num == 0)
 +                      || ((dispatch_thread_running != 0)
 +                              && (receive_thread_running != 0)))
 +              return (0);
 +
 +      if (dispatch_thread_running == 0)
        {
                int status;
 -
                status = pthread_create (&dispatch_thread_id,
                                NULL /* no attributes */,
                                dispatch_thread,
                                        sstrerror (errno, errbuf,
                                                sizeof (errbuf)));
                }
 +              else
 +              {
 +                      dispatch_thread_running = 1;
 +              }
 +      }
  
 +      if (receive_thread_running == 0)
 +      {
 +              int status;
                status = pthread_create (&receive_thread_id,
                                NULL /* no attributes */,
                                receive_thread,
                                        sstrerror (errno, errbuf,
                                                sizeof (errbuf)));
                }
 +              else
 +              {
 +                      receive_thread_running = 1;
 +              }
        }
 +
        return (0);
  } /* int network_init */
  
   * there, good. If not, well, then there is nothing to flush.. -octo
   */
  static int network_flush (int timeout,
 -              const char __attribute__((unused)) *identifier)
 +              const char __attribute__((unused)) *identifier,
 +              user_data_t __attribute__((unused)) *user_data)
  {
        pthread_mutex_lock (&send_buffer_lock);
  
  
  void module_register (void)
  {
 -      plugin_register_config ("network", network_config,
 -                      config_keys, config_keys_num);
 +      plugin_register_complex_config ("network", network_config);
        plugin_register_init   ("network", network_init);
 -      plugin_register_flush   ("network", network_flush);
 +      plugin_register_flush   ("network", network_flush,
 +                      /* user_data = */ NULL);
  } /* void module_register */
 +
 +/* vim: set fdm=marker : */