-fix #3870
[oweals/gnunet.git] / src / util / service.c
index 5f58bcf6a04a2bcc6a4bc87d1c286f1dc7148914..80d18d8f128f4967e2e258c2da9f482d7bfa261c 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2009, 2012 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2009, 2012 Christian Grothoff (and other contributing authors)
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      GNUnet 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
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
  * @author Christian Grothoff
  */
 #include "platform.h"
  * @author Christian Grothoff
  */
 #include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_configuration_lib.h"
-#include "gnunet_crypto_lib.h"
-#include "gnunet_directories.h"
-#include "gnunet_disk_lib.h"
-#include "gnunet_getopt_lib.h"
-#include "gnunet_os_lib.h"
+#include "gnunet_util_lib.h"
 #include "gnunet_protocols.h"
 #include "gnunet_protocols.h"
+#include "gnunet_constants.h"
 #include "gnunet_resolver_service.h"
 #include "gnunet_resolver_service.h"
-#include "gnunet_server_lib.h"
-#include "gnunet_service_lib.h"
+#include "speedup.h"
+
+#if HAVE_MALLINFO
+#include <malloc.h>
+#include "gauger.h"
+#endif
+
 
 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
 
 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
 
 /* ******************* access control ******************** */
 
 
 /* ******************* access control ******************** */
 
-/**
- * @brief IPV4 network in CIDR notation.
- */
-struct IPv4NetworkSet
-{
-  /**
-   * IPv4 address.
-   */
-  struct in_addr network;
-
-  /**
-   * IPv4 netmask.
-   */
-  struct in_addr netmask;
-};
-
-/**
- * @brief network in CIDR notation for IPV6.
- */
-struct IPv6NetworkSet
-{
-  /**
-   * IPv6 address.
-   */
-  struct in6_addr network;
-
-  /**
-   * IPv6 netmask.
-   */
-  struct in6_addr netmask;
-};
-
-
-/**
- * Parse a network specification. The argument specifies
- * a list of networks. The format is
- * <tt>[network/netmask;]*</tt> (no whitespace, must be terminated
- * with a semicolon). The network must be given in dotted-decimal
- * notation. The netmask can be given in CIDR notation (/16) or
- * in dotted-decimal (/255.255.0.0).
- * 
- * @param routeList a string specifying the forbidden networks
- * @return the converted list, NULL if the synatx is flawed
- */
-static struct IPv4NetworkSet *
-parse_ipv4_specification (const char *routeList)
-{
-  unsigned int count;
-  unsigned int i;
-  unsigned int j;
-  unsigned int len;
-  int cnt;
-  unsigned int pos;
-  unsigned int temps[8];
-  int slash;
-  struct IPv4NetworkSet *result;
-
-  if (NULL == routeList)
-    return NULL;
-  len = strlen (routeList);
-  if (0 == len)
-    return NULL;
-  count = 0;
-  for (i = 0; i < len; i++)
-    if (routeList[i] == ';')
-      count++;
-  result = GNUNET_malloc (sizeof (struct IPv4NetworkSet) * (count + 1));
-  i = 0;
-  pos = 0;
-  while (i < count)
-  {
-    cnt =
-        SSCANF (&routeList[pos], "%u.%u.%u.%u/%u.%u.%u.%u;", &temps[0],
-                &temps[1], &temps[2], &temps[3], &temps[4], &temps[5],
-                &temps[6], &temps[7]);
-    if (8 == cnt)
-    {
-      for (j = 0; j < 8; j++)
-        if (temps[j] > 0xFF)
-        {
-          LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
-               &routeList[pos]);
-          GNUNET_free (result);
-          return NULL;
-        }
-      result[i].network.s_addr =
-          htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) +
-                 temps[3]);
-      result[i].netmask.s_addr =
-          htonl ((temps[4] << 24) + (temps[5] << 16) + (temps[6] << 8) +
-                 temps[7]);
-      while (routeList[pos] != ';')
-        pos++;
-      pos++;
-      i++;
-      continue;
-    }
-    /* try second notation */
-    cnt =
-        SSCANF (&routeList[pos], "%u.%u.%u.%u/%u;", &temps[0], &temps[1],
-                &temps[2], &temps[3], &slash);
-    if (5 == cnt)
-    {
-      for (j = 0; j < 4; j++)
-        if (temps[j] > 0xFF)
-        {
-          LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
-               &routeList[pos]);
-          GNUNET_free (result);
-          return NULL;
-        }
-      result[i].network.s_addr =
-          htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) +
-                 temps[3]);
-      if ((slash <= 32) && (slash >= 0))
-      {
-        result[i].netmask.s_addr = 0;
-        while (slash > 0)
-        {
-          result[i].netmask.s_addr =
-              (result[i].netmask.s_addr >> 1) + 0x80000000;
-          slash--;
-        }
-        result[i].netmask.s_addr = htonl (result[i].netmask.s_addr);
-        while (';' != routeList[pos])
-          pos++;
-        pos++;
-        i++;
-        continue;
-      }
-      else
-      {
-        LOG (GNUNET_ERROR_TYPE_ERROR,
-             _("Invalid network notation ('/%d' is not legal in IPv4 CIDR)."),
-             slash);
-        GNUNET_free (result);
-        return NULL;            /* error */
-      }
-    }
-    /* try third notation */
-    slash = 32;
-    cnt =
-        SSCANF (&routeList[pos], "%u.%u.%u.%u;", &temps[0], &temps[1],
-                &temps[2], &temps[3]);
-    if (4 == cnt)
-    {
-      for (j = 0; j < 4; j++)
-        if (temps[j] > 0xFF)
-        {
-          LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
-               &routeList[pos]);
-          GNUNET_free (result);
-          return NULL;
-        }
-      result[i].network.s_addr =
-          htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) +
-                 temps[3]);
-      result[i].netmask.s_addr = 0;
-      while (slash > 0)
-      {
-        result[i].netmask.s_addr = (result[i].netmask.s_addr >> 1) + 0x80000000;
-        slash--;
-      }
-      result[i].netmask.s_addr = htonl (result[i].netmask.s_addr);
-      while (routeList[pos] != ';')
-        pos++;
-      pos++;
-      i++;
-      continue;
-    }
-    LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
-         &routeList[pos]);
-    GNUNET_free (result);
-    return NULL;                /* error */
-  }
-  if (pos < strlen (routeList))
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
-         &routeList[pos]);
-    GNUNET_free (result);
-    return NULL;                /* oops */
-  }
-  return result;                /* ok */
-}
-
-
-/**
- * Parse a network specification. The argument specifies
- * a list of networks. The format is
- * <tt>[network/netmask;]*</tt> (no whitespace, must be terminated
- * with a semicolon). The network must be given in colon-hex
- * notation.  The netmask must be given in CIDR notation (/16) or
- * can be omitted to specify a single host.
- * 
- * @param routeListX a string specifying the forbidden networks
- * @return the converted list, NULL if the synatx is flawed
- */
-static struct IPv6NetworkSet *
-parse_ipv6_specification (const char *routeListX)
-{
-  unsigned int count;
-  unsigned int i;
-  unsigned int len;
-  unsigned int pos;
-  int start;
-  int slash;
-  int ret;
-  char *routeList;
-  struct IPv6NetworkSet *result;
-  unsigned int bits;
-  unsigned int off;
-  int save;
-
-  if (NULL == routeListX)
-    return NULL;
-  len = strlen (routeListX);
-  if (0 == len)
-    return NULL;
-  routeList = GNUNET_strdup (routeListX);
-  count = 0;
-  for (i = 0; i < len; i++)
-    if (';' == routeList[i])
-      count++;
-  if (';' != routeList[len - 1])
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR,
-         _("Invalid network notation (does not end with ';': `%s')\n"),
-         routeList);
-    GNUNET_free (routeList);
-    return NULL;
-  }
-
-  result = GNUNET_malloc (sizeof (struct IPv6NetworkSet) * (count + 1));
-  i = 0;
-  pos = 0;
-  while (i < count)
-  {
-    start = pos;
-    while (';' != routeList[pos])
-      pos++;
-    slash = pos;
-    while ((slash >= start) && (routeList[slash] != '/'))
-      slash--;
-    if (slash < start)
-    {
-      memset (&result[i].netmask, 0xFF, sizeof (struct in6_addr));
-      slash = pos;
-    }
-    else
-    {
-      routeList[pos] = '\0';
-      ret = inet_pton (AF_INET6, &routeList[slash + 1], &result[i].netmask);
-      if (ret <= 0)
-      {
-        save = errno;
-        if ((1 != SSCANF (&routeList[slash + 1], "%u", &bits)) || (bits >= 128))
-        {
-          if (0 == ret)
-            LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong format `%s' for netmask\n"),
-                 &routeList[slash + 1]);
-          else
-          {
-            errno = save;
-            LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "inet_pton");
-          }
-          GNUNET_free (result);
-          GNUNET_free (routeList);
-          return NULL;
-        }
-        off = 0;
-        while (bits > 8)
-        {
-          result[i].netmask.s6_addr[off++] = 0xFF;
-          bits -= 8;
-        }
-        while (bits > 0)
-        {
-          result[i].netmask.s6_addr[off] =
-              (result[i].netmask.s6_addr[off] >> 1) + 0x80;
-          bits--;
-        }
-      }
-    }
-    routeList[slash] = '\0';
-    ret = inet_pton (AF_INET6, &routeList[start], &result[i].network);
-    if (ret <= 0)
-    {
-      if (0 == ret)
-        LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong format `%s' for network\n"),
-             &routeList[slash + 1]);
-      else
-        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "inet_pton");
-      GNUNET_free (result);
-      GNUNET_free (routeList);
-      return NULL;
-    }
-    pos++;
-    i++;
-  }
-  GNUNET_free (routeList);
-  return result;
-}
-
-
 /**
  * Check if the given IP address is in the list of IP addresses.
  *
  * @param list a list of networks
  * @param add the IP to check (in network byte order)
 /**
  * Check if the given IP address is in the list of IP addresses.
  *
  * @param list a list of networks
  * @param add the IP to check (in network byte order)
- * @return GNUNET_NO if the IP is not in the list, GNUNET_YES if it it is
+ * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
  */
 static int
  */
 static int
-check_ipv4_listed (const struct IPv4NetworkSet *list, const struct in_addr *add)
+check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
+                   const struct in_addr *add)
 {
   unsigned int i;
 
 {
   unsigned int i;
 
@@ -380,10 +77,11 @@ check_ipv4_listed (const struct IPv4NetworkSet *list, const struct in_addr *add)
  *
  * @param list a list of networks
  * @param ip the IP to check (in network byte order)
  *
  * @param list a list of networks
  * @param ip the IP to check (in network byte order)
- * @return GNUNET_NO if the IP is not in the list, GNUNET_YES if it it is
+ * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
  */
 static int
  */
 static int
-check_ipv6_listed (const struct IPv6NetworkSet *list, const struct in6_addr *ip)
+check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
+                   const struct in6_addr *ip)
 {
   unsigned int i;
   unsigned int j;
 {
   unsigned int i;
   unsigned int j;
@@ -436,7 +134,7 @@ struct GNUNET_SERVICE_Context
   /**
    * Name of our service.
    */
   /**
    * Name of our service.
    */
-  const char *serviceName;
+  const char *service_name;
 
   /**
    * Main service-specific task to run.
 
   /**
    * Main service-specific task to run.
@@ -444,31 +142,31 @@ struct GNUNET_SERVICE_Context
   GNUNET_SERVICE_Main task;
 
   /**
   GNUNET_SERVICE_Main task;
 
   /**
-   * Closure for task.
+   * Closure for @e task.
    */
   void *task_cls;
 
   /**
    * IPv4 addresses that are not allowed to connect.
    */
    */
   void *task_cls;
 
   /**
    * IPv4 addresses that are not allowed to connect.
    */
-  struct IPv4NetworkSet *v4_denied;
+  struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
 
   /**
    * IPv6 addresses that are not allowed to connect.
    */
 
   /**
    * IPv6 addresses that are not allowed to connect.
    */
-  struct IPv6NetworkSet *v6_denied;
+  struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
 
   /**
    * IPv4 addresses that are allowed to connect (if not
    * set, all are allowed).
    */
 
   /**
    * IPv4 addresses that are allowed to connect (if not
    * set, all are allowed).
    */
-  struct IPv4NetworkSet *v4_allowed;
+  struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
 
   /**
    * IPv6 addresses that are allowed to connect (if not
    * set, all are allowed).
    */
 
   /**
    * IPv6 addresses that are allowed to connect (if not
    * set, all are allowed).
    */
-  struct IPv6NetworkSet *v6_allowed;
+  struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
 
   /**
    * My (default) message handlers.  Adjusted copy
 
   /**
    * My (default) message handlers.  Adjusted copy
@@ -486,6 +184,11 @@ struct GNUNET_SERVICE_Context
    */
   struct GNUNET_NETWORK_Handle **lsocks;
 
    */
   struct GNUNET_NETWORK_Handle **lsocks;
 
+  /**
+   * Task ID of the shutdown task.
+   */
+  struct GNUNET_SCHEDULER_Task * shutdown_task;
+
   /**
    * Idle timeout for server.
    */
   /**
    * Idle timeout for server.
    */
@@ -511,17 +214,17 @@ struct GNUNET_SERVICE_Context
 
   /**
    * Do we require a matching UID for UNIX domain socket connections?
 
   /**
    * Do we require a matching UID for UNIX domain socket connections?
-   * GNUNET_NO means that the UID does not have to match (however,
-   * "match_gid" may still impose other access control checks).
+   * #GNUNET_NO means that the UID does not have to match (however,
+   * @e match_gid may still impose other access control checks).
    */
   int match_uid;
 
   /**
    * Do we require a matching GID for UNIX domain socket connections?
    */
   int match_uid;
 
   /**
    * Do we require a matching GID for UNIX domain socket connections?
-   * Ignored if "match_uid" is GNUNET_YES.  Note that this is about
+   * Ignored if @e match_uid is #GNUNET_YES.  Note that this is about
    * checking that the client's UID is in our group OR that the
    * checking that the client's UID is in our group OR that the
-   * client's GID is our GID.  If both "match_gid" and "match_uid" are
-   * "GNUNET_NO", all users on the local system have access.
+   * client's GID is our GID.  If both "match_gid" and @e match_uid are
+   * #GNUNET_NO, all users on the local system have access.
    */
   int match_gid;
 
    */
   int match_gid;
 
@@ -536,11 +239,12 @@ struct GNUNET_SERVICE_Context
 /* ****************** message handlers ****************** */
 
 /**
 /* ****************** message handlers ****************** */
 
 /**
+ * Send a 'TEST' message back to the client.
  *
  *
- * @param cls
- * @param size
- * @param buf
- * @return 
+ * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to
+ * @param size number of bytes available in 'buf'
+ * @param buf where to copy the message
+ * @return number of bytes written to 'buf'
  */
 static size_t
 write_test (void *cls, size_t size, void *buf)
  */
 static size_t
 write_test (void *cls, size_t size, void *buf)
@@ -604,7 +308,7 @@ static const struct GNUNET_SERVER_MessageHandler defhandlers[] = {
  * @param uc credentials, if available, otherwise NULL
  * @param addr address
  * @param addrlen length of address
  * @param uc credentials, if available, otherwise NULL
  * @param addr address
  * @param addrlen length of address
- * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
+ * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR
  *   for unknown address family (will be denied).
  */
 static int
  *   for unknown address family (will be denied).
  */
 static int
@@ -636,54 +340,7 @@ check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
     break;
 #ifndef WINDOWS
   case AF_UNIX:
     break;
 #ifndef WINDOWS
   case AF_UNIX:
-    ret = GNUNET_OK;            /* always OK for now */
-    if (GNUNET_YES == sctx->match_uid) 
-    {
-      /* UID match required */
-      ret = (NULL != uc) && (uc->uid == geteuid ());
-    }
-    else if ( (GNUNET_YES == sctx->match_gid) &&
-             ( (NULL == uc) || (uc->uid != geteuid ()) ) )
-    {
-      /* group match required and UID does not match */
-      if (NULL == uc) 
-      {
-       /* no credentials, group match not possible */
-       ret = GNUNET_NO;
-      }
-      else
-      {
-       struct group *grp;
-       unsigned int i;
-
-       if (uc->gid != getegid())
-       {
-         /* default group did not match, but maybe the user is in our group, let's check */
-         grp = getgrgid (getegid ());
-         if (NULL == grp)
-         {
-           GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "getgrgid");
-           return GNUNET_NO;
-         }
-         ret = GNUNET_NO;
-         for (i=0; NULL != grp->gr_mem[i]; i++)
-         {
-           struct passwd *nam = getpwnam (grp->gr_mem[i]);
-           if (NULL == nam)
-             continue; /* name in group that is not in user DB !? */
-           if (nam->pw_uid == uc->uid)
-           {
-             /* yes, uid is in our group, allow! */
-             ret = GNUNET_YES;
-             break;
-           }
-         }
-       }
-      }
-    }
-    if (GNUNET_NO == ret)
-      LOG (GNUNET_ERROR_TYPE_WARNING, _("Access denied to UID %d / GID %d\n"),
-           (NULL == uc) ? -1 : uc->uid, (NULL == uc) ? -1 : uc->gid);
+    ret = GNUNET_OK;            /* controlled using file-system ACL now */
     break;
 #endif
   default:
     break;
 #endif
   default:
@@ -694,9 +351,9 @@ check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
   if (GNUNET_OK != ret)
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
   if (GNUNET_OK != ret)
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
-         _("Access from `%s' denied to service `%s'\n"), 
+         _("Access from `%s' denied to service `%s'\n"),
         GNUNET_a2s (addr, addrlen),
         GNUNET_a2s (addr, addrlen),
-         sctx->serviceName);
+         sctx->service_name);
   }
   return ret;
 }
   }
   return ret;
 }
@@ -715,7 +372,7 @@ get_pid_file_name (struct GNUNET_SERVICE_Context *sctx)
   char *pif;
 
   if (GNUNET_OK !=
   char *pif;
 
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->serviceName,
+      GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
                                                "PIDFILE", &pif))
     return NULL;
   return pif;
                                                "PIDFILE", &pif))
     return NULL;
   return pif;
@@ -725,28 +382,33 @@ get_pid_file_name (struct GNUNET_SERVICE_Context *sctx)
 /**
  * Parse an IPv4 access control list.
  *
 /**
  * Parse an IPv4 access control list.
  *
- * @param ret
- * @param sctx
- * @param option
- * @return 
+ * @param ret location where to write the ACL (set)
+ * @param sctx service context to use to get the configuration
+ * @param option name of the ACL option to parse
+ * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
+ *         no ACL configured)
  */
 static int
  */
 static int
-process_acl4 (struct IPv4NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx,
+process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
+              struct GNUNET_SERVICE_Context *sctx,
               const char *option)
 {
   char *opt;
 
               const char *option)
 {
   char *opt;
 
-  if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->serviceName, option))
+  if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
+  {
+    *ret = NULL;
     return GNUNET_OK;
     return GNUNET_OK;
+  }
   GNUNET_break (GNUNET_OK ==
                 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
   GNUNET_break (GNUNET_OK ==
                 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
-                                                       sctx->serviceName,
+                                                       sctx->service_name,
                                                        option, &opt));
                                                        option, &opt));
-  if (NULL == (*ret = parse_ipv4_specification (opt)))
+  if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
          _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
          _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
-         opt, sctx->serviceName, option);
+         opt, sctx->service_name, option);
     GNUNET_free (opt);
     return GNUNET_SYSERR;
   }
     GNUNET_free (opt);
     return GNUNET_SYSERR;
   }
@@ -758,28 +420,33 @@ process_acl4 (struct IPv4NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx,
 /**
  * Parse an IPv6 access control list.
  *
 /**
  * Parse an IPv6 access control list.
  *
- * @param ret
- * @param sctx
- * @param option
- * @return
+ * @param ret location where to write the ACL (set)
+ * @param sctx service context to use to get the configuration
+ * @param option name of the ACL option to parse
+ * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
+ *         no ACL configured)
  */
 static int
  */
 static int
-process_acl6 (struct IPv6NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx,
+process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
+              struct GNUNET_SERVICE_Context *sctx,
               const char *option)
 {
   char *opt;
 
               const char *option)
 {
   char *opt;
 
-  if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->serviceName, option))
+  if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
+  {
+    *ret = NULL;
     return GNUNET_OK;
     return GNUNET_OK;
+  }
   GNUNET_break (GNUNET_OK ==
                 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
   GNUNET_break (GNUNET_OK ==
                 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
-                                                       sctx->serviceName,
+                                                       sctx->service_name,
                                                        option, &opt));
                                                        option, &opt));
-  if (NULL == (*ret = parse_ipv6_specification (opt)))
+  if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
          _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
          _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
-         opt, sctx->serviceName, option);
+         opt, sctx->service_name, option);
     GNUNET_free (opt);
     return GNUNET_SYSERR;
   }
     GNUNET_free (opt);
     return GNUNET_SYSERR;
   }
@@ -795,31 +462,30 @@ process_acl6 (struct IPv6NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx,
  * @param saddrs array to update
  * @param saddrlens where to store the address length
  * @param unixpath path to add
  * @param saddrs array to update
  * @param saddrlens where to store the address length
  * @param unixpath path to add
+ * @param abstract #GNUNET_YES to add an abstract UNIX domain socket.  This
+ *          parameter is ignore on systems other than LINUX
  */
 static void
  */
 static void
-add_unixpath (struct sockaddr **saddrs, socklen_t * saddrlens,
-              const char *unixpath)
+add_unixpath (struct sockaddr **saddrs,
+              socklen_t *saddrlens,
+              const char *unixpath,
+              int abstract)
 {
 #ifdef AF_UNIX
   struct sockaddr_un *un;
 {
 #ifdef AF_UNIX
   struct sockaddr_un *un;
-  size_t slen;
 
 
-  un = GNUNET_malloc (sizeof (struct sockaddr_un));
+  un = GNUNET_new (struct sockaddr_un);
   un->sun_family = AF_UNIX;
   un->sun_family = AF_UNIX;
-  slen = strlen (unixpath) + 1;
-  if (slen >= sizeof (un->sun_path))
-    slen = sizeof (un->sun_path) - 1;
-  memcpy (un->sun_path, unixpath, slen);
-  un->sun_path[slen] = '\0';
-  slen = sizeof (struct sockaddr_un);
-#if LINUX
-  un->sun_path[0] = '\0';
+  strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
+#ifdef LINUX
+  if (GNUNET_YES == abstract)
+    un->sun_path[0] = '\0';
 #endif
 #if HAVE_SOCKADDR_IN_SIN_LEN
 #endif
 #if HAVE_SOCKADDR_IN_SIN_LEN
-  un->sun_len = (u_char) slen;
+  un->sun_len = (u_char) sizeof (struct sockaddr_un);
 #endif
   *saddrs = (struct sockaddr *) un;
 #endif
   *saddrs = (struct sockaddr *) un;
-  *saddrlens = slen;
+  *saddrlens = sizeof (struct sockaddr_un);
 #else
   /* this function should never be called
    * unless AF_UNIX is defined! */
 #else
   /* this function should never be called
    * unless AF_UNIX is defined! */
@@ -832,26 +498,26 @@ add_unixpath (struct sockaddr **saddrs, socklen_t * saddrlens,
  * Get the list of addresses that a server for the given service
  * should bind to.
  *
  * Get the list of addresses that a server for the given service
  * should bind to.
  *
- * @param serviceName name of the service
+ * @param service_name name of the service
  * @param cfg configuration (which specifies the addresses)
  * @param addrs set (call by reference) to an array of pointers to the
  *              addresses the server should bind to and listen on; the
  *              array will be NULL-terminated (on success)
  * @param addr_lens set (call by reference) to an array of the lengths
  * @param cfg configuration (which specifies the addresses)
  * @param addrs set (call by reference) to an array of pointers to the
  *              addresses the server should bind to and listen on; the
  *              array will be NULL-terminated (on success)
  * @param addr_lens set (call by reference) to an array of the lengths
- *              of the respective 'struct sockaddr' struct in the 'addrs'
+ *              of the respective `struct sockaddr` struct in the @a addrs
  *              array (on success)
  * @return number of addresses found on success,
  *              array (on success)
  * @return number of addresses found on success,
- *              GNUNET_SYSERR if the configuration
+ *              #GNUNET_SYSERR if the configuration
  *              did not specify reasonable finding information or
  *              if it specified a hostname that could not be resolved;
  *              did not specify reasonable finding information or
  *              if it specified a hostname that could not be resolved;
- *              GNUNET_NO if the number of addresses configured is
- *              zero (in this case, '*addrs' and '*addr_lens' will be
+ *              #GNUNET_NO if the number of addresses configured is
+ *              zero (in this case, `*addrs` and `*addr_lens` will be
  *              set to NULL).
  */
 int
  *              set to NULL).
  */
 int
-GNUNET_SERVICE_get_server_addresses (const char *serviceName,
-                                     const struct GNUNET_CONFIGURATION_Handle
-                                     *cfg, struct sockaddr ***addrs,
+GNUNET_SERVICE_get_server_addresses (const char *service_name,
+                                     const struct GNUNET_CONFIGURATION_Handle *cfg,
+                                     struct sockaddr ***addrs,
                                      socklen_t ** addr_lens)
 {
   int disablev6;
                                      socklen_t ** addr_lens)
 {
   int disablev6;
@@ -865,6 +531,7 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
   unsigned int i;
   int resi;
   int ret;
   unsigned int i;
   int resi;
   int ret;
+  int abstract;
   struct sockaddr **saddrs;
   socklen_t *saddrlens;
   char *hostname;
   struct sockaddr **saddrs;
   socklen_t *saddrlens;
   char *hostname;
@@ -872,17 +539,17 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
   *addrs = NULL;
   *addr_lens = NULL;
   desc = NULL;
   *addrs = NULL;
   *addr_lens = NULL;
   desc = NULL;
-  if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "DISABLEV6"))
+  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
   {
     if (GNUNET_SYSERR ==
         (disablev6 =
   {
     if (GNUNET_SYSERR ==
         (disablev6 =
-         GNUNET_CONFIGURATION_get_value_yesno (cfg, serviceName, "DISABLEV6")))
+         GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
       return GNUNET_SYSERR;
   }
   else
     disablev6 = GNUNET_NO;
 
       return GNUNET_SYSERR;
   }
   else
     disablev6 = GNUNET_NO;
 
-  if (!disablev6)
+  if (! disablev6)
   {
     /* probe IPv6 support */
     desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
   {
     /* probe IPv6 support */
     desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
@@ -895,9 +562,8 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
         return GNUNET_SYSERR;
       }
       LOG (GNUNET_ERROR_TYPE_INFO,
         return GNUNET_SYSERR;
       }
       LOG (GNUNET_ERROR_TYPE_INFO,
-           _
-           ("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
-           serviceName, STRERROR (errno));
+           _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
+           service_name, STRERROR (errno));
       disablev6 = GNUNET_YES;
     }
     else
       disablev6 = GNUNET_YES;
     }
     else
@@ -908,35 +574,41 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
   }
 
   port = 0;
   }
 
   port = 0;
-  if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "PORT"))
+  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
   {
   {
-    GNUNET_break (GNUNET_OK ==
-                  GNUNET_CONFIGURATION_get_value_number (cfg, serviceName,
-                                                         "PORT", &port));
+    if (GNUNET_OK !=
+       GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
+                                              "PORT", &port))
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Require valid port number for service `%s' in configuration!\n"),
+           service_name);
+    }
     if (port > 65535)
     {
       LOG (GNUNET_ERROR_TYPE_ERROR,
            _("Require valid port number for service `%s' in configuration!\n"),
     if (port > 65535)
     {
       LOG (GNUNET_ERROR_TYPE_ERROR,
            _("Require valid port number for service `%s' in configuration!\n"),
-           serviceName);
+           service_name);
       return GNUNET_SYSERR;
     }
   }
 
       return GNUNET_SYSERR;
     }
   }
 
-  if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "BINDTO"))
+  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
   {
     GNUNET_break (GNUNET_OK ==
   {
     GNUNET_break (GNUNET_OK ==
-                  GNUNET_CONFIGURATION_get_value_string (cfg, serviceName,
+                  GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
                                                          "BINDTO", &hostname));
   }
   else
     hostname = NULL;
 
   unixpath = NULL;
                                                          "BINDTO", &hostname));
   }
   else
     hostname = NULL;
 
   unixpath = NULL;
+  abstract = GNUNET_NO;
 #ifdef AF_UNIX
   if ((GNUNET_YES ==
 #ifdef AF_UNIX
   if ((GNUNET_YES ==
-       GNUNET_CONFIGURATION_have_value (cfg, serviceName, "UNIXPATH")) &&
+       GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
       (GNUNET_OK ==
       (GNUNET_OK ==
-       GNUNET_CONFIGURATION_get_value_string (cfg, serviceName, "UNIXPATH",
+       GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
                                               &unixpath)) &&
       (0 < strlen (unixpath)))
   {
                                               &unixpath)) &&
       (0 < strlen (unixpath)))
   {
@@ -947,12 +619,28 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
     {
       LOG (GNUNET_ERROR_TYPE_WARNING,
            _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
     {
       LOG (GNUNET_ERROR_TYPE_WARNING,
            _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
-           sizeof (s_un.sun_path));
-      GNUNET_free_non_null (hostname);
-      GNUNET_free (unixpath);
-      return GNUNET_SYSERR;
+           (unsigned long long) sizeof (s_un.sun_path));
+      unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
+      LOG (GNUNET_ERROR_TYPE_INFO,
+          _("Using `%s' instead\n"),
+           unixpath);
     }
     }
-
+#ifdef LINUX
+    abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                                     "TESTING",
+                                                     "USE_ABSTRACT_SOCKETS");
+    if (GNUNET_SYSERR == abstract)
+      abstract = GNUNET_NO;
+#endif
+    if ((GNUNET_YES != abstract)
+        && (GNUNET_OK !=
+            GNUNET_DISK_directory_create_for_file (unixpath)))
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+                               "mkdir",
+                               unixpath);
+  }
+  if (NULL != unixpath)
+  {
     desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
     if (NULL == desc)
     {
     desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
     if (NULL == desc)
     {
@@ -965,9 +653,9 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
         return GNUNET_SYSERR;
       }
       LOG (GNUNET_ERROR_TYPE_INFO,
         return GNUNET_SYSERR;
       }
       LOG (GNUNET_ERROR_TYPE_INFO,
-           _
-           ("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
-           serviceName, STRERROR (errno));
+           _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
+           service_name,
+           STRERROR (errno));
       GNUNET_free (unixpath);
       unixpath = NULL;
     }
       GNUNET_free (unixpath);
       unixpath = NULL;
     }
@@ -982,9 +670,8 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
   if ((0 == port) && (NULL == unixpath))
   {
     LOG (GNUNET_ERROR_TYPE_ERROR,
   if ((0 == port) && (NULL == unixpath))
   {
     LOG (GNUNET_ERROR_TYPE_ERROR,
-         _
-         ("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
-         serviceName);
+         _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
+         service_name);
     GNUNET_free_non_null (hostname);
     return GNUNET_SYSERR;
   }
     GNUNET_free_non_null (hostname);
     return GNUNET_SYSERR;
   }
@@ -992,7 +679,7 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
   {
     saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
     saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
   {
     saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
     saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
-    add_unixpath (saddrs, saddrlens, unixpath);
+    add_unixpath (saddrs, saddrlens, unixpath, abstract);
     GNUNET_free_non_null (unixpath);
     GNUNET_free_non_null (hostname);
     *addrs = saddrs;
     GNUNET_free_non_null (unixpath);
     GNUNET_free_non_null (hostname);
     *addrs = saddrs;
@@ -1003,15 +690,19 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
   if (NULL != hostname)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
   if (NULL != hostname)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Resolving `%s' since that is where `%s' will bind to.\n", hostname,
-         serviceName);
+         "Resolving `%s' since that is where `%s' will bind to.\n",
+         hostname,
+         service_name);
     memset (&hints, 0, sizeof (struct addrinfo));
     if (disablev6)
       hints.ai_family = AF_INET;
     memset (&hints, 0, sizeof (struct addrinfo));
     if (disablev6)
       hints.ai_family = AF_INET;
+    hints.ai_protocol = IPPROTO_TCP;
     if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
     if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
-        (res == NULL))
+        (NULL == res))
     {
     {
-      LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"), hostname,
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Failed to resolve `%s': %s\n"),
+           hostname,
            gai_strerror (ret));
       GNUNET_free (hostname);
       GNUNET_free_non_null (unixpath);
            gai_strerror (ret));
       GNUNET_free (hostname);
       GNUNET_free_non_null (unixpath);
@@ -1028,8 +719,10 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
     }
     if (0 == i)
     {
     }
     if (0 == i)
     {
-      LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to find %saddress for `%s'.\n"),
-           disablev6 ? "IPv4 " : "", hostname);
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Failed to find %saddress for `%s'.\n"),
+           disablev6 ? "IPv4 " : "",
+           hostname);
       freeaddrinfo (res);
       GNUNET_free (hostname);
       GNUNET_free_non_null (unixpath);
       freeaddrinfo (res);
       GNUNET_free (hostname);
       GNUNET_free_non_null (unixpath);
@@ -1043,7 +736,7 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
     i = 0;
     if (NULL != unixpath)
     {
     i = 0;
     if (NULL != unixpath)
     {
-      add_unixpath (saddrs, saddrlens, unixpath);
+      add_unixpath (saddrs, saddrlens, unixpath, abstract);
       i++;
     }
     next = res;
       i++;
     }
     next = res;
@@ -1057,7 +750,7 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
       if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
         continue;               /* huh? */
       LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
       if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
         continue;               /* huh? */
       LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
-           serviceName, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
+           service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
       if (AF_INET == pos->ai_family)
       {
         GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
       if (AF_INET == pos->ai_family)
       {
         GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
@@ -1095,7 +788,7 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
       if (NULL != unixpath)
       {
       saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
       if (NULL != unixpath)
       {
-        add_unixpath (saddrs, saddrlens, unixpath);
+        add_unixpath (saddrs, saddrlens, unixpath, abstract);
         i++;
       }
       saddrlens[i] = sizeof (struct sockaddr_in);
         i++;
       }
       saddrlens[i] = sizeof (struct sockaddr_in);
@@ -1117,7 +810,7 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
       i = 0;
       if (NULL != unixpath)
       {
       i = 0;
       if (NULL != unixpath)
       {
-        add_unixpath (saddrs, saddrlens, unixpath);
+        add_unixpath (saddrs, saddrlens, unixpath, abstract);
         i++;
       }
       saddrlens[i] = sizeof (struct sockaddr_in6);
         i++;
       }
       saddrlens[i] = sizeof (struct sockaddr_in6);
@@ -1146,11 +839,11 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
 
 #ifdef MINGW
 /**
 
 #ifdef MINGW
 /**
+ * Read listen sockets from the parent process (ARM).
  *
  *
- *
- * @param sctx 
- * @return GNUNET_YES if ok, GNUNET_NO if not ok (must bind yourself),
- * and GNUNET_SYSERR on error.
+ * @param sctx service context to initialize
+ * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself),
+ * and #GNUNET_SYSERR on error.
  */
 static int
 receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
  */
 static int
 receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
@@ -1170,7 +863,7 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
    */
   lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
   if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
    */
   lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
   if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
-    return GNUNET_NO
+    return GNUNET_NO;
   fail = 1;
   do
   {
   fail = 1;
   do
   {
@@ -1243,8 +936,8 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
  * - REJECT_FROM  (disallow allow connections from specified IPv4 subnets)
  * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
  *
  * - REJECT_FROM  (disallow allow connections from specified IPv4 subnets)
  * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
  *
- * @param sctx
- * @return GNUNET_OK if configuration succeeded
+ * @param sctx service context to initialize
+ * @return #GNUNET_OK if configuration succeeded
  */
 static int
 setup_service (struct GNUNET_SERVICE_Context *sctx)
  */
 static int
 setup_service (struct GNUNET_SERVICE_Context *sctx)
@@ -1253,22 +946,20 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
   int tolerant;
 
 #ifndef MINGW
   int tolerant;
 
 #ifndef MINGW
-  const char *lpid;
-  unsigned int pid;
   const char *nfds;
   unsigned int cnt;
   int flags;
 #endif
 
   const char *nfds;
   unsigned int cnt;
   int flags;
 #endif
 
-  if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->serviceName, "TIMEOUT"))
+  if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TIMEOUT"))
   {
     if (GNUNET_OK !=
   {
     if (GNUNET_OK !=
-        GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->serviceName,
+        GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name,
                                              "TIMEOUT", &idleout))
     {
       LOG (GNUNET_ERROR_TYPE_ERROR,
            _("Specified value for `%s' of service `%s' is invalid\n"),
                                              "TIMEOUT", &idleout))
     {
       LOG (GNUNET_ERROR_TYPE_ERROR,
            _("Specified value for `%s' of service `%s' is invalid\n"),
-           "TIMEOUT", sctx->serviceName);
+           "TIMEOUT", sctx->service_name);
       return GNUNET_SYSERR;
     }
     sctx->timeout = idleout;
       return GNUNET_SYSERR;
     }
     sctx->timeout = idleout;
@@ -1277,16 +968,16 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
     sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
 
   if (GNUNET_CONFIGURATION_have_value
     sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
 
   if (GNUNET_CONFIGURATION_have_value
-      (sctx->cfg, sctx->serviceName, "TOLERANT"))
+      (sctx->cfg, sctx->service_name, "TOLERANT"))
   {
     if (GNUNET_SYSERR ==
         (tolerant =
   {
     if (GNUNET_SYSERR ==
         (tolerant =
-         GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->serviceName,
+         GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
                                                "TOLERANT")))
     {
       LOG (GNUNET_ERROR_TYPE_ERROR,
            _("Specified value for `%s' of service `%s' is invalid\n"),
                                                "TOLERANT")))
     {
       LOG (GNUNET_ERROR_TYPE_ERROR,
            _("Specified value for `%s' of service `%s' is invalid\n"),
-           "TOLERANT", sctx->serviceName);
+           "TOLERANT", sctx->service_name);
       return GNUNET_SYSERR;
     }
   }
       return GNUNET_SYSERR;
     }
   }
@@ -1295,9 +986,7 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
 
 #ifndef MINGW
   errno = 0;
 
 #ifndef MINGW
   errno = 0;
-  if ((NULL != (lpid = getenv ("LISTEN_PID"))) &&
-      (1 == SSCANF (lpid, "%u", &pid)) && (getpid () == (pid_t) pid) &&
-      (NULL != (nfds = getenv ("LISTEN_FDS"))) &&
+  if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
       (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
       (cnt + 4 < FD_SETSIZE))
   {
       (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
       (cnt + 4 < FD_SETSIZE))
   {
@@ -1322,7 +1011,6 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
         break;
       }
     }
         break;
       }
     }
-    unsetenv ("LISTEN_PID");
     unsetenv ("LISTEN_FDS");
   }
 #else
     unsetenv ("LISTEN_FDS");
   }
 #else
@@ -1335,15 +1023,15 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
 
   if ((NULL == sctx->lsocks) &&
       (GNUNET_SYSERR ==
 
   if ((NULL == sctx->lsocks) &&
       (GNUNET_SYSERR ==
-       GNUNET_SERVICE_get_server_addresses (sctx->serviceName, sctx->cfg,
+       GNUNET_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg,
                                             &sctx->addrs, &sctx->addrlens)))
     return GNUNET_SYSERR;
   sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
   sctx->match_uid =
                                             &sctx->addrs, &sctx->addrlens)))
     return GNUNET_SYSERR;
   sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
   sctx->match_uid =
-      GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->serviceName,
+      GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
                                             "UNIX_MATCH_UID");
   sctx->match_gid =
                                             "UNIX_MATCH_UID");
   sctx->match_gid =
-      GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->serviceName,
+      GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
                                             "UNIX_MATCH_GID");
   process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
   process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
                                             "UNIX_MATCH_GID");
   process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
   process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
@@ -1358,8 +1046,8 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
  * Get the name of the user that'll be used
  * to provide the service.
  *
  * Get the name of the user that'll be used
  * to provide the service.
  *
- * @param sctx
- * @return 
+ * @param sctx service context
+ * @return value of the 'USERNAME' option
  */
 static char *
 get_user_name (struct GNUNET_SERVICE_Context *sctx)
  */
 static char *
 get_user_name (struct GNUNET_SERVICE_Context *sctx)
@@ -1367,18 +1055,19 @@ get_user_name (struct GNUNET_SERVICE_Context *sctx)
   char *un;
 
   if (GNUNET_OK !=
   char *un;
 
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->serviceName,
+      GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
                                                "USERNAME", &un))
     return NULL;
   return un;
 }
 
                                                "USERNAME", &un))
     return NULL;
   return un;
 }
 
+
 /**
  * Write PID file.
  *
 /**
  * Write PID file.
  *
- * @param sctx
- * @param pid
- * @return 
+ * @param sctx service context
+ * @param pid PID to write (should be equal to 'getpid()'
+ * @return  #GNUNET_OK on success (including no work to be done)
  */
 static int
 write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
  */
 static int
 write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
@@ -1401,7 +1090,7 @@ write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
   {
     /* we get to create a directory -- and claim it
      * as ours! */
   {
     /* we get to create a directory -- and claim it
      * as ours! */
-    GNUNET_DISK_directory_create (rdir);
+    (void) GNUNET_DISK_directory_create (rdir);
     if ((NULL != user) && (0 < strlen (user)))
       GNUNET_DISK_file_change_owner (rdir, user);
   }
     if ((NULL != user) && (0 < strlen (user)))
       GNUNET_DISK_file_change_owner (rdir, user);
   }
@@ -1434,19 +1123,23 @@ write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
 
 
 /**
 
 
 /**
- * Task run during shutdown.
+ * Task run during shutdown.  Stops the server/service.
  *
  *
- * @param cls unused
+ * @param cls the `struct GNUNET_SERVICE_Context`
  * @param tc unused
  */
 static void
  * @param tc unused
  */
 static void
-shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+shutdown_task (void *cls,
+               const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 {
-  struct GNUNET_SERVER_Handle *server = cls;
+  struct GNUNET_SERVICE_Context *service = cls;
+  struct GNUNET_SERVER_Handle *server = service->server;
 
 
-  // FIXME: we should not unconditionally destroy the server
-  // here (often only stopping 'listening' would be better)
-  GNUNET_SERVER_destroy (server);
+  service->shutdown_task = NULL;
+  if (0 != (service->options & GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN))
+    GNUNET_SERVER_stop_listening (server);
+  else
+    GNUNET_SERVER_destroy (server);
 }
 
 
 }
 
 
@@ -1462,36 +1155,46 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct GNUNET_SERVICE_Context *sctx = cls;
   unsigned int i;
 
   struct GNUNET_SERVICE_Context *sctx = cls;
   unsigned int i;
 
+  if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+    return;
+  (void) GNUNET_SPEEDUP_start_ (sctx->cfg);
   GNUNET_RESOLVER_connect (sctx->cfg);
   if (NULL != sctx->lsocks)
   GNUNET_RESOLVER_connect (sctx->cfg);
   if (NULL != sctx->lsocks)
-    sctx->server =
-        GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
+    sctx->server
+      = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
                                            sctx->timeout, sctx->require_found);
   else
                                            sctx->timeout, sctx->require_found);
   else
-    sctx->server =
-        GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
+    sctx->server
+      = GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
                               sctx->timeout, sctx->require_found);
   if (NULL == sctx->server)
   {
     if (NULL != sctx->addrs)
                               sctx->timeout, sctx->require_found);
   if (NULL == sctx->server)
   {
     if (NULL != sctx->addrs)
-    {
-      i = 0;
-      while (NULL != sctx->addrs[i])
-      {
-        LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to start `%s' at `%s'\n"),
-             sctx->serviceName, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
-        i++;
-      }
-    }
+      for (i = 0; NULL != sctx->addrs[i]; i++)
+        LOG (GNUNET_ERROR_TYPE_INFO,
+             _("Failed to start `%s' at `%s'\n"),
+             sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
     sctx->ret = GNUNET_SYSERR;
     return;
   }
     sctx->ret = GNUNET_SYSERR;
     return;
   }
+#ifndef WINDOWS
+  if (NULL != sctx->addrs)
+    for (i = 0; NULL != sctx->addrs[i]; i++)
+      if ((AF_UNIX == sctx->addrs[i]->sa_family)
+          && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
+        GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
+                                     sctx->match_uid,
+                                     sctx->match_gid);
+#endif
+
+
   if (0 == (sctx->options & GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN))
   {
     /* install a task that will kill the server
      * process if the scheduler ever gets a shutdown signal */
   if (0 == (sctx->options & GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN))
   {
     /* install a task that will kill the server
      * process if the scheduler ever gets a shutdown signal */
-    GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
-                                  sctx->server);
+    sctx->shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+                                                        &shutdown_task,
+                                                       sctx);
   }
   sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
   memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
   }
   sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
   memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
@@ -1512,7 +1215,7 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     while (NULL != sctx->addrs[i])
     {
       LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
     while (NULL != sctx->addrs[i])
     {
       LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
-           sctx->serviceName, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
+           sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
       i++;
     }
   }
       i++;
     }
   }
@@ -1524,7 +1227,7 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  * Detach from terminal.
  *
  * @param sctx service context
  * Detach from terminal.
  *
  * @param sctx service context
- * @return
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 static int
 detach_terminal (struct GNUNET_SERVICE_Context *sctx)
  */
 static int
 detach_terminal (struct GNUNET_SERVICE_Context *sctx)
@@ -1605,7 +1308,7 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
  * Set user ID.
  *
  * @param sctx service context
  * Set user ID.
  *
  * @param sctx service context
- * @return
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 static int
 set_user_id (struct GNUNET_SERVICE_Context *sctx)
  */
 static int
 set_user_id (struct GNUNET_SERVICE_Context *sctx)
@@ -1672,22 +1375,26 @@ pid_file_delete (struct GNUNET_SERVICE_Context *sctx)
  *
  * @param argc number of command line arguments
  * @param argv command line arguments
  *
  * @param argc number of command line arguments
  * @param argv command line arguments
- * @param serviceName our service name
- * @param opt service options
+ * @param service_name our service name
+ * @param options service options
  * @param task main task of the service
  * @param task main task of the service
- * @param task_cls closure for task
- * @return GNUNET_SYSERR on error, GNUNET_OK
+ * @param task_cls closure for @a task
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK
  *         if we shutdown nicely
  */
 int
  *         if we shutdown nicely
  */
 int
-GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName,
-                    enum GNUNET_SERVICE_Options opt, GNUNET_SERVICE_Main task,
+GNUNET_SERVICE_run (int argc, char *const *argv,
+                    const char *service_name,
+                    enum GNUNET_SERVICE_Options options,
+                    GNUNET_SERVICE_Main task,
                     void *task_cls)
 {
 #define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0)
 
   int err;
                     void *task_cls)
 {
 #define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0)
 
   int err;
+  int ret;
   char *cfg_fn;
   char *cfg_fn;
+  char *opt_cfg_fn;
   char *loglev;
   char *logfile;
   int do_daemonize;
   char *loglev;
   char *logfile;
   int do_daemonize;
@@ -1697,40 +1404,79 @@ GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName,
   long long clock_offset;
   struct GNUNET_SERVICE_Context sctx;
   struct GNUNET_CONFIGURATION_Handle *cfg;
   long long clock_offset;
   struct GNUNET_SERVICE_Context sctx;
   struct GNUNET_CONFIGURATION_Handle *cfg;
+  const char *xdg;
 
   struct GNUNET_GETOPT_CommandLineOption service_options[] = {
 
   struct GNUNET_GETOPT_CommandLineOption service_options[] = {
-    GNUNET_GETOPT_OPTION_CFG_FILE (&cfg_fn),
+    GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_fn),
     {'d', "daemonize", NULL,
      gettext_noop ("do daemonize (detach from terminal)"), 0,
      GNUNET_GETOPT_set_one, &do_daemonize},
     GNUNET_GETOPT_OPTION_HELP (NULL),
     GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
     GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
     {'d', "daemonize", NULL,
      gettext_noop ("do daemonize (detach from terminal)"), 0,
      GNUNET_GETOPT_set_one, &do_daemonize},
     GNUNET_GETOPT_OPTION_HELP (NULL),
     GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
     GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
-    GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION),
+    GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
     GNUNET_GETOPT_OPTION_END
   };
   err = 1;
   do_daemonize = 0;
   logfile = NULL;
   loglev = NULL;
     GNUNET_GETOPT_OPTION_END
   };
   err = 1;
   do_daemonize = 0;
   logfile = NULL;
   loglev = NULL;
-  cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE);
+  opt_cfg_fn = NULL;
+  xdg = getenv ("XDG_CONFIG_HOME");
+  if (NULL != xdg)
+    GNUNET_asprintf (&cfg_fn,
+                     "%s%s%s",
+                     xdg,
+                     DIR_SEPARATOR_STR,
+                     "gnunet.conf");
+  else
+    cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE);
   memset (&sctx, 0, sizeof (sctx));
   memset (&sctx, 0, sizeof (sctx));
-  sctx.options = opt;
+  sctx.options = options;
   sctx.ready_confirm_fd = -1;
   sctx.ret = GNUNET_OK;
   sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
   sctx.task = task;
   sctx.task_cls = task_cls;
   sctx.ready_confirm_fd = -1;
   sctx.ret = GNUNET_OK;
   sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
   sctx.task = task;
   sctx.task_cls = task_cls;
-  sctx.serviceName = serviceName;
+  sctx.service_name = service_name;
   sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
   sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
+
   /* setup subsystems */
   /* setup subsystems */
-  if (GNUNET_SYSERR ==
-      GNUNET_GETOPT_run (serviceName, service_options, argc, argv))
+  ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
+  if (GNUNET_SYSERR == ret)
     goto shutdown;
     goto shutdown;
-  if (GNUNET_OK != GNUNET_log_setup (serviceName, loglev, logfile))
-    HANDLE_ERROR;
-  if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfg_fn))
+  if (GNUNET_NO == ret)
+  {
+    err = 0;
     goto shutdown;
     goto shutdown;
+  }
+  if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
+    HANDLE_ERROR;
+  if (NULL == opt_cfg_fn)
+    opt_cfg_fn = GNUNET_strdup (cfg_fn);
+  if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn))
+  {
+    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  _("Malformed configuration file `%s', exit ...\n"),
+                  opt_cfg_fn);
+      goto shutdown;
+    }
+  }
+  else
+  {
+    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  _("Malformed configuration, exit ...\n"));
+      goto shutdown;
+    }
+    if (0 != strcmp (opt_cfg_fn, cfg_fn))
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("Could not access configuration file `%s'\n"),
+                 opt_cfg_fn);
+  }
   if (GNUNET_OK != setup_service (&sctx))
     goto shutdown;
   if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
   if (GNUNET_OK != setup_service (&sctx))
     goto shutdown;
   if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
@@ -1738,7 +1484,9 @@ GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName,
   if (GNUNET_OK != set_user_id (&sctx))
     goto shutdown;
   LOG (GNUNET_ERROR_TYPE_DEBUG,
   if (GNUNET_OK != set_user_id (&sctx))
     goto shutdown;
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Service `%s' runs with configuration from `%s'\n", serviceName, cfg_fn);
+       "Service `%s' runs with configuration from `%s'\n",
+       service_name,
+       opt_cfg_fn);
   if ((GNUNET_OK ==
        GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
                                               "SKEW_OFFSET", &skew_offset)) &&
   if ((GNUNET_OK ==
        GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
                                               "SKEW_OFFSET", &skew_offset)) &&
@@ -1753,7 +1501,6 @@ GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName,
   /* actually run service */
   err = 0;
   GNUNET_SCHEDULER_run (&service_task, &sctx);
   /* actually run service */
   err = 0;
   GNUNET_SCHEDULER_run (&service_task, &sctx);
-
   /* shutdown */
   if ((1 == do_daemonize) && (NULL != sctx.server))
     pid_file_delete (&sctx);
   /* shutdown */
   if ((1 == do_daemonize) && (NULL != sctx.server))
     pid_file_delete (&sctx);
@@ -1766,7 +1513,27 @@ shutdown:
       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
     GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd));
   }
       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
     GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd));
   }
+#if HAVE_MALLINFO
+  {
+    char *counter;
+
+    if ( (GNUNET_YES ==
+         GNUNET_CONFIGURATION_have_value (sctx.cfg, service_name,
+                                          "GAUGER_HEAP")) &&
+        (GNUNET_OK ==
+         GNUNET_CONFIGURATION_get_value_string (sctx.cfg, service_name,
+                                                "GAUGER_HEAP",
+                                                &counter)) )
+    {
+      struct mallinfo mi;
 
 
+      mi = mallinfo ();
+      GAUGER (service_name, counter, mi.usmblks, "blocks");
+      GNUNET_free (counter);
+    }
+  }
+#endif
+  GNUNET_SPEEDUP_stop_ ();
   GNUNET_CONFIGURATION_destroy (cfg);
   i = 0;
   if (NULL != sctx.addrs)
   GNUNET_CONFIGURATION_destroy (cfg);
   i = 0;
   if (NULL != sctx.addrs)
@@ -1777,6 +1544,7 @@ shutdown:
   GNUNET_free_non_null (logfile);
   GNUNET_free_non_null (loglev);
   GNUNET_free (cfg_fn);
   GNUNET_free_non_null (logfile);
   GNUNET_free_non_null (loglev);
   GNUNET_free (cfg_fn);
+  GNUNET_free_non_null (opt_cfg_fn);
   GNUNET_free_non_null (sctx.v4_denied);
   GNUNET_free_non_null (sctx.v6_denied);
   GNUNET_free_non_null (sctx.v4_allowed);
   GNUNET_free_non_null (sctx.v4_denied);
   GNUNET_free_non_null (sctx.v6_denied);
   GNUNET_free_non_null (sctx.v4_allowed);
@@ -1790,23 +1558,26 @@ shutdown:
  * Run a service startup sequence within an existing
  * initialized system.
  *
  * Run a service startup sequence within an existing
  * initialized system.
  *
- * @param serviceName our service name
+ * @param service_name our service name
  * @param cfg configuration to use
  * @param cfg configuration to use
+ * @param options service options
  * @return NULL on error, service handle
  */
 struct GNUNET_SERVICE_Context *
  * @return NULL on error, service handle
  */
 struct GNUNET_SERVICE_Context *
-GNUNET_SERVICE_start (const char *serviceName,
-                      const struct GNUNET_CONFIGURATION_Handle *cfg)
+GNUNET_SERVICE_start (const char *service_name,
+                      const struct GNUNET_CONFIGURATION_Handle *cfg,
+                     enum GNUNET_SERVICE_Options options)
 {
   int i;
   struct GNUNET_SERVICE_Context *sctx;
 
 {
   int i;
   struct GNUNET_SERVICE_Context *sctx;
 
-  sctx = GNUNET_malloc (sizeof (struct GNUNET_SERVICE_Context));
+  sctx = GNUNET_new (struct GNUNET_SERVICE_Context);
   sctx->ready_confirm_fd = -1;  /* no daemonizing */
   sctx->ret = GNUNET_OK;
   sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
   sctx->ready_confirm_fd = -1;  /* no daemonizing */
   sctx->ret = GNUNET_OK;
   sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
-  sctx->serviceName = serviceName;
+  sctx->service_name = service_name;
   sctx->cfg = cfg;
   sctx->cfg = cfg;
+  sctx->options = options;
 
   /* setup subsystems */
   if (GNUNET_OK != setup_service (sctx))
 
   /* setup subsystems */
   if (GNUNET_OK != setup_service (sctx))
@@ -1828,6 +1599,15 @@ GNUNET_SERVICE_start (const char *serviceName,
     GNUNET_SERVICE_stop (sctx);
     return NULL;
   }
     GNUNET_SERVICE_stop (sctx);
     return NULL;
   }
+#ifndef WINDOWS
+  if (NULL != sctx->addrs)
+    for (i = 0; NULL != sctx->addrs[i]; i++)
+      if ((AF_UNIX == sctx->addrs[i]->sa_family)
+          && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
+        GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
+                                     sctx->match_uid,
+                                     sctx->match_gid);
+#endif
   sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
   memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
   i = 0;
   sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
   memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
   i = 0;
@@ -1852,6 +1632,20 @@ GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx)
 }
 
 
 }
 
 
+/**
+ * Get the NULL-terminated array of listen sockets for this service.
+ *
+ * @param ctx service context to query
+ * @return NULL if there are no listen sockets, otherwise NULL-terminated
+ *              array of listen sockets.
+ */
+struct GNUNET_NETWORK_Handle *const*
+GNUNET_SERVICE_get_listen_sockets (struct GNUNET_SERVICE_Context *ctx)
+{
+  return ctx->lsocks;
+}
+
+
 /**
  * Stop a service that was started with "GNUNET_SERVICE_start".
  *
 /**
  * Stop a service that was started with "GNUNET_SERVICE_start".
  *
@@ -1862,6 +1656,31 @@ GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx)
 {
   unsigned int i;
 
 {
   unsigned int i;
 
+#if HAVE_MALLINFO
+  {
+    char *counter;
+
+    if ( (GNUNET_YES ==
+         GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name,
+                                          "GAUGER_HEAP")) &&
+        (GNUNET_OK ==
+         GNUNET_CONFIGURATION_get_value_string (sctx->cfg, sctx->service_name,
+                                                "GAUGER_HEAP",
+                                                &counter)) )
+    {
+      struct mallinfo mi;
+
+      mi = mallinfo ();
+      GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
+      GNUNET_free (counter);
+    }
+  }
+#endif
+  if (NULL != sctx->shutdown_task)
+  {
+    GNUNET_SCHEDULER_cancel (sctx->shutdown_task);
+    sctx->shutdown_task = NULL;
+  }
   if (NULL != sctx->server)
     GNUNET_SERVER_destroy (sctx->server);
   GNUNET_free_non_null (sctx->my_handlers);
   if (NULL != sctx->server)
     GNUNET_SERVER_destroy (sctx->server);
   GNUNET_free_non_null (sctx->my_handlers);