gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r38186 - in gnunet/src: include util


From: gnunet
Subject: [GNUnet-SVN] r38186 - in gnunet/src: include util
Date: Sun, 23 Oct 2016 18:03:55 +0200

Author: grothoff
Date: 2016-10-23 18:03:54 +0200 (Sun, 23 Oct 2016)
New Revision: 38186

Added:
   gnunet/src/util/service.c
Removed:
   gnunet/src/util/client.c
   gnunet/src/util/service.c
Modified:
   gnunet/src/include/gnunet_client_lib.h
   gnunet/src/util/Makefile.am
   gnunet/src/util/mq.c
Log:
move to new client API: remove old client API

Modified: gnunet/src/include/gnunet_client_lib.h
===================================================================
--- gnunet/src/include/gnunet_client_lib.h      2016-10-23 16:03:36 UTC (rev 
38185)
+++ gnunet/src/include/gnunet_client_lib.h      2016-10-23 16:03:54 UTC (rev 
38186)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2001-2013 GNUnet e.V.
+     Copyright (C) 2001-2013, 2016 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -45,12 +45,7 @@
 
 #include "gnunet_mq_lib.h"
 
-/**
- * Opaque handle for a connection to a service.
- */
-struct GNUNET_CLIENT_Connection;
 
-
 /**
  * Create a message queue to connect to a GNUnet service.
  * If handlers are specfied, receive messages from the connection.
@@ -69,209 +64,6 @@
                        void *error_handler_cls);
 
 
-/**
- * Create a message queue for a GNUNET_CLIENT_Connection.
- * If handlers are specfied, receive messages from the connection.
- *
- * @param connection the client connection, taken over and freed by the MQ
- * @param handlers handlers for receiving messages
- * @param error_handler error handler
- * @param error_handler_cls closure for the @a error_handler
- * @return the message queue
- * @deprecated use #GNUNET_CLIENT_connecT
- */
-struct GNUNET_MQ_Handle *
-GNUNET_MQ_queue_for_connection_client (struct GNUNET_CLIENT_Connection 
*connection,
-                                       const struct GNUNET_MQ_MessageHandler 
*handlers,
-                                       GNUNET_MQ_ErrorHandler error_handler,
-                                       void *error_handler_cls);
-
-
-/**
- * Get a connection with a service.
- *
- * @param service_name name of the service
- * @param cfg configuration to use
- * @return NULL on error (service unknown to configuration)
- * @deprecated use #GNUNET_CLIENT_connect2
- */
-struct GNUNET_CLIENT_Connection *
-GNUNET_CLIENT_connect (const char *service_name,
-                       const struct GNUNET_CONFIGURATION_Handle *cfg);
-
-
-/**
- * Destroy connection with the service.  This will automatically
- * cancel any pending "receive" request (however, the handler will
- * *NOT* be called, not even with a NULL message).  Any pending
- * transmission request will also be cancelled UNLESS the callback for
- * the transmission request has already been called, in which case the
- * transmission 'finish_pending_write' argument determines whether or
- * not the write is guaranteed to complete before the socket is fully
- * destroyed (unless, of course, there is an error with the server in
- * which case the message may still be lost).
- *
- * @param client handle to the service connection
- * @deprecated
- */
-void
-GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *client);
-
-
-/**
- * Type of a function to call when we receive a message
- * from the service.
- *
- * @param cls closure
- * @param msg message received, NULL on timeout or fatal error
- */
-typedef void
-(*GNUNET_CLIENT_MessageHandler) (void *cls,
-                                const struct GNUNET_MessageHeader *msg);
-
-
-/**
- * Read from the service.
- *
- * @param client connection to the service
- * @param handler function to call with the message
- * @param handler_cls closure for @a handler
- * @param timeout how long to wait until timing out
- * @deprecated
- */
-void
-GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *client,
-                       GNUNET_CLIENT_MessageHandler handler,
-                      void *handler_cls,
-                       struct GNUNET_TIME_Relative timeout);
-
-
-/**
- * Transmit handle for client connections.
- */
-struct GNUNET_CLIENT_TransmitHandle;
-
-
-/**
- * Ask the client to call us once the specified number of bytes
- * are free in the transmission buffer.  Will never call the @a notify
- * callback in this task, but always first go into the scheduler.
- *
- * @param client connection to the service
- * @param size number of bytes to send
- * @param timeout after how long should we give up (and call
- *        @a notify with buf NULL and size 0)?
- * @param auto_retry if the connection to the service dies, should we
- *        automatically re-connect and retry (within the timeout period)
- *        or should we immediately fail in this case?  Pass #GNUNET_YES
- *        if the caller does not care about temporary connection errors,
- *        for example because the protocol is stateless
- * @param notify function to call
- * @param notify_cls closure for @a notify
- * @return NULL if someone else is already waiting to be notified
- *         non-NULL if the notify callback was queued (can be used to cancel
- *         using #GNUNET_CONNECTION_notify_transmit_ready_cancel)
- * @deprecated
- */
-struct GNUNET_CLIENT_TransmitHandle *
-GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *client,
-                                     size_t size,
-                                     struct GNUNET_TIME_Relative timeout,
-                                     int auto_retry,
-                                     GNUNET_CONNECTION_TransmitReadyNotify 
notify,
-                                     void *notify_cls);
-
-
-/**
- * Cancel a request for notification.
- *
- * @param th handle from the original request.
- * @deprecated
- */
-void
-GNUNET_CLIENT_notify_transmit_ready_cancel (struct 
GNUNET_CLIENT_TransmitHandle *th);
-
-
-/**
- * Convenience API that combines sending a request
- * to the service and waiting for a response.
- * If either operation times out, the callback
- * will be called with a "NULL" response (in which
- * case the connection should probably be destroyed).
- *
- * @param client connection to use
- * @param hdr message to transmit
- * @param timeout when to give up (for both transmission
- *         and for waiting for a response)
- * @param auto_retry if the connection to the service dies, should we
- *        automatically re-connect and retry (within the timeout period)
- *        or should we immediately fail in this case?  Pass #GNUNET_YES
- *        if the caller does not care about temporary connection errors,
- *        for example because the protocol is stateless
- * @param rn function to call with the response
- * @param rn_cls closure for @a rn
- * @return #GNUNET_OK on success, #GNUNET_SYSERR if a request
- *         is already pending
- * @deprecated
- */
-int
-GNUNET_CLIENT_transmit_and_get_response (struct GNUNET_CLIENT_Connection 
*client,
-                                         const struct GNUNET_MessageHeader 
*hdr,
-                                         struct GNUNET_TIME_Relative timeout,
-                                         int auto_retry,
-                                         GNUNET_CLIENT_MessageHandler rn,
-                                         void *rn_cls);
-
-
-/**
- * Handle for a test to check if a service is running.
- */
-struct GNUNET_CLIENT_TestHandle;
-
-/**
- * Function called with the result on the service test.
- *
- * @param cls closure
- * @param result #GNUNET_YES if the service is running,
- *               #GNUNET_NO if the service is not running
- *               #GNUNET_SYSERR if the configuration is invalid
- */
-typedef void
-(*GNUNET_CLIENT_TestResultCallback)(void *cls,
-                                   int result);
-
-
-/**
- * Test if the service is running.  If we are given a UNIXPATH or a
- * local address, we do this NOT by trying to connect to the service,
- * but by trying to BIND to the same port.  If the BIND fails, we know
- * the service is running.
- *
- * @param service name of the service to wait for
- * @param cfg configuration to use
- * @param timeout how long to wait at most
- * @param cb function to call with the result
- * @param cb_cls closure for @a cb
- * @return handle to cancel the test
- * @deprecated
- */
-struct GNUNET_CLIENT_TestHandle *
-GNUNET_CLIENT_service_test (const char *service,
-                            const struct GNUNET_CONFIGURATION_Handle *cfg,
-                            struct GNUNET_TIME_Relative timeout,
-                            GNUNET_CLIENT_TestResultCallback cb, void *cb_cls);
-
-
-/**
- * Abort testing for service.
- *
- * @param th test handle
- * @deprecated
- */
-void
-GNUNET_CLIENT_service_test_cancel (struct GNUNET_CLIENT_TestHandle *th);
-
-
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
 #endif

Modified: gnunet/src/util/Makefile.am
===================================================================
--- gnunet/src/util/Makefile.am 2016-10-23 16:03:36 UTC (rev 38185)
+++ gnunet/src/util/Makefile.am 2016-10-23 16:03:54 UTC (rev 38186)
@@ -59,7 +59,6 @@
 libgnunetutil_la_SOURCES = \
   bandwidth.c \
   bio.c \
-  client.c \
   client_new.c \
   common_allocation.c \
   common_endian.c \

Deleted: gnunet/src/util/client.c
===================================================================
--- gnunet/src/util/client.c    2016-10-23 16:03:36 UTC (rev 38185)
+++ gnunet/src/util/client.c    2016-10-23 16:03:54 UTC (rev 38186)
@@ -1,1299 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2013 GNUnet e.V.
-
-     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 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file util/client.c
- * @brief code for access to services
- * @author Christian Grothoff
- *
- * Generic TCP code for reliable, record-oriented TCP
- * connections between clients and service providers.
- */
-#include "platform.h"
-#include "gnunet_protocols.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_socks.h"
-
-
-/**
- * How often do we re-try tranmsitting requests before giving up?
- * Note that if we succeeded transmitting a request but failed to read
- * a response, we do NOT re-try.
- */
-#define MAX_ATTEMPTS 50
-
-#define LOG(kind,...) GNUNET_log_from (kind, "util",__VA_ARGS__)
-
-/**
- * Handle for a transmission request.
- */
-struct GNUNET_CLIENT_TransmitHandle
-{
-  /**
-   * Connection state.
-   */
-  struct GNUNET_CLIENT_Connection *client;
-
-  /**
-   * Function to call to get the data for transmission.
-   */
-  GNUNET_CONNECTION_TransmitReadyNotify notify;
-
-  /**
-   * Closure for @e notify.
-   */
-  void *notify_cls;
-
-  /**
-   * Handle to the transmission with the underlying
-   * connection.
-   */
-  struct GNUNET_CONNECTION_TransmitHandle *th;
-
-  /**
-   * If we are re-trying and are delaying to do so,
-   * handle to the scheduled task managing the delay.
-   */
-  struct GNUNET_SCHEDULER_Task *reconnect_task;
-
-  /**
-   * Timeout for the operation overall.
-   */
-  struct GNUNET_TIME_Absolute timeout;
-
-  /**
-   * Number of bytes requested.
-   */
-  size_t size;
-
-  /**
-   * Are we allowed to re-try to connect without telling
-   * the user (of this API) about the connection troubles?
-   */
-  int auto_retry;
-
-  /**
-   * Number of attempts left for transmitting the request.  We may
-   * fail the first time (say because the service is not yet up), in
-   * which case (if auto_retry is set) we wait a bit and re-try
-   * (timeout permitting).
-   */
-  unsigned int attempts_left;
-
-};
-
-
-/**
- * Struct to refer to a GNUnet TCP connection.
- * This is more than just a socket because if the server
- * drops the connection, the client automatically tries
- * to reconnect (and for that needs connection information).
- */
-struct GNUNET_CLIENT_Connection
-{
-
-  /**
-   * The connection handle, NULL if not live
-   */
-  struct GNUNET_CONNECTION_Handle *connection;
-
-  /**
-   * Our configuration.
-   */
-  const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-  /**
-   * Name of the service we interact with.
-   */
-  char *service_name;
-
-  /**
-   * Handler for current receiver task.
-   */
-  GNUNET_CLIENT_MessageHandler receiver_handler;
-
-  /**
-   * Closure for @e receiver_handler.
-   */
-  void *receiver_handler_cls;
-
-  /**
-   * Handle for a pending transmission request, NULL if there is
-   * none pending.
-   */
-  struct GNUNET_CLIENT_TransmitHandle *th;
-
-  /**
-   * If we are re-trying and are delaying to do so,
-   * handle to the scheduled task managing the delay.
-   */
-  struct GNUNET_SCHEDULER_Task * receive_task;
-
-  /**
-   * Buffer for received message.
-   */
-  char *received_buf;
-
-  /**
-   * Timeout for receiving a response (absolute time).
-   */
-  struct GNUNET_TIME_Absolute receive_timeout;
-
-  /**
-   * Current value for our incremental back-off (for
-   * connect re-tries).
-   */
-  struct GNUNET_TIME_Relative back_off;
-
-  /**
-   * Number of bytes in received_buf that are valid.
-   */
-  size_t received_pos;
-
-  /**
-   * Size of received_buf.
-   */
-  unsigned int received_size;
-
-  /**
-   * Do we have a complete response in received_buf?
-   */
-  int msg_complete;
-
-  /**
-   * Are we currently busy doing receive-processing?
-   * #GNUNET_YES if so, #GNUNET_NO if not. #GNUNET_SYSERR
-   * if the connection has failed (but we may not have
-   * closed the handle itself yet).
-   */
-  int in_receive;
-
-  /**
-   * Is this the first message we are sending to the service?
-   */
-  int first_message;
-
-  /**
-   * How often have we tried to connect?
-   */
-  unsigned int attempts;
-
-};
-
-
-/**
- * Try connecting to the server using UNIX domain sockets.
- *
- * @param service_name name of service to connect to
- * @param cfg configuration to use
- * @return NULL on error, connection to UNIX otherwise
- */
-static struct GNUNET_CONNECTION_Handle *
-try_unixpath (const char *service_name,
-             const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
-#if AF_UNIX
-  struct GNUNET_CONNECTION_Handle *connection;
-  char *unixpath;
-  struct sockaddr_un s_un;
-
-  unixpath = NULL;
-  if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, 
service_name, "UNIXPATH", &unixpath)) &&
-      (0 < strlen (unixpath)))
-  {
-    /* We have a non-NULL unixpath, need to validate it */
-    if (strlen (unixpath) >= sizeof (s_un.sun_path))
-    {
-      LOG (GNUNET_ERROR_TYPE_WARNING,
-          _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
-          (unsigned long long) sizeof (s_un.sun_path));
-      unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
-      LOG (GNUNET_ERROR_TYPE_INFO,
-          _("Using `%s' instead\n"), unixpath);
-      if (NULL == unixpath)
-       return NULL;
-    }
-    connection = GNUNET_CONNECTION_create_from_connect_to_unixpath (cfg, 
unixpath);
-    if (NULL != connection)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "Connected to unixpath `%s'!\n",
-          unixpath);
-      GNUNET_free (unixpath);
-      return connection;
-    }
-  }
-  GNUNET_free_non_null (unixpath);
-#endif
-  return NULL;
-}
-
-
-/**
- * Test whether the configuration has proper values for connection
- * (UNIXPATH || (PORT && HOSTNAME)).
- *
- * @param service_name name of service to connect to
- * @param cfg configuration to use
- * @return #GNUNET_OK if the configuration is valid, #GNUNET_SYSERR if not
- */
-static int
-test_service_configuration (const char *service_name,
-                           const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
-  int ret = GNUNET_SYSERR;
-  char *hostname = NULL;
-  unsigned long long port;
-#if AF_UNIX
-  char *unixpath = NULL;
-
-  if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, 
service_name, "UNIXPATH", &unixpath)) &&
-      (0 < strlen (unixpath)))
-    ret = GNUNET_OK;
-  GNUNET_free_non_null (unixpath);
-#endif
-
-  if ( (GNUNET_YES ==
-       GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) &&
-       (GNUNET_OK ==
-       GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", 
&port)) &&
-       (port <= 65535) && (0 != port) &&
-       (GNUNET_OK ==
-       GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME",
-                                              &hostname)) &&
-       (0 != strlen (hostname)) )
-    ret = GNUNET_OK;
-  GNUNET_free_non_null (hostname);
-  return ret;
-}
-
-
-/**
- * Try to connect to the service.
- *
- * @param service_name name of service to connect to
- * @param cfg configuration to use
- * @param attempt counter used to alternate between IP and UNIX domain sockets
- * @return NULL on error
- */
-static struct GNUNET_CONNECTION_Handle *
-do_connect (const char *service_name,
-            const struct GNUNET_CONFIGURATION_Handle *cfg,
-           unsigned int attempt)
-{
-  struct GNUNET_CONNECTION_Handle *connection;
-  char *hostname;
-  unsigned long long port;
-
-  /* Never use a local source if a proxy is configured */
-  if (GNUNET_YES == GNUNET_SOCKS_check_service (service_name,cfg))
-    return GNUNET_SOCKS_do_connect (service_name,cfg);
-
-  connection = NULL;
-  if (0 == (attempt % 2))
-  {
-    /* on even rounds, try UNIX first */
-    connection = try_unixpath (service_name, cfg);
-    if (NULL != connection)
-      return connection;
-  }
-  if (GNUNET_YES ==
-      GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
-  {
-    if ((GNUNET_OK !=
-        GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", 
&port))
-       || (port > 65535) ||
-       (GNUNET_OK !=
-        GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME",
-                                               &hostname)))
-    {
-      LOG (GNUNET_ERROR_TYPE_WARNING,
-          _
-          ("Could not determine valid hostname and port for service `%s' from 
configuration.\n"),
-          service_name);
-      return NULL;
-    }
-    if (0 == strlen (hostname))
-    {
-      GNUNET_free (hostname);
-      LOG (GNUNET_ERROR_TYPE_WARNING,
-          _("Need a non-empty hostname for service `%s'.\n"), service_name);
-      return NULL;
-    }
-  }
-  else
-  {
-    /* unspecified means 0 (disabled) */
-    port = 0;
-    hostname = NULL;
-  }
-  if (0 == port)
-  {
-    /* if port is 0, try UNIX */
-    connection = try_unixpath (service_name, cfg);
-    if (NULL != connection)
-    {
-      GNUNET_free_non_null (hostname);
-      return connection;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Port is 0 for service `%s', UNIXPATH did not work, returning 
NULL!\n",
-         service_name);
-    GNUNET_free_non_null (hostname);
-    return NULL;
-  }
-  connection = GNUNET_CONNECTION_create_from_connect (cfg, hostname, port);
-  GNUNET_free (hostname);
-  return connection;
-}
-
-
-/**
- * Create a message queue to connect to a GNUnet service.
- * If handlers are specfied, receive messages from the connection.
- *
- * @param connection the client connection
- * @param handlers handlers for receiving messages, can be NULL
- * @param error_handler error handler
- * @param error_handler_cls closure for the @a error_handler
- * @return the message queue, NULL on error
- */
-struct GNUNET_MQ_Handle *
-GNUNET_CLIENT_connecTX (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                       const char *service_name,
-                       const struct GNUNET_MQ_MessageHandler *handlers,
-                       GNUNET_MQ_ErrorHandler error_handler,
-                       void *error_handler_cls)
-{
-  struct GNUNET_CLIENT_Connection *c;
-
-  c = GNUNET_CLIENT_connect (service_name,
-                             cfg);
-  if (NULL == c)
-    return NULL;
-  return GNUNET_MQ_queue_for_connection_client (c,
-                                                handlers,
-                                                error_handler,
-                                                error_handler_cls);
-}
-
-
-/**
- * Get a connection with a service.
- *
- * @param service_name name of the service
- * @param cfg configuration to use
- * @return NULL on error (service unknown to configuration)
- */
-struct GNUNET_CLIENT_Connection *
-GNUNET_CLIENT_connect (const char *service_name,
-                       const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
-  struct GNUNET_CLIENT_Connection *client;
-  struct GNUNET_CONNECTION_Handle *connection;
-
-  if (GNUNET_OK !=
-      test_service_configuration (service_name,
-                                 cfg))
-    return NULL;
-  connection = do_connect (service_name, cfg, 0);
-  client = GNUNET_new (struct GNUNET_CLIENT_Connection);
-  client->first_message = GNUNET_YES;
-  client->attempts = 1;
-  client->connection = connection;
-  client->service_name = GNUNET_strdup (service_name);
-  client->cfg = cfg;
-  client->back_off = GNUNET_TIME_UNIT_MILLISECONDS;
-  return client;
-}
-
-
-/**
- * Destroy connection with the service.  This will automatically
- * cancel any pending "receive" request (however, the handler will
- * *NOT* be called, not even with a NULL message).  Any pending
- * transmission request will also be cancelled UNLESS the callback for
- * the transmission request has already been called, in which case the
- * transmission 'finish_pending_write' argument determines whether or
- * not the write is guaranteed to complete before the socket is fully
- * destroyed (unless, of course, there is an error with the server in
- * which case the message may still be lost).
- *
- * @param client handle to the service connection
- */
-void
-GNUNET_CLIENT_disconnect (struct GNUNET_CLIENT_Connection *client)
-{
-  if (GNUNET_YES == client->in_receive)
-  {
-    GNUNET_CONNECTION_receive_cancel (client->connection);
-    client->in_receive = GNUNET_NO;
-  }
-  if (NULL != client->th)
-  {
-    GNUNET_CLIENT_notify_transmit_ready_cancel (client->th);
-    client->th = NULL;
-  }
-  if (NULL != client->connection)
-  {
-    GNUNET_CONNECTION_destroy (client->connection);
-    client->connection = NULL;
-  }
-  if (NULL != client->receive_task)
-  {
-    GNUNET_SCHEDULER_cancel (client->receive_task);
-    client->receive_task = NULL;
-  }
-  client->receiver_handler = NULL;
-  GNUNET_array_grow (client->received_buf,
-                     client->received_size,
-                     0);
-  GNUNET_free (client->service_name);
-  GNUNET_free (client);
-}
-
-
-/**
- * Check if message is complete.  Sets the "msg_complete" member
- * in the client struct.
- *
- * @param client connection with the buffer to check
- */
-static void
-check_complete (struct GNUNET_CLIENT_Connection *client)
-{
-  if ((client->received_pos >= sizeof (struct GNUNET_MessageHeader)) &&
-      (client->received_pos >=
-       ntohs (((const struct GNUNET_MessageHeader *) client->received_buf)->
-              size)))
-    client->msg_complete = GNUNET_YES;
-}
-
-
-/**
- * Callback function for data received from the network.  Note that
- * both @a available and @a errCode would be 0 if the read simply timed out.
- *
- * @param cls closure
- * @param buf pointer to received data
- * @param available number of bytes availabe in @a buf,
- *        possibly 0 (on errors)
- * @param addr address of the sender
- * @param addrlen size of @a addr
- * @param errCode value of errno (on errors receiving)
- */
-static void
-receive_helper (void *cls,
-                const void *buf,
-                size_t available,
-                const struct sockaddr *addr,
-                socklen_t addrlen,
-                int errCode)
-{
-  struct GNUNET_CLIENT_Connection *client = cls;
-  struct GNUNET_TIME_Relative remaining;
-  GNUNET_CLIENT_MessageHandler receive_handler;
-  void *receive_handler_cls;
-
-  GNUNET_assert (GNUNET_NO == client->msg_complete);
-  GNUNET_assert (GNUNET_YES == client->in_receive);
-  client->in_receive = GNUNET_NO;
-  if ( (0 == available) ||
-       (NULL == client->connection) ||
-       (0 != errCode) )
-  {
-    /* signal timeout! */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Timeout in receive_helper, available %u, client->connection %s, 
errCode `%s'\n",
-         (unsigned int) available,
-         NULL == client->connection ? "NULL" : "non-NULL",
-         STRERROR (errCode));
-    /* remember failure */
-    client->in_receive = GNUNET_SYSERR;
-    if (NULL != (receive_handler = client->receiver_handler))
-    {
-      receive_handler_cls = client->receiver_handler_cls;
-      client->receiver_handler = NULL;
-      receive_handler (receive_handler_cls,
-                       NULL);
-    }
-    return;
-  }
-  /* FIXME: optimize for common fast case where buf contains the
-   * entire message and we need no copying... */
-
-  /* slow path: append to array */
-  if (client->received_size < client->received_pos + available)
-    GNUNET_array_grow (client->received_buf, client->received_size,
-                       client->received_pos + available);
-  GNUNET_memcpy (&client->received_buf[client->received_pos], buf, available);
-  client->received_pos += available;
-  check_complete (client);
-  /* check for timeout */
-  remaining = GNUNET_TIME_absolute_get_remaining (client->receive_timeout);
-  if (0 == remaining.rel_value_us)
-  {
-    /* signal timeout! */
-    if (NULL != (receive_handler = client->receiver_handler))
-    {
-      client->receiver_handler = NULL;
-      receive_handler (client->receiver_handler_cls, NULL);
-    }
-    return;
-  }
-  /* back to receive -- either for more data or to call callback! */
-  GNUNET_CLIENT_receive (client, client->receiver_handler,
-                         client->receiver_handler_cls, remaining);
-}
-
-
-/**
- * Continuation to call the receive callback.
- *
- * @param cls our handle to the client connection
- */
-static void
-receive_task (void *cls)
-{
-  struct GNUNET_CLIENT_Connection *client = cls;
-  GNUNET_CLIENT_MessageHandler handler = client->receiver_handler;
-  const struct GNUNET_MessageHeader *cmsg =
-      (const struct GNUNET_MessageHeader *) client->received_buf;
-  void *handler_cls = client->receiver_handler_cls;
-  uint16_t msize = ntohs (cmsg->size);
-  char mbuf[msize] GNUNET_ALIGN;
-  struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) mbuf;
-
-  client->receive_task = NULL;
-  if ( (GNUNET_SYSERR == client->in_receive) &&
-       (GNUNET_YES != client->msg_complete) )
-  {
-    /* Connection failure, signal to caller! */
-    client->receiver_handler = NULL;
-    if (NULL != handler)
-      handler (handler_cls,
-               NULL);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received message of type %u and size %u from %s service.\n",
-       ntohs (cmsg->type),
-       msize,
-       client->service_name);
-  GNUNET_assert (GNUNET_YES == client->msg_complete);
-  GNUNET_assert (client->received_pos >= msize);
-  GNUNET_memcpy (msg, cmsg, msize);
-  memmove (client->received_buf,
-          &client->received_buf[msize],
-           client->received_pos - msize);
-  client->received_pos -= msize;
-  client->msg_complete = GNUNET_NO;
-  client->receiver_handler = NULL;
-  check_complete (client);
-  if (NULL != handler)
-    handler (handler_cls, msg);
-}
-
-
-/**
- * Read from the service.
- *
- * @param client the service
- * @param handler function to call with the message
- * @param handler_cls closure for @a handler
- * @param timeout how long to wait until timing out
- */
-void
-GNUNET_CLIENT_receive (struct GNUNET_CLIENT_Connection *client,
-                       GNUNET_CLIENT_MessageHandler handler,
-                      void *handler_cls,
-                       struct GNUNET_TIME_Relative timeout)
-{
-  if (NULL == client->connection)
-  {
-    /* already disconnected, fail instantly! */
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               "Client API violation for service `%s'\n",
-               client->service_name);
-    GNUNET_break (0);           /* this should not happen in well-written 
code! */
-    if (NULL != handler)
-      handler (handler_cls,
-               NULL);
-    return;
-  }
-  client->receiver_handler = handler;
-  client->receiver_handler_cls = handler_cls;
-  client->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
-  if ( (GNUNET_YES == client->msg_complete) ||
-       (GNUNET_SYSERR == client->in_receive) )
-  {
-    GNUNET_assert (NULL == client->receive_task);
-    client->receive_task = GNUNET_SCHEDULER_add_now (&receive_task,
-                                                    client);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "calling GNUNET_CONNECTION_receive\n");
-  GNUNET_assert (GNUNET_NO == client->in_receive);
-  client->in_receive = GNUNET_YES;
-  GNUNET_CONNECTION_receive (client->connection,
-                             GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
-                             timeout,
-                             &receive_helper,
-                             client);
-}
-
-
-/**
- * Handle for a test to check if a service is running.
- */
-struct GNUNET_CLIENT_TestHandle
-{
-  /**
-   * Function to call with the result of the test.
-   */
-  GNUNET_CLIENT_TestResultCallback cb;
-
-  /**
-   * Closure for @e cb.
-   */
-  void *cb_cls;
-
-  /**
-   * Client connection we are using for the test, if any.
-   */
-  struct GNUNET_CLIENT_Connection *client;
-
-  /**
-   * Handle for the transmission request, if any.
-   */
-  struct GNUNET_CLIENT_TransmitHandle *th;
-
-  /**
-   * Deadline for calling @e cb.
-   */
-  struct GNUNET_TIME_Absolute test_deadline;
-
-  /**
-   * ID of task used for asynchronous operations.
-   */
-  struct GNUNET_SCHEDULER_Task *task;
-
-  /**
-   * Final result to report back (once known).
-   */
-  int result;
-};
-
-
-/**
- * Abort testing for service.
- *
- * @param th test handle
- */
-void
-GNUNET_CLIENT_service_test_cancel (struct GNUNET_CLIENT_TestHandle *th)
-{
-  if (NULL != th->th)
-  {
-    GNUNET_CLIENT_notify_transmit_ready_cancel (th->th);
-    th->th = NULL;
-  }
-  if (NULL != th->client)
-  {
-    GNUNET_CLIENT_disconnect (th->client);
-    th->client = NULL;
-  }
-  if (NULL != th->task)
-  {
-    GNUNET_SCHEDULER_cancel (th->task);
-    th->task = NULL;
-  }
-  GNUNET_free (th);
-}
-
-
-/**
- * Task that reports back the result by calling the callback
- * and then cleans up.
- *
- * @param cls the `struct GNUNET_CLIENT_TestHandle`
- */
-static void
-report_result (void *cls)
-{
-  struct GNUNET_CLIENT_TestHandle *th = cls;
-
-  th->task = NULL;
-  th->cb (th->cb_cls, th->result);
-  GNUNET_CLIENT_service_test_cancel (th);
-}
-
-
-/**
- * Report service test result asynchronously back to callback.
- *
- * @param th test handle with the result and the callback
- * @param result result to report
- */
-static void
-service_test_report (struct GNUNET_CLIENT_TestHandle *th,
-                    int result)
-{
-  th->result = result;
-  th->task = GNUNET_SCHEDULER_add_now (&report_result,
-                                      th);
-}
-
-
-/**
- * Receive confirmation from test, service is up.
- *
- * @param cls closure with the `struct GNUNET_CLIENT_TestHandle`
- * @param msg message received, NULL on timeout or fatal error
- */
-static void
-confirm_handler (void *cls,
-                 const struct GNUNET_MessageHeader *msg)
-{
-  struct GNUNET_CLIENT_TestHandle *th = cls;
-
-  /* We may want to consider looking at the reply in more
-   * detail in the future, for example, is this the
-   * correct service? FIXME! */
-  if (NULL != msg)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received confirmation that service is running.\n");
-    service_test_report (th, GNUNET_YES);
-  }
-  else
-  {
-    service_test_report (th, GNUNET_NO);
-  }
-}
-
-
-/**
- * Send the 'TEST' message to the service.  If successful, prepare to
- * receive the reply.
- *
- * @param cls the `struct GNUNET_CLIENT_TestHandle` of the test
- * @param size number of bytes available in @a buf
- * @param buf where to write the message
- * @return number of bytes written to @a buf
- */
-static size_t
-write_test (void *cls, size_t size, void *buf)
-{
-  struct GNUNET_CLIENT_TestHandle *th = cls;
-  struct GNUNET_MessageHeader *msg;
-
-  th->th = NULL;
-  if (size < sizeof (struct GNUNET_MessageHeader))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-        "Failed to transmit TEST request.\n");
-    service_test_report (th, GNUNET_NO);
-    return 0;                   /* client disconnected */
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Transmitting `%s' request.\n",
-       "TEST");
-  msg = (struct GNUNET_MessageHeader *) buf;
-  msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
-  msg->size = htons (sizeof (struct GNUNET_MessageHeader));
-  GNUNET_CLIENT_receive (th->client,
-                        &confirm_handler, th,
-                         GNUNET_TIME_absolute_get_remaining
-                         (th->test_deadline));
-  return sizeof (struct GNUNET_MessageHeader);
-}
-
-
-/**
- * Test if the service is running.  If we are given a UNIXPATH or a
- * local address, we do this NOT by trying to connect to the service,
- * but by trying to BIND to the same port.  If the BIND fails, we know
- * the service is running.
- *
- * @param service name of the service to wait for
- * @param cfg configuration to use
- * @param timeout how long to wait at most
- * @param cb function to call with the result
- * @param cb_cls closure for @a cb
- * @return handle to cancel the test
- */
-struct GNUNET_CLIENT_TestHandle *
-GNUNET_CLIENT_service_test (const char *service,
-                            const struct GNUNET_CONFIGURATION_Handle *cfg,
-                            struct GNUNET_TIME_Relative timeout,
-                            GNUNET_CLIENT_TestResultCallback cb,
-                           void *cb_cls)
-{
-  struct GNUNET_CLIENT_TestHandle *th;
-  char *hostname;
-  unsigned long long port;
-  struct GNUNET_NETWORK_Handle *sock;
-
-  th = GNUNET_new (struct GNUNET_CLIENT_TestHandle);
-  th->cb = cb;
-  th->cb_cls = cb_cls;
-  th->test_deadline = GNUNET_TIME_relative_to_absolute (timeout);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Testing if service `%s' is running.\n",
-       service);
-#ifdef AF_UNIX
-  {
-    /* probe UNIX support */
-    struct sockaddr_un s_un;
-    char *unixpath;
-    int abstract;
-
-    unixpath = NULL;
-    if ((GNUNET_OK ==
-        GNUNET_CONFIGURATION_get_value_filename (cfg,
-                                                 service,
-                                                 "UNIXPATH",
-                                                 &unixpath)) &&
-       (0 < strlen (unixpath)))  /* We have a non-NULL unixpath, does that 
mean it's valid? */
-    {
-      if (strlen (unixpath) >= sizeof (s_un.sun_path))
-      {
-        LOG (GNUNET_ERROR_TYPE_WARNING,
-             _("UNIXPATH `%s' too long, maximum length is %llu\n"),
-            unixpath,
-             (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");
-#else
-    abstract = GNUNET_NO;
-#endif
-    if ((NULL != unixpath) && (GNUNET_YES != abstract))
-    {
-      if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (unixpath))
-        GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
-                                  "mkdir", unixpath);
-    }
-    if (NULL != unixpath)
-    {
-      sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
-      if (NULL != sock)
-      {
-       memset (&s_un, 0, sizeof (s_un));
-       s_un.sun_family = AF_UNIX;
-        strncpy (s_un.sun_path, unixpath, sizeof (s_un.sun_path) - 1);
-        if (GNUNET_YES == abstract)
-          s_un.sun_path[0] = '\0';
-#if HAVE_SOCKADDR_IN_SIN_LEN
-        s_un.sun_len = (u_char) sizeof (struct sockaddr_un);
-#endif
-       if (GNUNET_OK !=
-           GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_un,
-                                       sizeof (struct sockaddr_un)))
-        {
-         /* failed to bind => service must be running */
-         GNUNET_free (unixpath);
-         (void) GNUNET_NETWORK_socket_close (sock);
-         service_test_report (th, GNUNET_YES);
-         return th;
-       }
-       (void) GNUNET_NETWORK_socket_close (sock);
-        /* let's try IP */
-      }
-    }
-    GNUNET_free_non_null (unixpath);
-  }
-#endif
-
-  hostname = NULL;
-  if ((GNUNET_OK !=
-       GNUNET_CONFIGURATION_get_value_number (cfg, service, "PORT", &port)) ||
-      (port > 65535) ||
-      (GNUNET_OK !=
-       GNUNET_CONFIGURATION_get_value_string (cfg, service, "HOSTNAME",
-                                              &hostname)))
-  {
-    /* UNIXPATH failed (if possible) AND IP failed => error */
-    service_test_report (th, GNUNET_SYSERR);
-    return th;
-  }
-
-  if (0 == strcmp ("localhost", hostname)
-#if !LINUX
-      && 0
-#endif
-      )
-  {
-    /* can test using 'bind' */
-    struct sockaddr_in s_in;
-
-    memset (&s_in, 0, sizeof (s_in));
-#if HAVE_SOCKADDR_IN_SIN_LEN
-    s_in.sin_len = sizeof (struct sockaddr_in);
-#endif
-    s_in.sin_family = AF_INET;
-    s_in.sin_port = htons (port);
-
-    sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
-    if (NULL != sock)
-    {
-      if (GNUNET_OK !=
-          GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_in,
-                                      sizeof (s_in)))
-      {
-        /* failed to bind => service must be running */
-        GNUNET_free (hostname);
-        (void) GNUNET_NETWORK_socket_close (sock);
-        service_test_report (th, GNUNET_YES);
-        return th;
-      }
-      (void) GNUNET_NETWORK_socket_close (sock);
-    }
-  }
-
-  if (0 == strcmp ("ip6-localhost", hostname)
-#if !LINUX
-      && 0
-#endif
-      )
-  {
-    /* can test using 'bind' */
-    struct sockaddr_in6 s_in6;
-
-    memset (&s_in6, 0, sizeof (s_in6));
-#if HAVE_SOCKADDR_IN_SIN_LEN
-    s_in6.sin6_len = sizeof (struct sockaddr_in6);
-#endif
-    s_in6.sin6_family = AF_INET6;
-    s_in6.sin6_port = htons (port);
-
-    sock = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_STREAM, 0);
-    if (NULL != sock)
-    {
-      if (GNUNET_OK !=
-          GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_in6,
-                                      sizeof (s_in6)))
-      {
-        /* failed to bind => service must be running */
-        GNUNET_free (hostname);
-        (void) GNUNET_NETWORK_socket_close (sock);
-        service_test_report (th, GNUNET_YES);
-        return th;
-      }
-      (void) GNUNET_NETWORK_socket_close (sock);
-    }
-  }
-
-  if (((0 == strcmp ("localhost", hostname)) ||
-       (0 == strcmp ("ip6-localhost", hostname)))
-#if !LINUX
-      && 0
-#endif
-      )
-  {
-    /* all binds succeeded => claim service not running right now */
-    GNUNET_free_non_null (hostname);
-    service_test_report (th, GNUNET_NO);
-    return th;
-  }
-  GNUNET_free_non_null (hostname);
-
-  /* non-localhost, try 'connect' method */
-  th->client = GNUNET_CLIENT_connect (service, cfg);
-  if (NULL == th->client)
-  {
-    LOG (GNUNET_ERROR_TYPE_INFO,
-         _("Could not connect to service `%s', configuration broken.\n"),
-         service);
-    service_test_report (th, GNUNET_SYSERR);
-    return th;
-  }
-  th->th = GNUNET_CLIENT_notify_transmit_ready (th->client,
-                                               sizeof (struct 
GNUNET_MessageHeader),
-                                               timeout, GNUNET_YES,
-                                               &write_test, th);
-  if (NULL == th->th)
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         _("Failure to transmit request to service `%s'\n"), service);
-    service_test_report (th, GNUNET_SYSERR);
-    return th;
-  }
-  return th;
-}
-
-
-/**
- * Connection notifies us about failure or success of
- * a transmission request.  Either pass it on to our
- * user or, if possible, retry.
- *
- * @param cls our `struct GNUNET_CLIENT_TransmissionHandle`
- * @param size number of bytes available for transmission
- * @param buf where to write them
- * @return number of bytes written to @a buf
- */
-static size_t
-client_notify (void *cls, size_t size, void *buf);
-
-
-/**
- * This task is run if we should re-try connection to the
- * service after a while.
- *
- * @param cls our `struct GNUNET_CLIENT_TransmitHandle` of the request
- */
-static void
-client_delayed_retry (void *cls)
-{
-  struct GNUNET_CLIENT_TransmitHandle *th = cls;
-  struct GNUNET_TIME_Relative delay;
-
-  th->reconnect_task = NULL;
-  th->client->connection =
-    do_connect (th->client->service_name,
-               th->client->cfg,
-               th->client->attempts++);
-  th->client->first_message = GNUNET_YES;
-  if (NULL == th->client->connection)
-  {
-    /* could happen if we're out of sockets */
-    delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining 
(th->timeout),
-                                      th->client->back_off);
-    th->client->back_off = GNUNET_TIME_STD_BACKOFF (th->client->back_off);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Transmission failed %u times, trying again in %s.\n",
-         MAX_ATTEMPTS - th->attempts_left,
-         GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
-    GNUNET_assert (NULL == th->th);
-    GNUNET_assert (NULL == th->reconnect_task);
-    th->reconnect_task =
-        GNUNET_SCHEDULER_add_delayed (delay,
-                                     &client_delayed_retry,
-                                     th);
-    return;
-  }
-  th->th =
-      GNUNET_CONNECTION_notify_transmit_ready (th->client->connection, 
th->size,
-                                               
GNUNET_TIME_absolute_get_remaining
-                                               (th->timeout),
-                                              &client_notify,
-                                               th);
-  if (NULL == th->th)
-  {
-    GNUNET_break (0);
-    th->client->th = NULL;
-    th->notify (th->notify_cls, 0, NULL);
-    GNUNET_free (th);
-    return;
-  }
-}
-
-
-/**
- * Connection notifies us about failure or success of a transmission
- * request.  Either pass it on to our user or, if possible, retry.
- *
- * @param cls our `struct GNUNET_CLIENT_TransmissionHandle`
- * @param size number of bytes available for transmission
- * @param buf where to write them
- * @return number of bytes written to @a buf
- */
-static size_t
-client_notify (void *cls,
-               size_t size,
-               void *buf)
-{
-  struct GNUNET_CLIENT_TransmitHandle *th = cls;
-  struct GNUNET_CLIENT_Connection *client = th->client;
-  size_t ret;
-  struct GNUNET_TIME_Relative delay;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "client_notify is running\n");
-  th->th = NULL;
-  client->th = NULL;
-  if (NULL == buf)
-  {
-    delay = GNUNET_TIME_absolute_get_remaining (th->timeout);
-    delay.rel_value_us /= 2;
-    if ( (GNUNET_YES != th->auto_retry) ||
-         (0 == --th->attempts_left) ||
-         (delay.rel_value_us < 1) )
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Transmission failed %u times, giving up.\n",
-           MAX_ATTEMPTS - th->attempts_left);
-      GNUNET_break (0 ==
-                    th->notify (th->notify_cls, 0, NULL));
-      GNUNET_free (th);
-      return 0;
-    }
-    /* auto-retry */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Failed to connect to `%s', automatically trying again.\n",
-         client->service_name);
-    if (GNUNET_YES == client->in_receive)
-    {
-      GNUNET_CONNECTION_receive_cancel (client->connection);
-      client->in_receive = GNUNET_NO;
-    }
-    GNUNET_CONNECTION_destroy (client->connection);
-    client->connection = NULL;
-    delay = GNUNET_TIME_relative_min (delay, client->back_off);
-    client->back_off =
-        GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply
-                                  (client->back_off, 2),
-                                  GNUNET_TIME_UNIT_SECONDS);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Transmission failed %u times, trying again in %s.\n",
-         MAX_ATTEMPTS - th->attempts_left,
-         GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
-    client->th = th;
-    GNUNET_assert (NULL == th->reconnect_task);
-    GNUNET_assert (NULL == th->th);
-    th->reconnect_task =
-        GNUNET_SCHEDULER_add_delayed (delay,
-                                     &client_delayed_retry,
-                                     th);
-    return 0;
-  }
-  GNUNET_assert (size >= th->size);
-  ret = th->notify (th->notify_cls, size, buf);
-  GNUNET_free (th);
-  if (sizeof (struct GNUNET_MessageHeader) <= ret)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Transmitting message of type %u and size %u to %s service.\n",
-         ntohs (((struct GNUNET_MessageHeader *) buf)->type),
-         ntohs (((struct GNUNET_MessageHeader *) buf)->size),
-         client->service_name);
-  }
-  return ret;
-}
-
-
-/**
- * Ask the client to call us once the specified number of bytes
- * are free in the transmission buffer.  Will never call the @a notify
- * callback in this task, but always first go into the scheduler.
- *
- * @param client connection to the service
- * @param size number of bytes to send
- * @param timeout after how long should we give up (and call
- *        notify with buf NULL and size 0)?
- * @param auto_retry if the connection to the service dies, should we
- *        automatically re-connect and retry (within the timeout period)
- *        or should we immediately fail in this case?  Pass GNUNET_YES
- *        if the caller does not care about temporary connection errors,
- *        for example because the protocol is stateless
- * @param notify function to call
- * @param notify_cls closure for @a notify
- * @return NULL if our buffer will never hold size bytes,
- *         a handle if the notify callback was queued (can be used to cancel)
- */
-struct GNUNET_CLIENT_TransmitHandle *
-GNUNET_CLIENT_notify_transmit_ready (struct GNUNET_CLIENT_Connection *client,
-                                     size_t size,
-                                     struct GNUNET_TIME_Relative timeout,
-                                     int auto_retry,
-                                     GNUNET_CONNECTION_TransmitReadyNotify 
notify,
-                                    void *notify_cls)
-{
-  struct GNUNET_CLIENT_TransmitHandle *th;
-
-  if (NULL != client->th)
-  {
-    /* If this breaks, you most likley called this function twice without 
waiting
-     * for completion or canceling the request */
-    GNUNET_assert (0);
-    return NULL;
-  }
-  th = GNUNET_new (struct GNUNET_CLIENT_TransmitHandle);
-  th->client = client;
-  th->size = size;
-  th->timeout = GNUNET_TIME_relative_to_absolute (timeout);
-  /* always auto-retry on first message to service */
-  th->auto_retry = (GNUNET_YES == client->first_message) ? GNUNET_YES : 
auto_retry;
-  client->first_message = GNUNET_NO;
-  th->notify = notify;
-  th->notify_cls = notify_cls;
-  th->attempts_left = MAX_ATTEMPTS;
-  client->th = th;
-  if (NULL == client->connection)
-  {
-    GNUNET_assert (NULL == th->th);
-    GNUNET_assert (NULL == th->reconnect_task);
-    th->reconnect_task =
-        GNUNET_SCHEDULER_add_delayed (client->back_off,
-                                      &client_delayed_retry,
-                                      th);
-  }
-  else
-  {
-    th->th = GNUNET_CONNECTION_notify_transmit_ready (client->connection,
-                                                      size,
-                                                      timeout,
-                                                      &client_notify,
-                                                      th);
-    if (NULL == th->th)
-    {
-      GNUNET_break (0);
-      GNUNET_free (th);
-      client->th = NULL;
-      return NULL;
-    }
-  }
-  return th;
-}
-
-
-/**
- * Cancel a request for notification.
- *
- * @param th handle from the original request.
- */
-void
-GNUNET_CLIENT_notify_transmit_ready_cancel (struct 
GNUNET_CLIENT_TransmitHandle *th)
-{
-  if (NULL != th->reconnect_task)
-  {
-    GNUNET_assert (NULL == th->th);
-    GNUNET_SCHEDULER_cancel (th->reconnect_task);
-    th->reconnect_task = NULL;
-  }
-  else
-  {
-    GNUNET_assert (NULL != th->th);
-    GNUNET_CONNECTION_notify_transmit_ready_cancel (th->th);
-  }
-  th->client->th = NULL;
-  GNUNET_free (th);
-}
-
-
-/*  end of client.c */

Modified: gnunet/src/util/mq.c
===================================================================
--- gnunet/src/util/mq.c        2016-10-23 16:03:36 UTC (rev 38185)
+++ gnunet/src/util/mq.c        2016-10-23 16:03:54 UTC (rev 38186)
@@ -220,34 +220,6 @@
 
 
 /**
- * Implementation-specific state for connection to
- * service (MQ for clients).
- */
-struct ClientConnectionState
-{
-  /**
-   * Did we call receive alread alreadyy?
-   */
-  int receive_active;
-
-  /**
-   * Do we also want to receive?
-   */
-  int receive_requested;
-
-  /**
-   * Connection to the service.
-   */
-  struct GNUNET_CLIENT_Connection *connection;
-
-  /**
-   * Active transmission request (or NULL).
-   */
-  struct GNUNET_CLIENT_TransmitHandle *th;
-};
-
-
-/**
  * Call the message message handler that was registered
  * for the type of the given message in the given message queue.
  *
@@ -775,175 +747,6 @@
 
 
 /**
- * Type of a function to call when we receive a message
- * from the service.
- *
- * @param cls closure
- * @param msg message received, NULL on timeout or fatal error
- */
-static void
-handle_client_message (void *cls,
-                       const struct GNUNET_MessageHeader *msg)
-{
-  struct GNUNET_MQ_Handle *mq = cls;
-  struct ClientConnectionState *state;
-
-  state = mq->impl_state;
-  if (NULL == msg)
-  {
-    GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_READ);
-    return;
-  }
-  GNUNET_CLIENT_receive (state->connection,
-                        &handle_client_message,
-                        mq,
-                         GNUNET_TIME_UNIT_FOREVER_REL);
-  GNUNET_MQ_inject_message (mq, msg);
-}
-
-
-/**
- * Transmit a queued message to the session's client.
- *
- * @param cls consensus session
- * @param size number of bytes available in @a buf
- * @param buf where the callee should write the message
- * @return number of bytes written to buf
- */
-static size_t
-connection_client_transmit_queued (void *cls,
-                                   size_t size,
-                                   void *buf)
-{
-  struct GNUNET_MQ_Handle *mq = cls;
-  const struct GNUNET_MessageHeader *msg;
-  struct ClientConnectionState *state = mq->impl_state;
-  size_t msg_size;
-
-  GNUNET_assert (NULL != mq);
-  state->th = NULL;
-  msg = GNUNET_MQ_impl_current (mq);
-
-  if (NULL == buf)
-  {
-    GNUNET_MQ_inject_error (mq, GNUNET_MQ_ERROR_READ);
-    return 0;
-  }
-
-  if ( (GNUNET_YES == state->receive_requested) &&
-       (GNUNET_NO == state->receive_active) )
-  {
-    state->receive_active = GNUNET_YES;
-    GNUNET_CLIENT_receive (state->connection,
-                          &handle_client_message,
-                          mq,
-                           GNUNET_TIME_UNIT_FOREVER_REL);
-  }
-
-  msg_size = ntohs (msg->size);
-  GNUNET_assert (size >= msg_size);
-  GNUNET_memcpy (buf, msg, msg_size);
-  state->th = NULL;
-
-  GNUNET_MQ_impl_send_continue (mq);
-
-  return msg_size;
-}
-
-
-static void
-connection_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
-                                void *impl_state)
-{
-  struct ClientConnectionState *state = impl_state;
-
-  if (NULL != state->th)
-  {
-    GNUNET_CLIENT_notify_transmit_ready_cancel (state->th);
-    state->th = NULL;
-  }
-  GNUNET_CLIENT_disconnect (state->connection);
-  GNUNET_free (impl_state);
-}
-
-
-static void
-connection_client_send_impl (struct GNUNET_MQ_Handle *mq,
-                             const struct GNUNET_MessageHeader *msg,
-                             void *impl_state)
-{
-  struct ClientConnectionState *state = impl_state;
-
-  GNUNET_assert (NULL != state);
-  GNUNET_assert (NULL == state->th);
-  state->th =
-      GNUNET_CLIENT_notify_transmit_ready (state->connection,
-                                          ntohs (msg->size),
-                                           GNUNET_TIME_UNIT_FOREVER_REL,
-                                           GNUNET_NO,
-                                           &connection_client_transmit_queued,
-                                           mq);
-  GNUNET_assert (NULL != state->th);
-}
-
-
-static void
-connection_client_cancel_impl (struct GNUNET_MQ_Handle *mq,
-                               void *impl_state)
-{
-  struct ClientConnectionState *state = impl_state;
-
-  if (NULL != state->th)
-  {
-    GNUNET_CLIENT_notify_transmit_ready_cancel (state->th);
-    state->th = NULL;
-  }
-  else if (NULL != mq->send_task)
-  {
-    GNUNET_SCHEDULER_cancel (mq->send_task);
-    mq->send_task = NULL;
-  }
-  else
-    GNUNET_assert (0);
-}
-
-
-struct GNUNET_MQ_Handle *
-GNUNET_MQ_queue_for_connection_client (struct GNUNET_CLIENT_Connection 
*connection,
-                                       const struct GNUNET_MQ_MessageHandler 
*handlers,
-                                       GNUNET_MQ_ErrorHandler error_handler,
-                                       void *error_handler_cls)
-{
-  struct GNUNET_MQ_Handle *mq;
-  struct ClientConnectionState *state;
-  unsigned int i;
-
-  mq = GNUNET_new (struct GNUNET_MQ_Handle);
-  if (NULL != handlers)
-  {
-    for (i=0;NULL != handlers[i].cb; i++) ;
-    mq->handlers = GNUNET_new_array (i + 1,
-                                    struct GNUNET_MQ_MessageHandler);
-    GNUNET_memcpy (mq->handlers,
-                   handlers,
-                   i * sizeof (struct GNUNET_MQ_MessageHandler));
-  }
-  mq->error_handler = error_handler;
-  mq->error_handler_cls = error_handler_cls;
-  state = GNUNET_new (struct ClientConnectionState);
-  state->connection = connection;
-  mq->impl_state = state;
-  mq->send_impl = &connection_client_send_impl;
-  mq->destroy_impl = &connection_client_destroy_impl;
-  mq->cancel_impl = &connection_client_cancel_impl;
-  if (NULL != handlers)
-    state->receive_requested = GNUNET_YES;
-
-  return mq;
-}
-
-
-/**
  * Associate the assoc_data in mq with a unique request id.
  *
  * @param mq message queue, id will be unique for the queue

Deleted: gnunet/src/util/service.c
===================================================================
--- gnunet/src/util/service.c   2016-10-23 16:03:36 UTC (rev 38185)
+++ gnunet/src/util/service.c   2016-10-23 16:03:54 UTC (rev 38186)
@@ -1,1697 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009, 2012 GNUnet e.V.
-
-     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 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file util/service.c
- * @brief functions related to starting services
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_protocols.h"
-#include "gnunet_constants.h"
-#include "gnunet_resolver_service.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_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", 
syscall)
-
-#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file 
(kind, "util", syscall, filename)
-
-
-/* ******************* access control ******************** */
-
-/**
- * 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
- */
-static int
-check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
-                   const struct in_addr *add)
-{
-  unsigned int i;
-
-  if (NULL == list)
-    return GNUNET_NO;
-  i = 0;
-  while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
-  {
-    if ((add->s_addr & list[i].netmask.s_addr) ==
-        (list[i].network.s_addr & list[i].netmask.s_addr))
-      return GNUNET_YES;
-    i++;
-  }
-  return GNUNET_NO;
-}
-
-
-/**
- * Check if the given IP address is in the list of IP addresses.
- *
- * @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
- */
-static int
-check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
-                   const struct in6_addr *ip)
-{
-  unsigned int i;
-  unsigned int j;
-  struct in6_addr zero;
-
-  if (NULL == list)
-    return GNUNET_NO;
-  memset (&zero, 0, sizeof (struct in6_addr));
-  i = 0;
-NEXT:
-  while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr)))
-  {
-    for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
-      if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
-          (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
-      {
-        i++;
-        goto NEXT;
-      }
-    return GNUNET_YES;
-  }
-  return GNUNET_NO;
-}
-
-
-/* ****************** service struct ****************** */
-
-
-/**
- * Context for "service_task".
- */
-struct GNUNET_SERVICE_Context
-{
-  /**
-   * Our configuration.
-   */
-  const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-  /**
-   * Handle for the server.
-   */
-  struct GNUNET_SERVER_Handle *server;
-
-  /**
-   * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
-   * listen sockets.
-   */
-  struct sockaddr **addrs;
-
-  /**
-   * Name of our service.
-   */
-  const char *service_name;
-
-  /**
-   * Main service-specific task to run.
-   */
-  GNUNET_SERVICE_Main task;
-
-  /**
-   * Closure for @e task.
-   */
-  void *task_cls;
-
-  /**
-   * IPv4 addresses that are not allowed to connect.
-   */
-  struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
-
-  /**
-   * IPv6 addresses that are not allowed to connect.
-   */
-  struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
-
-  /**
-   * IPv4 addresses that are allowed to connect (if not
-   * set, all are allowed).
-   */
-  struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
-
-  /**
-   * IPv6 addresses that are allowed to connect (if not
-   * set, all are allowed).
-   */
-  struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
-
-  /**
-   * My (default) message handlers.  Adjusted copy
-   * of "defhandlers".
-   */
-  struct GNUNET_SERVER_MessageHandler *my_handlers;
-
-  /**
-   * Array of the lengths of the entries in addrs.
-   */
-  socklen_t *addrlens;
-
-  /**
-   * NULL-terminated array of listen sockets we should take over.
-   */
-  struct GNUNET_NETWORK_Handle **lsocks;
-
-  /**
-   * Task ID of the shutdown task.
-   */
-  struct GNUNET_SCHEDULER_Task *shutdown_task;
-
-  /**
-   * Idle timeout for server.
-   */
-  struct GNUNET_TIME_Relative timeout;
-
-  /**
-   * Overall success/failure of the service start.
-   */
-  int ret;
-
-  /**
-   * If we are daemonizing, this FD is set to the
-   * pipe to the parent.  Send '.' if we started
-   * ok, '!' if not.  -1 if we are not daemonizing.
-   */
-  int ready_confirm_fd;
-
-  /**
-   * Do we close connections if we receive messages
-   * for which we have no handler?
-   */
-  int require_found;
-
-  /**
-   * Do we require a matching UID for UNIX domain socket connections?
-   * #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?
-   * 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
-   * 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;
-
-  /**
-   * Our options.
-   */
-  enum GNUNET_SERVICE_Options options;
-
-};
-
-
-/* ****************** message handlers ****************** */
-
-/**
- * Send a 'TEST' message back to the client.
- *
- * @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)
-{
-  struct GNUNET_SERVER_Client *client = cls;
-  struct GNUNET_MessageHeader *msg;
-
-  if (size < sizeof (struct GNUNET_MessageHeader))
-  {
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return 0;                   /* client disconnected */
-  }
-  msg = (struct GNUNET_MessageHeader *) buf;
-  msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
-  msg->size = htons (sizeof (struct GNUNET_MessageHeader));
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-  return sizeof (struct GNUNET_MessageHeader);
-}
-
-
-/**
- * Handler for TEST message.
- *
- * @param cls closure (refers to service)
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_test (void *cls, struct GNUNET_SERVER_Client *client,
-             const struct GNUNET_MessageHeader *message)
-{
-  /* simply bounce message back to acknowledge */
-  if (NULL ==
-      GNUNET_SERVER_notify_transmit_ready (client,
-                                           sizeof (struct 
GNUNET_MessageHeader),
-                                           GNUNET_TIME_UNIT_FOREVER_REL,
-                                           &write_test, client))
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-}
-
-
-/**
- * Default handlers for all services.  Will be copied and the
- * "callback_cls" fields will be replaced with the specific service
- * struct.
- */
-static const struct GNUNET_SERVER_MessageHandler defhandlers[] = {
-  {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST,
-   sizeof (struct GNUNET_MessageHeader)},
-  {NULL, NULL, 0, 0}
-};
-
-
-/* ****************** service core routines ************** */
-
-
-/**
- * Check if access to the service is allowed from the given address.
- *
- * @param cls closure
- * @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
- *   for unknown address family (will be denied).
- */
-static int
-check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
-              const struct sockaddr *addr, socklen_t addrlen)
-{
-  struct GNUNET_SERVICE_Context *sctx = cls;
-  const struct sockaddr_in *i4;
-  const struct sockaddr_in6 *i6;
-  int ret;
-
-  switch (addr->sa_family)
-  {
-  case AF_INET:
-    GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
-    i4 = (const struct sockaddr_in *) addr;
-    ret = ((NULL == sctx->v4_allowed) ||
-           (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
-        ((NULL == sctx->v4_denied) ||
-         (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
-    break;
-  case AF_INET6:
-    GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
-    i6 = (const struct sockaddr_in6 *) addr;
-    ret = ((NULL == sctx->v6_allowed) ||
-           (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
-        ((NULL == sctx->v6_denied) ||
-         (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
-    break;
-#ifndef WINDOWS
-  case AF_UNIX:
-    ret = GNUNET_OK;            /* controlled using file-system ACL now */
-    break;
-#endif
-  default:
-    LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"),
-         addr->sa_family);
-    return GNUNET_SYSERR;
-  }
-  if (GNUNET_OK != ret)
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         _("Access from `%s' denied to service `%s'\n"),
-        GNUNET_a2s (addr, addrlen),
-         sctx->service_name);
-  }
-  return ret;
-}
-
-
-/**
- * Get the name of the file where we will
- * write the PID of the service.
- *
- * @param sctx service context
- * @return name of the file for the process ID
- */
-static char *
-get_pid_file_name (struct GNUNET_SERVICE_Context *sctx)
-{
-  char *pif;
-
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
-                                               "PIDFILE", &pif))
-    return NULL;
-  return pif;
-}
-
-
-/**
- * Parse an IPv4 access control list.
- *
- * @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
-process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
-              struct GNUNET_SERVICE_Context *sctx,
-              const char *option)
-{
-  char *opt;
-
-  if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
-  {
-    *ret = NULL;
-    return GNUNET_OK;
-  }
-  GNUNET_break (GNUNET_OK ==
-                GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
-                                                       sctx->service_name,
-                                                       option, &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"),
-         opt, sctx->service_name, option);
-    GNUNET_free (opt);
-    return GNUNET_SYSERR;
-  }
-  GNUNET_free (opt);
-  return GNUNET_OK;
-}
-
-
-/**
- * Parse an IPv6 access control list.
- *
- * @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
-process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
-              struct GNUNET_SERVICE_Context *sctx,
-              const char *option)
-{
-  char *opt;
-
-  if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
-  {
-    *ret = NULL;
-    return GNUNET_OK;
-  }
-  GNUNET_break (GNUNET_OK ==
-                GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
-                                                       sctx->service_name,
-                                                       option, &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"),
-         opt, sctx->service_name, option);
-    GNUNET_free (opt);
-    return GNUNET_SYSERR;
-  }
-  GNUNET_free (opt);
-  return GNUNET_OK;
-}
-
-
-/**
- * Add the given UNIX domain path as an address to the
- * list (as the first entry).
- *
- * @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
-add_unixpath (struct sockaddr **saddrs,
-              socklen_t *saddrlens,
-              const char *unixpath,
-              int abstract)
-{
-#ifdef AF_UNIX
-  struct sockaddr_un *un;
-
-  un = GNUNET_new (struct sockaddr_un);
-  un->sun_family = AF_UNIX;
-  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
-  un->sun_len = (u_char) sizeof (struct sockaddr_un);
-#endif
-  *saddrs = (struct sockaddr *) un;
-  *saddrlens = sizeof (struct sockaddr_un);
-#else
-  /* this function should never be called
-   * unless AF_UNIX is defined! */
-  GNUNET_assert (0);
-#endif
-}
-
-
-/**
- * Get the list of addresses that a server for the given service
- * should bind to.
- *
- * @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
- *              of the respective `struct sockaddr` struct in the @a addrs
- *              array (on success)
- * @return number of addresses found on success,
- *              #GNUNET_SYSERR if the configuration
- *              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
- *              set to NULL).
- */
-int
-GNUNET_SERVICE_get_server_addresses (const char *service_name,
-                                     const struct GNUNET_CONFIGURATION_Handle 
*cfg,
-                                     struct sockaddr ***addrs,
-                                     socklen_t ** addr_lens)
-{
-  int disablev6;
-  struct GNUNET_NETWORK_Handle *desc;
-  unsigned long long port;
-  char *unixpath;
-  struct addrinfo hints;
-  struct addrinfo *res;
-  struct addrinfo *pos;
-  struct addrinfo *next;
-  unsigned int i;
-  int resi;
-  int ret;
-  int abstract;
-  struct sockaddr **saddrs;
-  socklen_t *saddrlens;
-  char *hostname;
-
-  *addrs = NULL;
-  *addr_lens = NULL;
-  desc = NULL;
-  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
-  {
-    if (GNUNET_SYSERR ==
-        (disablev6 =
-         GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, 
"DISABLEV6")))
-      return GNUNET_SYSERR;
-  }
-  else
-    disablev6 = GNUNET_NO;
-
-  if (! disablev6)
-  {
-    /* probe IPv6 support */
-    desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
-    if (NULL == desc)
-    {
-      if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
-          (EACCES == errno))
-      {
-        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
-        return GNUNET_SYSERR;
-      }
-      LOG (GNUNET_ERROR_TYPE_INFO,
-           _("Disabling IPv6 support for service `%s', failed to create IPv6 
socket: %s\n"),
-           service_name, STRERROR (errno));
-      disablev6 = GNUNET_YES;
-    }
-    else
-    {
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
-      desc = NULL;
-    }
-  }
-
-  port = 0;
-  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "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"),
-           service_name);
-      return GNUNET_SYSERR;
-    }
-  }
-
-  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
-  {
-    GNUNET_break (GNUNET_OK ==
-                  GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
-                                                         "BINDTO", &hostname));
-  }
-  else
-    hostname = NULL;
-
-  unixpath = NULL;
-  abstract = GNUNET_NO;
-#ifdef AF_UNIX
-  if ((GNUNET_YES ==
-       GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
-      (GNUNET_OK ==
-       GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
-                                              &unixpath)) &&
-      (0 < strlen (unixpath)))
-  {
-    /* probe UNIX support */
-    struct sockaddr_un s_un;
-
-    if (strlen (unixpath) >= sizeof (s_un.sun_path))
-    {
-      LOG (GNUNET_ERROR_TYPE_WARNING,
-           _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
-           (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)
-    {
-      if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
-          (EACCES == errno))
-      {
-        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
-        GNUNET_free_non_null (hostname);
-        GNUNET_free (unixpath);
-        return GNUNET_SYSERR;
-      }
-      LOG (GNUNET_ERROR_TYPE_INFO,
-           _("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;
-    }
-    else
-    {
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
-      desc = NULL;
-    }
-  }
-#endif
-
-  if ((0 == port) && (NULL == unixpath))
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR,
-         _("Have neither PORT nor UNIXPATH for service `%s', but one is 
required\n"),
-         service_name);
-    GNUNET_free_non_null (hostname);
-    return GNUNET_SYSERR;
-  }
-  if (0 == port)
-  {
-    saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
-    saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
-    add_unixpath (saddrs, saddrlens, unixpath, abstract);
-    GNUNET_free_non_null (unixpath);
-    GNUNET_free_non_null (hostname);
-    *addrs = saddrs;
-    *addr_lens = saddrlens;
-    return 1;
-  }
-
-  if (NULL != hostname)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "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;
-    hints.ai_protocol = IPPROTO_TCP;
-    if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
-        (NULL == res))
-    {
-      LOG (GNUNET_ERROR_TYPE_ERROR,
-           _("Failed to resolve `%s': %s\n"),
-           hostname,
-           gai_strerror (ret));
-      GNUNET_free (hostname);
-      GNUNET_free_non_null (unixpath);
-      return GNUNET_SYSERR;
-    }
-    next = res;
-    i = 0;
-    while (NULL != (pos = next))
-    {
-      next = pos->ai_next;
-      if ((disablev6) && (pos->ai_family == AF_INET6))
-        continue;
-      i++;
-    }
-    if (0 == i)
-    {
-      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);
-      return GNUNET_SYSERR;
-    }
-    resi = i;
-    if (NULL != unixpath)
-      resi++;
-    saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
-    saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
-    i = 0;
-    if (NULL != unixpath)
-    {
-      add_unixpath (saddrs, saddrlens, unixpath, abstract);
-      i++;
-    }
-    next = res;
-    while (NULL != (pos = next))
-    {
-      next = pos->ai_next;
-      if ((disablev6) && (AF_INET6 == pos->ai_family))
-        continue;
-      if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
-        continue;               /* not TCP */
-      if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
-        continue;               /* huh? */
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
-           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);
-        saddrlens[i] = pos->ai_addrlen;
-        saddrs[i] = GNUNET_malloc (saddrlens[i]);
-        GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
-        ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
-      }
-      else
-      {
-        GNUNET_assert (AF_INET6 == pos->ai_family);
-        GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
-        saddrlens[i] = pos->ai_addrlen;
-        saddrs[i] = GNUNET_malloc (saddrlens[i]);
-        GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
-        ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
-      }
-      i++;
-    }
-    GNUNET_free (hostname);
-    freeaddrinfo (res);
-    resi = i;
-  }
-  else
-  {
-    /* will bind against everything, just set port */
-    if (disablev6)
-    {
-      /* V4-only */
-      resi = 1;
-      if (NULL != unixpath)
-        resi++;
-      i = 0;
-      saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
-      saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
-      if (NULL != unixpath)
-      {
-        add_unixpath (saddrs, saddrlens, unixpath, abstract);
-        i++;
-      }
-      saddrlens[i] = sizeof (struct sockaddr_in);
-      saddrs[i] = GNUNET_malloc (saddrlens[i]);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-      ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
-#endif
-      ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
-      ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
-    }
-    else
-    {
-      /* dual stack */
-      resi = 2;
-      if (NULL != unixpath)
-        resi++;
-      saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
-      saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
-      i = 0;
-      if (NULL != unixpath)
-      {
-        add_unixpath (saddrs, saddrlens, unixpath, abstract);
-        i++;
-      }
-      saddrlens[i] = sizeof (struct sockaddr_in6);
-      saddrs[i] = GNUNET_malloc (saddrlens[i]);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-      ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
-#endif
-      ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
-      ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
-      i++;
-      saddrlens[i] = sizeof (struct sockaddr_in);
-      saddrs[i] = GNUNET_malloc (saddrlens[i]);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-      ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
-#endif
-      ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
-      ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
-    }
-  }
-  GNUNET_free_non_null (unixpath);
-  *addrs = saddrs;
-  *addr_lens = saddrlens;
-  return resi;
-}
-
-
-#ifdef MINGW
-/**
- * Read listen sockets from the parent process (ARM).
- *
- * @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)
-{
-  const char *env_buf;
-  int fail;
-  uint64_t count;
-  uint64_t i;
-  HANDLE lsocks_pipe;
-
-  env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
-  if ((NULL == env_buf) || (strlen (env_buf) <= 0))
-    return GNUNET_NO;
-  /* Using W32 API directly here, because this pipe will
-   * never be used outside of this function, and it's just too much of a bother
-   * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
-   */
-  lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
-  if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
-    return GNUNET_NO;
-  fail = 1;
-  do
-  {
-    int ret;
-    int fail2;
-    DWORD rd;
-
-    ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
-    if ((0 == ret) || (sizeof (count) != rd) || (0 == count))
-      break;
-    sctx->lsocks =
-        GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
-
-    fail2 = 1;
-    for (i = 0; i < count; i++)
-    {
-      WSAPROTOCOL_INFOA pi;
-      uint64_t size;
-      SOCKET s;
-
-      ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
-      if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) )
-        break;
-      ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
-      if ( (0 == ret) || (sizeof (pi) != rd))
-        break;
-      s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, 
WSA_FLAG_OVERLAPPED);
-      sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
-      if (NULL == sctx->lsocks[i])
-        break;
-      else if (i == count - 1)
-        fail2 = 0;
-    }
-    if (fail2)
-      break;
-    sctx->lsocks[count] = NULL;
-    fail = 0;
-  }
-  while (fail);
-
-  CloseHandle (lsocks_pipe);
-
-  if (fail)
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR,
-         _("Could not access a pre-bound socket, will try to bind myself\n"));
-    for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++)
-      GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i]));
-    GNUNET_free_non_null (sctx->lsocks);
-    sctx->lsocks = NULL;
-    return GNUNET_NO;
-  }
-  return GNUNET_YES;
-}
-#endif
-
-
-/**
- * Setup addr, addrlen, idle_timeout
- * based on configuration!
- *
- * Configuration may specify:
- * - PORT (where to bind to for TCP)
- * - UNIXPATH (where to bind to for UNIX domain sockets)
- * - TIMEOUT (after how many ms does an inactive service timeout);
- * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
- * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
- * - ACCEPT_FROM  (only allow connections from specified IPv4 subnets)
- * - ACCEPT_FROM6 (only 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 service context to initialize
- * @return #GNUNET_OK if configuration succeeded
- */
-static int
-setup_service (struct GNUNET_SERVICE_Context *sctx)
-{
-  struct GNUNET_TIME_Relative idleout;
-  int tolerant;
-
-#ifndef MINGW
-  const char *nfds;
-  unsigned int cnt;
-  int flags;
-#endif
-
-  if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, 
"TIMEOUT"))
-  {
-    if (GNUNET_OK !=
-        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", sctx->service_name);
-      return GNUNET_SYSERR;
-    }
-    sctx->timeout = idleout;
-  }
-  else
-    sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
-
-  if (GNUNET_CONFIGURATION_have_value
-      (sctx->cfg, sctx->service_name, "TOLERANT"))
-  {
-    if (GNUNET_SYSERR ==
-        (tolerant =
-         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", sctx->service_name);
-      return GNUNET_SYSERR;
-    }
-  }
-  else
-    tolerant = GNUNET_NO;
-
-#ifndef MINGW
-  errno = 0;
-  if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
-      (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
-      (cnt + 4 < FD_SETSIZE))
-  {
-    sctx->lsocks =
-        GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1));
-    while (0 < cnt--)
-    {
-      flags = fcntl (3 + cnt, F_GETFD);
-      if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
-          (NULL ==
-           (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
-      {
-        LOG (GNUNET_ERROR_TYPE_ERROR,
-             _
-             ("Could not access pre-bound socket %u, will try to bind 
myself\n"),
-             (unsigned int) 3 + cnt);
-        cnt++;
-        while (sctx->lsocks[cnt] != NULL)
-          GNUNET_break (0 == GNUNET_NETWORK_socket_close 
(sctx->lsocks[cnt++]));
-        GNUNET_free (sctx->lsocks);
-        sctx->lsocks = NULL;
-        break;
-      }
-    }
-    unsetenv ("LISTEN_FDS");
-  }
-#else
-  if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
-  {
-    receive_sockets_from_parent (sctx);
-    putenv ("GNUNET_OS_READ_LSOCKS=");
-  }
-#endif
-
-  if ((NULL == sctx->lsocks) &&
-      (GNUNET_SYSERR ==
-       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 =
-      GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
-                                            "UNIX_MATCH_UID");
-  sctx->match_gid =
-      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");
-  process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
-  process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
-
-  return GNUNET_OK;
-}
-
-
-/**
- * Get the name of the user that'll be used
- * to provide the service.
- *
- * @param sctx service context
- * @return value of the 'USERNAME' option
- */
-static char *
-get_user_name (struct GNUNET_SERVICE_Context *sctx)
-{
-  char *un;
-
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
-                                               "USERNAME", &un))
-    return NULL;
-  return un;
-}
-
-
-/**
- * Write PID file.
- *
- * @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)
-{
-  FILE *pidfd;
-  char *pif;
-  char *user;
-  char *rdir;
-  int len;
-
-  if (NULL == (pif = get_pid_file_name (sctx)))
-    return GNUNET_OK;           /* no file desired */
-  user = get_user_name (sctx);
-  rdir = GNUNET_strdup (pif);
-  len = strlen (rdir);
-  while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
-    len--;
-  rdir[len] = '\0';
-  if (0 != ACCESS (rdir, F_OK))
-  {
-    /* we get to create a directory -- and claim it
-     * as ours! */
-    (void) GNUNET_DISK_directory_create (rdir);
-    if ((NULL != user) && (0 < strlen (user)))
-      GNUNET_DISK_file_change_owner (rdir, user);
-  }
-  if (0 != ACCESS (rdir, W_OK | X_OK))
-  {
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
-    GNUNET_free (rdir);
-    GNUNET_free_non_null (user);
-    GNUNET_free (pif);
-    return GNUNET_SYSERR;
-  }
-  GNUNET_free (rdir);
-  pidfd = FOPEN (pif, "w");
-  if (NULL == pidfd)
-  {
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
-    GNUNET_free (pif);
-    GNUNET_free_non_null (user);
-    return GNUNET_SYSERR;
-  }
-  if (0 > FPRINTF (pidfd, "%u", pid))
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
-  GNUNET_break (0 == FCLOSE (pidfd));
-  if ((NULL != user) && (0 < strlen (user)))
-    GNUNET_DISK_file_change_owner (pif, user);
-  GNUNET_free_non_null (user);
-  GNUNET_free (pif);
-  return GNUNET_OK;
-}
-
-
-/**
- * Task run during shutdown.  Stops the server/service.
- *
- * @param cls the `struct GNUNET_SERVICE_Context`
- */
-static void
-shutdown_task (void *cls)
-{
-  struct GNUNET_SERVICE_Context *service = cls;
-  struct GNUNET_SERVER_Handle *server = service->server;
-
-  service->shutdown_task = NULL;
-  if (0 != (service->options & GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN))
-    GNUNET_SERVER_stop_listening (server);
-  else
-    GNUNET_SERVER_destroy (server);
-}
-
-
-/**
- * Initial task for the service.
- *
- * @param cls service context
- */
-static void
-service_task (void *cls)
-{
-  struct GNUNET_SERVICE_Context *sctx = cls;
-  unsigned int i;
-
-  (void) GNUNET_SPEEDUP_start_ (sctx->cfg);
-  GNUNET_RESOLVER_connect (sctx->cfg);
-  if (NULL != sctx->lsocks)
-    sctx->server
-      = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
-                                           sctx->timeout, sctx->require_found);
-  else
-    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)
-      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;
-  }
-#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 */
-    sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
-                                                        sctx);
-  }
-  sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
-  GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
-  i = 0;
-  while (NULL != sctx->my_handlers[i].callback)
-    sctx->my_handlers[i++].callback_cls = sctx;
-  GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
-  if (-1 != sctx->ready_confirm_fd)
-  {
-    GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1));
-    GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd));
-    sctx->ready_confirm_fd = -1;
-    write_pid_file (sctx, getpid ());
-  }
-  if (NULL != sctx->addrs)
-  {
-    i = 0;
-    while (NULL != sctx->addrs[i])
-    {
-      LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
-           sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
-      i++;
-    }
-  }
-  sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
-}
-
-
-/**
- * Detach from terminal.
- *
- * @param sctx service context
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-detach_terminal (struct GNUNET_SERVICE_Context *sctx)
-{
-#ifndef MINGW
-  pid_t pid;
-  int nullfd;
-  int filedes[2];
-
-  if (0 != PIPE (filedes))
-  {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
-    return GNUNET_SYSERR;
-  }
-  pid = fork ();
-  if (pid < 0)
-  {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
-    return GNUNET_SYSERR;
-  }
-  if (0 != pid)
-  {
-    /* Parent */
-    char c;
-
-    GNUNET_break (0 == CLOSE (filedes[1]));
-    c = 'X';
-    if (1 != READ (filedes[0], &c, sizeof (char)))
-      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
-    fflush (stdout);
-    switch (c)
-    {
-    case '.':
-      exit (0);
-    case 'I':
-      LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to 
initialize\n"));
-      break;
-    case 'S':
-      LOG (GNUNET_ERROR_TYPE_INFO,
-           _("Service process could not initialize server function\n"));
-      break;
-    case 'X':
-      LOG (GNUNET_ERROR_TYPE_INFO,
-           _("Service process failed to report status\n"));
-      break;
-    }
-    exit (1);                   /* child reported error */
-  }
-  GNUNET_break (0 == CLOSE (0));
-  GNUNET_break (0 == CLOSE (1));
-  GNUNET_break (0 == CLOSE (filedes[0]));
-  nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND);
-  if (nullfd < 0)
-    return GNUNET_SYSERR;
-  /* set stdin/stdout to /dev/null */
-  if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
-  {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
-    (void) CLOSE (nullfd);
-    return GNUNET_SYSERR;
-  }
-  (void) CLOSE (nullfd);
-  /* Detach from controlling terminal */
-  pid = setsid ();
-  if (-1 == pid)
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
-  sctx->ready_confirm_fd = filedes[1];
-#else
-  /* FIXME: we probably need to do something else
-   * elsewhere in order to fork the process itself... */
-  FreeConsole ();
-#endif
-  return GNUNET_OK;
-}
-
-
-/**
- * Set user ID.
- *
- * @param sctx service context
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-set_user_id (struct GNUNET_SERVICE_Context *sctx)
-{
-  char *user;
-
-  if (NULL == (user = get_user_name (sctx)))
-    return GNUNET_OK;           /* keep */
-#ifndef MINGW
-  struct passwd *pws;
-
-  errno = 0;
-  pws = getpwnam (user);
-  if (NULL == pws)
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR,
-         _("Cannot obtain information about user `%s': %s\n"), user,
-         errno == 0 ? _("No such user") : STRERROR (errno));
-    GNUNET_free (user);
-    return GNUNET_SYSERR;
-  }
-  if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
-#if HAVE_INITGROUPS
-      (0 != initgroups (user, pws->pw_gid)) ||
-#endif
-      (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
-  {
-    if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
-        (0 != setreuid (pws->pw_uid, pws->pw_uid)))
-    {
-      LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s': 
%s\n"),
-           user, STRERROR (errno));
-      GNUNET_free (user);
-      return GNUNET_SYSERR;
-    }
-  }
-#endif
-  GNUNET_free (user);
-  return GNUNET_OK;
-}
-
-
-/**
- * Delete the PID file that was created by our parent.
- *
- * @param sctx service context
- */
-static void
-pid_file_delete (struct GNUNET_SERVICE_Context *sctx)
-{
-  char *pif = get_pid_file_name (sctx);
-
-  if (NULL == pif)
-    return;                     /* no PID file */
-  if (0 != UNLINK (pif))
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
-  GNUNET_free (pif);
-}
-
-
-/**
- * Run a standard GNUnet service startup sequence (initialize loggers
- * and configuration, parse options).
- *
- * @param argc number of command line arguments
- * @param argv command line arguments
- * @param service_name our service name
- * @param options service options
- * @param task main task of the service
- * @param task_cls closure for @a task
- * @return #GNUNET_SYSERR on error, #GNUNET_OK
- *         if we shutdown nicely
- */
-int
-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;
-  int ret;
-  char *cfg_fn;
-  char *opt_cfg_fn;
-  char *loglev;
-  char *logfile;
-  int do_daemonize;
-  unsigned int i;
-  unsigned long long skew_offset;
-  unsigned long long skew_variance;
-  long long clock_offset;
-  struct GNUNET_SERVICE_Context sctx;
-  struct GNUNET_CONFIGURATION_Handle *cfg;
-  const char *xdg;
-
-  struct GNUNET_GETOPT_CommandLineOption service_options[] = {
-    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),
-    GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
-    GNUNET_GETOPT_OPTION_END
-  };
-  err = 1;
-  do_daemonize = 0;
-  logfile = NULL;
-  loglev = NULL;
-  opt_cfg_fn = NULL;
-  xdg = getenv ("XDG_CONFIG_HOME");
-  if (NULL != xdg)
-    GNUNET_asprintf (&cfg_fn,
-                     "%s%s%s",
-                     xdg,
-                     DIR_SEPARATOR_STR,
-                     GNUNET_OS_project_data_get ()->config_file);
-  else
-    cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
-  memset (&sctx, 0, sizeof (sctx));
-  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.service_name = service_name;
-  sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
-
-  /* setup subsystems */
-  ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
-  if (GNUNET_SYSERR == ret)
-    goto shutdown;
-  if (GNUNET_NO == ret)
-  {
-    err = 0;
-    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)))
-    HANDLE_ERROR;
-  if (GNUNET_OK != set_user_id (&sctx))
-    goto shutdown;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "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)) &&
-      (GNUNET_OK ==
-       GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
-                                              "SKEW_VARIANCE", 
&skew_variance)))
-  {
-    clock_offset = skew_offset - skew_variance;
-    GNUNET_TIME_set_offset (clock_offset);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
-  }
-  /* actually run service */
-  err = 0;
-  GNUNET_SCHEDULER_run (&service_task, &sctx);
-  /* shutdown */
-  if ((1 == do_daemonize) && (NULL != sctx.server))
-    pid_file_delete (&sctx);
-  GNUNET_free_non_null (sctx.my_handlers);
-
-shutdown:
-  if (-1 != sctx.ready_confirm_fd)
-  {
-    if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1))
-      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)
-    while (NULL != sctx.addrs[i])
-      GNUNET_free (sctx.addrs[i++]);
-  GNUNET_free_non_null (sctx.addrs);
-  GNUNET_free_non_null (sctx.addrlens);
-  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.v6_allowed);
-
-  return err ? GNUNET_SYSERR : sctx.ret;
-}
-
-
-/**
- * Run a service startup sequence within an existing
- * initialized system.
- *
- * @param service_name our service name
- * @param cfg configuration to use
- * @param options service options
- * @return NULL on error, service handle
- */
-struct GNUNET_SERVICE_Context *
-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;
-
-  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->service_name = service_name;
-  sctx->cfg = cfg;
-  sctx->options = options;
-
-  /* setup subsystems */
-  if (GNUNET_OK != setup_service (sctx))
-  {
-    GNUNET_SERVICE_stop (sctx);
-    return NULL;
-  }
-  if (NULL != sctx->lsocks)
-    sctx->server =
-        GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
-                                           sctx->timeout, sctx->require_found);
-  else
-    sctx->server =
-        GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
-                              sctx->timeout, sctx->require_found);
-
-  if (NULL == sctx->server)
-  {
-    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));
-  GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
-  i = 0;
-  while ((sctx->my_handlers[i].callback != NULL))
-    sctx->my_handlers[i++].callback_cls = sctx;
-  GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
-  return sctx;
-}
-
-
-/**
- * Obtain the server used by a service.  Note that the server must NOT
- * be destroyed by the caller.
- *
- * @param ctx the service context returned from the start function
- * @return handle to the server for this service, NULL if there is none
- */
-struct GNUNET_SERVER_Handle *
-GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx)
-{
-  return ctx->server;
-}
-
-
-/**
- * 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".
- *
- * @param sctx the service context returned from the start function
- */
-void
-GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx)
-{
-  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->addrs)
-  {
-    i = 0;
-    while (NULL != sctx->addrs[i])
-      GNUNET_free (sctx->addrs[i++]);
-    GNUNET_free (sctx->addrs);
-  }
-  GNUNET_free_non_null (sctx->addrlens);
-  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->v6_allowed);
-  GNUNET_free (sctx);
-}
-
-
-/* end of service.c */

Added: gnunet/src/util/service.c
===================================================================
--- gnunet/src/util/service.c                           (rev 0)
+++ gnunet/src/util/service.c   2016-10-23 16:03:54 UTC (rev 38186)
@@ -0,0 +1,1697 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009, 2012 GNUnet e.V.
+
+     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 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file util/service.c
+ * @brief functions related to starting services
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_constants.h"
+#include "gnunet_resolver_service.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_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", 
syscall)
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file 
(kind, "util", syscall, filename)
+
+
+/* ******************* access control ******************** */
+
+/**
+ * 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
+ */
+static int
+check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
+                   const struct in_addr *add)
+{
+  unsigned int i;
+
+  if (NULL == list)
+    return GNUNET_NO;
+  i = 0;
+  while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
+  {
+    if ((add->s_addr & list[i].netmask.s_addr) ==
+        (list[i].network.s_addr & list[i].netmask.s_addr))
+      return GNUNET_YES;
+    i++;
+  }
+  return GNUNET_NO;
+}
+
+
+/**
+ * Check if the given IP address is in the list of IP addresses.
+ *
+ * @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
+ */
+static int
+check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
+                   const struct in6_addr *ip)
+{
+  unsigned int i;
+  unsigned int j;
+  struct in6_addr zero;
+
+  if (NULL == list)
+    return GNUNET_NO;
+  memset (&zero, 0, sizeof (struct in6_addr));
+  i = 0;
+NEXT:
+  while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr)))
+  {
+    for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
+      if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
+          (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
+      {
+        i++;
+        goto NEXT;
+      }
+    return GNUNET_YES;
+  }
+  return GNUNET_NO;
+}
+
+
+/* ****************** service struct ****************** */
+
+
+/**
+ * Context for "service_task".
+ */
+struct GNUNET_SERVICE_Context
+{
+  /**
+   * Our configuration.
+   */
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * Handle for the server.
+   */
+  struct GNUNET_SERVER_Handle *server;
+
+  /**
+   * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
+   * listen sockets.
+   */
+  struct sockaddr **addrs;
+
+  /**
+   * Name of our service.
+   */
+  const char *service_name;
+
+  /**
+   * Main service-specific task to run.
+   */
+  GNUNET_SERVICE_Main task;
+
+  /**
+   * Closure for @e task.
+   */
+  void *task_cls;
+
+  /**
+   * IPv4 addresses that are not allowed to connect.
+   */
+  struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
+
+  /**
+   * IPv6 addresses that are not allowed to connect.
+   */
+  struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
+
+  /**
+   * IPv4 addresses that are allowed to connect (if not
+   * set, all are allowed).
+   */
+  struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
+
+  /**
+   * IPv6 addresses that are allowed to connect (if not
+   * set, all are allowed).
+   */
+  struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
+
+  /**
+   * My (default) message handlers.  Adjusted copy
+   * of "defhandlers".
+   */
+  struct GNUNET_SERVER_MessageHandler *my_handlers;
+
+  /**
+   * Array of the lengths of the entries in addrs.
+   */
+  socklen_t *addrlens;
+
+  /**
+   * NULL-terminated array of listen sockets we should take over.
+   */
+  struct GNUNET_NETWORK_Handle **lsocks;
+
+  /**
+   * Task ID of the shutdown task.
+   */
+  struct GNUNET_SCHEDULER_Task *shutdown_task;
+
+  /**
+   * Idle timeout for server.
+   */
+  struct GNUNET_TIME_Relative timeout;
+
+  /**
+   * Overall success/failure of the service start.
+   */
+  int ret;
+
+  /**
+   * If we are daemonizing, this FD is set to the
+   * pipe to the parent.  Send '.' if we started
+   * ok, '!' if not.  -1 if we are not daemonizing.
+   */
+  int ready_confirm_fd;
+
+  /**
+   * Do we close connections if we receive messages
+   * for which we have no handler?
+   */
+  int require_found;
+
+  /**
+   * Do we require a matching UID for UNIX domain socket connections?
+   * #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?
+   * 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
+   * 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;
+
+  /**
+   * Our options.
+   */
+  enum GNUNET_SERVICE_Options options;
+
+};
+
+
+/* ****************** message handlers ****************** */
+
+/**
+ * Send a 'TEST' message back to the client.
+ *
+ * @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)
+{
+  struct GNUNET_SERVER_Client *client = cls;
+  struct GNUNET_MessageHeader *msg;
+
+  if (size < sizeof (struct GNUNET_MessageHeader))
+  {
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return 0;                   /* client disconnected */
+  }
+  msg = (struct GNUNET_MessageHeader *) buf;
+  msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
+  msg->size = htons (sizeof (struct GNUNET_MessageHeader));
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  return sizeof (struct GNUNET_MessageHeader);
+}
+
+
+/**
+ * Handler for TEST message.
+ *
+ * @param cls closure (refers to service)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_test (void *cls, struct GNUNET_SERVER_Client *client,
+             const struct GNUNET_MessageHeader *message)
+{
+  /* simply bounce message back to acknowledge */
+  if (NULL ==
+      GNUNET_SERVER_notify_transmit_ready (client,
+                                           sizeof (struct 
GNUNET_MessageHeader),
+                                           GNUNET_TIME_UNIT_FOREVER_REL,
+                                           &write_test, client))
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+}
+
+
+/**
+ * Default handlers for all services.  Will be copied and the
+ * "callback_cls" fields will be replaced with the specific service
+ * struct.
+ */
+static const struct GNUNET_SERVER_MessageHandler defhandlers[] = {
+  {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST,
+   sizeof (struct GNUNET_MessageHeader)},
+  {NULL, NULL, 0, 0}
+};
+
+
+/* ****************** service core routines ************** */
+
+
+/**
+ * Check if access to the service is allowed from the given address.
+ *
+ * @param cls closure
+ * @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
+ *   for unknown address family (will be denied).
+ */
+static int
+check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
+              const struct sockaddr *addr, socklen_t addrlen)
+{
+  struct GNUNET_SERVICE_Context *sctx = cls;
+  const struct sockaddr_in *i4;
+  const struct sockaddr_in6 *i6;
+  int ret;
+
+  switch (addr->sa_family)
+  {
+  case AF_INET:
+    GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
+    i4 = (const struct sockaddr_in *) addr;
+    ret = ((NULL == sctx->v4_allowed) ||
+           (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
+        ((NULL == sctx->v4_denied) ||
+         (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
+    break;
+  case AF_INET6:
+    GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
+    i6 = (const struct sockaddr_in6 *) addr;
+    ret = ((NULL == sctx->v6_allowed) ||
+           (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
+        ((NULL == sctx->v6_denied) ||
+         (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
+    break;
+#ifndef WINDOWS
+  case AF_UNIX:
+    ret = GNUNET_OK;            /* controlled using file-system ACL now */
+    break;
+#endif
+  default:
+    LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"),
+         addr->sa_family);
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK != ret)
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         _("Access from `%s' denied to service `%s'\n"),
+        GNUNET_a2s (addr, addrlen),
+         sctx->service_name);
+  }
+  return ret;
+}
+
+
+/**
+ * Get the name of the file where we will
+ * write the PID of the service.
+ *
+ * @param sctx service context
+ * @return name of the file for the process ID
+ */
+static char *
+get_pid_file_name (struct GNUNET_SERVICE_Context *sctx)
+{
+  char *pif;
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
+                                               "PIDFILE", &pif))
+    return NULL;
+  return pif;
+}
+
+
+/**
+ * Parse an IPv4 access control list.
+ *
+ * @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
+process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
+              struct GNUNET_SERVICE_Context *sctx,
+              const char *option)
+{
+  char *opt;
+
+  if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
+  {
+    *ret = NULL;
+    return GNUNET_OK;
+  }
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
+                                                       sctx->service_name,
+                                                       option, &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"),
+         opt, sctx->service_name, option);
+    GNUNET_free (opt);
+    return GNUNET_SYSERR;
+  }
+  GNUNET_free (opt);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Parse an IPv6 access control list.
+ *
+ * @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
+process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
+              struct GNUNET_SERVICE_Context *sctx,
+              const char *option)
+{
+  char *opt;
+
+  if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
+  {
+    *ret = NULL;
+    return GNUNET_OK;
+  }
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
+                                                       sctx->service_name,
+                                                       option, &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"),
+         opt, sctx->service_name, option);
+    GNUNET_free (opt);
+    return GNUNET_SYSERR;
+  }
+  GNUNET_free (opt);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Add the given UNIX domain path as an address to the
+ * list (as the first entry).
+ *
+ * @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
+add_unixpath (struct sockaddr **saddrs,
+              socklen_t *saddrlens,
+              const char *unixpath,
+              int abstract)
+{
+#ifdef AF_UNIX
+  struct sockaddr_un *un;
+
+  un = GNUNET_new (struct sockaddr_un);
+  un->sun_family = AF_UNIX;
+  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
+  un->sun_len = (u_char) sizeof (struct sockaddr_un);
+#endif
+  *saddrs = (struct sockaddr *) un;
+  *saddrlens = sizeof (struct sockaddr_un);
+#else
+  /* this function should never be called
+   * unless AF_UNIX is defined! */
+  GNUNET_assert (0);
+#endif
+}
+
+
+/**
+ * Get the list of addresses that a server for the given service
+ * should bind to.
+ *
+ * @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
+ *              of the respective `struct sockaddr` struct in the @a addrs
+ *              array (on success)
+ * @return number of addresses found on success,
+ *              #GNUNET_SYSERR if the configuration
+ *              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
+ *              set to NULL).
+ */
+int
+GNUNET_SERVICE_get_server_addresses (const char *service_name,
+                                     const struct GNUNET_CONFIGURATION_Handle 
*cfg,
+                                     struct sockaddr ***addrs,
+                                     socklen_t ** addr_lens)
+{
+  int disablev6;
+  struct GNUNET_NETWORK_Handle *desc;
+  unsigned long long port;
+  char *unixpath;
+  struct addrinfo hints;
+  struct addrinfo *res;
+  struct addrinfo *pos;
+  struct addrinfo *next;
+  unsigned int i;
+  int resi;
+  int ret;
+  int abstract;
+  struct sockaddr **saddrs;
+  socklen_t *saddrlens;
+  char *hostname;
+
+  *addrs = NULL;
+  *addr_lens = NULL;
+  desc = NULL;
+  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
+  {
+    if (GNUNET_SYSERR ==
+        (disablev6 =
+         GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, 
"DISABLEV6")))
+      return GNUNET_SYSERR;
+  }
+  else
+    disablev6 = GNUNET_NO;
+
+  if (! disablev6)
+  {
+    /* probe IPv6 support */
+    desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
+    if (NULL == desc)
+    {
+      if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
+          (EACCES == errno))
+      {
+        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+        return GNUNET_SYSERR;
+      }
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Disabling IPv6 support for service `%s', failed to create IPv6 
socket: %s\n"),
+           service_name, STRERROR (errno));
+      disablev6 = GNUNET_YES;
+    }
+    else
+    {
+      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
+      desc = NULL;
+    }
+  }
+
+  port = 0;
+  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "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"),
+           service_name);
+      return GNUNET_SYSERR;
+    }
+  }
+
+  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
+  {
+    GNUNET_break (GNUNET_OK ==
+                  GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
+                                                         "BINDTO", &hostname));
+  }
+  else
+    hostname = NULL;
+
+  unixpath = NULL;
+  abstract = GNUNET_NO;
+#ifdef AF_UNIX
+  if ((GNUNET_YES ==
+       GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
+      (GNUNET_OK ==
+       GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
+                                              &unixpath)) &&
+      (0 < strlen (unixpath)))
+  {
+    /* probe UNIX support */
+    struct sockaddr_un s_un;
+
+    if (strlen (unixpath) >= sizeof (s_un.sun_path))
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING,
+           _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
+           (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)
+    {
+      if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
+          (EACCES == errno))
+      {
+        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+        GNUNET_free_non_null (hostname);
+        GNUNET_free (unixpath);
+        return GNUNET_SYSERR;
+      }
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("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;
+    }
+    else
+    {
+      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
+      desc = NULL;
+    }
+  }
+#endif
+
+  if ((0 == port) && (NULL == unixpath))
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Have neither PORT nor UNIXPATH for service `%s', but one is 
required\n"),
+         service_name);
+    GNUNET_free_non_null (hostname);
+    return GNUNET_SYSERR;
+  }
+  if (0 == port)
+  {
+    saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
+    saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
+    add_unixpath (saddrs, saddrlens, unixpath, abstract);
+    GNUNET_free_non_null (unixpath);
+    GNUNET_free_non_null (hostname);
+    *addrs = saddrs;
+    *addr_lens = saddrlens;
+    return 1;
+  }
+
+  if (NULL != hostname)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "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;
+    hints.ai_protocol = IPPROTO_TCP;
+    if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
+        (NULL == res))
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Failed to resolve `%s': %s\n"),
+           hostname,
+           gai_strerror (ret));
+      GNUNET_free (hostname);
+      GNUNET_free_non_null (unixpath);
+      return GNUNET_SYSERR;
+    }
+    next = res;
+    i = 0;
+    while (NULL != (pos = next))
+    {
+      next = pos->ai_next;
+      if ((disablev6) && (pos->ai_family == AF_INET6))
+        continue;
+      i++;
+    }
+    if (0 == i)
+    {
+      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);
+      return GNUNET_SYSERR;
+    }
+    resi = i;
+    if (NULL != unixpath)
+      resi++;
+    saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+    saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+    i = 0;
+    if (NULL != unixpath)
+    {
+      add_unixpath (saddrs, saddrlens, unixpath, abstract);
+      i++;
+    }
+    next = res;
+    while (NULL != (pos = next))
+    {
+      next = pos->ai_next;
+      if ((disablev6) && (AF_INET6 == pos->ai_family))
+        continue;
+      if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
+        continue;               /* not TCP */
+      if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
+        continue;               /* huh? */
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
+           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);
+        saddrlens[i] = pos->ai_addrlen;
+        saddrs[i] = GNUNET_malloc (saddrlens[i]);
+        GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+        ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+      }
+      else
+      {
+        GNUNET_assert (AF_INET6 == pos->ai_family);
+        GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
+        saddrlens[i] = pos->ai_addrlen;
+        saddrs[i] = GNUNET_malloc (saddrlens[i]);
+        GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+        ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
+      }
+      i++;
+    }
+    GNUNET_free (hostname);
+    freeaddrinfo (res);
+    resi = i;
+  }
+  else
+  {
+    /* will bind against everything, just set port */
+    if (disablev6)
+    {
+      /* V4-only */
+      resi = 1;
+      if (NULL != unixpath)
+        resi++;
+      i = 0;
+      saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+      saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+      if (NULL != unixpath)
+      {
+        add_unixpath (saddrs, saddrlens, unixpath, abstract);
+        i++;
+      }
+      saddrlens[i] = sizeof (struct sockaddr_in);
+      saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+      ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
+#endif
+      ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
+      ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+    }
+    else
+    {
+      /* dual stack */
+      resi = 2;
+      if (NULL != unixpath)
+        resi++;
+      saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+      saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+      i = 0;
+      if (NULL != unixpath)
+      {
+        add_unixpath (saddrs, saddrlens, unixpath, abstract);
+        i++;
+      }
+      saddrlens[i] = sizeof (struct sockaddr_in6);
+      saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+      ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
+#endif
+      ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
+      ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
+      i++;
+      saddrlens[i] = sizeof (struct sockaddr_in);
+      saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+      ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
+#endif
+      ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
+      ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+    }
+  }
+  GNUNET_free_non_null (unixpath);
+  *addrs = saddrs;
+  *addr_lens = saddrlens;
+  return resi;
+}
+
+
+#ifdef MINGW
+/**
+ * Read listen sockets from the parent process (ARM).
+ *
+ * @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)
+{
+  const char *env_buf;
+  int fail;
+  uint64_t count;
+  uint64_t i;
+  HANDLE lsocks_pipe;
+
+  env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
+  if ((NULL == env_buf) || (strlen (env_buf) <= 0))
+    return GNUNET_NO;
+  /* Using W32 API directly here, because this pipe will
+   * never be used outside of this function, and it's just too much of a bother
+   * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
+   */
+  lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
+  if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
+    return GNUNET_NO;
+  fail = 1;
+  do
+  {
+    int ret;
+    int fail2;
+    DWORD rd;
+
+    ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
+    if ((0 == ret) || (sizeof (count) != rd) || (0 == count))
+      break;
+    sctx->lsocks =
+        GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
+
+    fail2 = 1;
+    for (i = 0; i < count; i++)
+    {
+      WSAPROTOCOL_INFOA pi;
+      uint64_t size;
+      SOCKET s;
+
+      ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
+      if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) )
+        break;
+      ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
+      if ( (0 == ret) || (sizeof (pi) != rd))
+        break;
+      s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, 
WSA_FLAG_OVERLAPPED);
+      sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
+      if (NULL == sctx->lsocks[i])
+        break;
+      else if (i == count - 1)
+        fail2 = 0;
+    }
+    if (fail2)
+      break;
+    sctx->lsocks[count] = NULL;
+    fail = 0;
+  }
+  while (fail);
+
+  CloseHandle (lsocks_pipe);
+
+  if (fail)
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Could not access a pre-bound socket, will try to bind myself\n"));
+    for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++)
+      GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i]));
+    GNUNET_free_non_null (sctx->lsocks);
+    sctx->lsocks = NULL;
+    return GNUNET_NO;
+  }
+  return GNUNET_YES;
+}
+#endif
+
+
+/**
+ * Setup addr, addrlen, idle_timeout
+ * based on configuration!
+ *
+ * Configuration may specify:
+ * - PORT (where to bind to for TCP)
+ * - UNIXPATH (where to bind to for UNIX domain sockets)
+ * - TIMEOUT (after how many ms does an inactive service timeout);
+ * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
+ * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
+ * - ACCEPT_FROM  (only allow connections from specified IPv4 subnets)
+ * - ACCEPT_FROM6 (only 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 service context to initialize
+ * @return #GNUNET_OK if configuration succeeded
+ */
+static int
+setup_service (struct GNUNET_SERVICE_Context *sctx)
+{
+  struct GNUNET_TIME_Relative idleout;
+  int tolerant;
+
+#ifndef MINGW
+  const char *nfds;
+  unsigned int cnt;
+  int flags;
+#endif
+
+  if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, 
"TIMEOUT"))
+  {
+    if (GNUNET_OK !=
+        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", sctx->service_name);
+      return GNUNET_SYSERR;
+    }
+    sctx->timeout = idleout;
+  }
+  else
+    sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+
+  if (GNUNET_CONFIGURATION_have_value
+      (sctx->cfg, sctx->service_name, "TOLERANT"))
+  {
+    if (GNUNET_SYSERR ==
+        (tolerant =
+         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", sctx->service_name);
+      return GNUNET_SYSERR;
+    }
+  }
+  else
+    tolerant = GNUNET_NO;
+
+#ifndef MINGW
+  errno = 0;
+  if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
+      (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
+      (cnt + 4 < FD_SETSIZE))
+  {
+    sctx->lsocks =
+        GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1));
+    while (0 < cnt--)
+    {
+      flags = fcntl (3 + cnt, F_GETFD);
+      if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
+          (NULL ==
+           (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
+      {
+        LOG (GNUNET_ERROR_TYPE_ERROR,
+             _
+             ("Could not access pre-bound socket %u, will try to bind 
myself\n"),
+             (unsigned int) 3 + cnt);
+        cnt++;
+        while (sctx->lsocks[cnt] != NULL)
+          GNUNET_break (0 == GNUNET_NETWORK_socket_close 
(sctx->lsocks[cnt++]));
+        GNUNET_free (sctx->lsocks);
+        sctx->lsocks = NULL;
+        break;
+      }
+    }
+    unsetenv ("LISTEN_FDS");
+  }
+#else
+  if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
+  {
+    receive_sockets_from_parent (sctx);
+    putenv ("GNUNET_OS_READ_LSOCKS=");
+  }
+#endif
+
+  if ((NULL == sctx->lsocks) &&
+      (GNUNET_SYSERR ==
+       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 =
+      GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
+                                            "UNIX_MATCH_UID");
+  sctx->match_gid =
+      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");
+  process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
+  process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
+
+  return GNUNET_OK;
+}
+
+
+/**
+ * Get the name of the user that'll be used
+ * to provide the service.
+ *
+ * @param sctx service context
+ * @return value of the 'USERNAME' option
+ */
+static char *
+get_user_name (struct GNUNET_SERVICE_Context *sctx)
+{
+  char *un;
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
+                                               "USERNAME", &un))
+    return NULL;
+  return un;
+}
+
+
+/**
+ * Write PID file.
+ *
+ * @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)
+{
+  FILE *pidfd;
+  char *pif;
+  char *user;
+  char *rdir;
+  int len;
+
+  if (NULL == (pif = get_pid_file_name (sctx)))
+    return GNUNET_OK;           /* no file desired */
+  user = get_user_name (sctx);
+  rdir = GNUNET_strdup (pif);
+  len = strlen (rdir);
+  while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
+    len--;
+  rdir[len] = '\0';
+  if (0 != ACCESS (rdir, F_OK))
+  {
+    /* we get to create a directory -- and claim it
+     * as ours! */
+    (void) GNUNET_DISK_directory_create (rdir);
+    if ((NULL != user) && (0 < strlen (user)))
+      GNUNET_DISK_file_change_owner (rdir, user);
+  }
+  if (0 != ACCESS (rdir, W_OK | X_OK))
+  {
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
+    GNUNET_free (rdir);
+    GNUNET_free_non_null (user);
+    GNUNET_free (pif);
+    return GNUNET_SYSERR;
+  }
+  GNUNET_free (rdir);
+  pidfd = FOPEN (pif, "w");
+  if (NULL == pidfd)
+  {
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
+    GNUNET_free (pif);
+    GNUNET_free_non_null (user);
+    return GNUNET_SYSERR;
+  }
+  if (0 > FPRINTF (pidfd, "%u", pid))
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
+  GNUNET_break (0 == FCLOSE (pidfd));
+  if ((NULL != user) && (0 < strlen (user)))
+    GNUNET_DISK_file_change_owner (pif, user);
+  GNUNET_free_non_null (user);
+  GNUNET_free (pif);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Task run during shutdown.  Stops the server/service.
+ *
+ * @param cls the `struct GNUNET_SERVICE_Context`
+ */
+static void
+shutdown_task (void *cls)
+{
+  struct GNUNET_SERVICE_Context *service = cls;
+  struct GNUNET_SERVER_Handle *server = service->server;
+
+  service->shutdown_task = NULL;
+  if (0 != (service->options & GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN))
+    GNUNET_SERVER_stop_listening (server);
+  else
+    GNUNET_SERVER_destroy (server);
+}
+
+
+/**
+ * Initial task for the service.
+ *
+ * @param cls service context
+ */
+static void
+service_task (void *cls)
+{
+  struct GNUNET_SERVICE_Context *sctx = cls;
+  unsigned int i;
+
+  (void) GNUNET_SPEEDUP_start_ (sctx->cfg);
+  GNUNET_RESOLVER_connect (sctx->cfg);
+  if (NULL != sctx->lsocks)
+    sctx->server
+      = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
+                                           sctx->timeout, sctx->require_found);
+  else
+    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)
+      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;
+  }
+#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 */
+    sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+                                                        sctx);
+  }
+  sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
+  GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
+  i = 0;
+  while (NULL != sctx->my_handlers[i].callback)
+    sctx->my_handlers[i++].callback_cls = sctx;
+  GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
+  if (-1 != sctx->ready_confirm_fd)
+  {
+    GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1));
+    GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd));
+    sctx->ready_confirm_fd = -1;
+    write_pid_file (sctx, getpid ());
+  }
+  if (NULL != sctx->addrs)
+  {
+    i = 0;
+    while (NULL != sctx->addrs[i])
+    {
+      LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
+           sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
+      i++;
+    }
+  }
+  sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
+}
+
+
+/**
+ * Detach from terminal.
+ *
+ * @param sctx service context
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+detach_terminal (struct GNUNET_SERVICE_Context *sctx)
+{
+#ifndef MINGW
+  pid_t pid;
+  int nullfd;
+  int filedes[2];
+
+  if (0 != PIPE (filedes))
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
+    return GNUNET_SYSERR;
+  }
+  pid = fork ();
+  if (pid < 0)
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
+    return GNUNET_SYSERR;
+  }
+  if (0 != pid)
+  {
+    /* Parent */
+    char c;
+
+    GNUNET_break (0 == CLOSE (filedes[1]));
+    c = 'X';
+    if (1 != READ (filedes[0], &c, sizeof (char)))
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
+    fflush (stdout);
+    switch (c)
+    {
+    case '.':
+      exit (0);
+    case 'I':
+      LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to 
initialize\n"));
+      break;
+    case 'S':
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Service process could not initialize server function\n"));
+      break;
+    case 'X':
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Service process failed to report status\n"));
+      break;
+    }
+    exit (1);                   /* child reported error */
+  }
+  GNUNET_break (0 == CLOSE (0));
+  GNUNET_break (0 == CLOSE (1));
+  GNUNET_break (0 == CLOSE (filedes[0]));
+  nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND);
+  if (nullfd < 0)
+    return GNUNET_SYSERR;
+  /* set stdin/stdout to /dev/null */
+  if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
+    (void) CLOSE (nullfd);
+    return GNUNET_SYSERR;
+  }
+  (void) CLOSE (nullfd);
+  /* Detach from controlling terminal */
+  pid = setsid ();
+  if (-1 == pid)
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
+  sctx->ready_confirm_fd = filedes[1];
+#else
+  /* FIXME: we probably need to do something else
+   * elsewhere in order to fork the process itself... */
+  FreeConsole ();
+#endif
+  return GNUNET_OK;
+}
+
+
+/**
+ * Set user ID.
+ *
+ * @param sctx service context
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+set_user_id (struct GNUNET_SERVICE_Context *sctx)
+{
+  char *user;
+
+  if (NULL == (user = get_user_name (sctx)))
+    return GNUNET_OK;           /* keep */
+#ifndef MINGW
+  struct passwd *pws;
+
+  errno = 0;
+  pws = getpwnam (user);
+  if (NULL == pws)
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Cannot obtain information about user `%s': %s\n"), user,
+         errno == 0 ? _("No such user") : STRERROR (errno));
+    GNUNET_free (user);
+    return GNUNET_SYSERR;
+  }
+  if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
+#if HAVE_INITGROUPS
+      (0 != initgroups (user, pws->pw_gid)) ||
+#endif
+      (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
+  {
+    if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
+        (0 != setreuid (pws->pw_uid, pws->pw_uid)))
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s': 
%s\n"),
+           user, STRERROR (errno));
+      GNUNET_free (user);
+      return GNUNET_SYSERR;
+    }
+  }
+#endif
+  GNUNET_free (user);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Delete the PID file that was created by our parent.
+ *
+ * @param sctx service context
+ */
+static void
+pid_file_delete (struct GNUNET_SERVICE_Context *sctx)
+{
+  char *pif = get_pid_file_name (sctx);
+
+  if (NULL == pif)
+    return;                     /* no PID file */
+  if (0 != UNLINK (pif))
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
+  GNUNET_free (pif);
+}
+
+
+/**
+ * Run a standard GNUnet service startup sequence (initialize loggers
+ * and configuration, parse options).
+ *
+ * @param argc number of command line arguments
+ * @param argv command line arguments
+ * @param service_name our service name
+ * @param options service options
+ * @param task main task of the service
+ * @param task_cls closure for @a task
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK
+ *         if we shutdown nicely
+ */
+int
+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;
+  int ret;
+  char *cfg_fn;
+  char *opt_cfg_fn;
+  char *loglev;
+  char *logfile;
+  int do_daemonize;
+  unsigned int i;
+  unsigned long long skew_offset;
+  unsigned long long skew_variance;
+  long long clock_offset;
+  struct GNUNET_SERVICE_Context sctx;
+  struct GNUNET_CONFIGURATION_Handle *cfg;
+  const char *xdg;
+
+  struct GNUNET_GETOPT_CommandLineOption service_options[] = {
+    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),
+    GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
+    GNUNET_GETOPT_OPTION_END
+  };
+  err = 1;
+  do_daemonize = 0;
+  logfile = NULL;
+  loglev = NULL;
+  opt_cfg_fn = NULL;
+  xdg = getenv ("XDG_CONFIG_HOME");
+  if (NULL != xdg)
+    GNUNET_asprintf (&cfg_fn,
+                     "%s%s%s",
+                     xdg,
+                     DIR_SEPARATOR_STR,
+                     GNUNET_OS_project_data_get ()->config_file);
+  else
+    cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
+  memset (&sctx, 0, sizeof (sctx));
+  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.service_name = service_name;
+  sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
+
+  /* setup subsystems */
+  ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
+  if (GNUNET_SYSERR == ret)
+    goto shutdown;
+  if (GNUNET_NO == ret)
+  {
+    err = 0;
+    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)))
+    HANDLE_ERROR;
+  if (GNUNET_OK != set_user_id (&sctx))
+    goto shutdown;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "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)) &&
+      (GNUNET_OK ==
+       GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
+                                              "SKEW_VARIANCE", 
&skew_variance)))
+  {
+    clock_offset = skew_offset - skew_variance;
+    GNUNET_TIME_set_offset (clock_offset);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
+  }
+  /* actually run service */
+  err = 0;
+  GNUNET_SCHEDULER_run (&service_task, &sctx);
+  /* shutdown */
+  if ((1 == do_daemonize) && (NULL != sctx.server))
+    pid_file_delete (&sctx);
+  GNUNET_free_non_null (sctx.my_handlers);
+
+shutdown:
+  if (-1 != sctx.ready_confirm_fd)
+  {
+    if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1))
+      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)
+    while (NULL != sctx.addrs[i])
+      GNUNET_free (sctx.addrs[i++]);
+  GNUNET_free_non_null (sctx.addrs);
+  GNUNET_free_non_null (sctx.addrlens);
+  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.v6_allowed);
+
+  return err ? GNUNET_SYSERR : sctx.ret;
+}
+
+
+/**
+ * Run a service startup sequence within an existing
+ * initialized system.
+ *
+ * @param service_name our service name
+ * @param cfg configuration to use
+ * @param options service options
+ * @return NULL on error, service handle
+ */
+struct GNUNET_SERVICE_Context *
+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;
+
+  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->service_name = service_name;
+  sctx->cfg = cfg;
+  sctx->options = options;
+
+  /* setup subsystems */
+  if (GNUNET_OK != setup_service (sctx))
+  {
+    GNUNET_SERVICE_stop (sctx);
+    return NULL;
+  }
+  if (NULL != sctx->lsocks)
+    sctx->server =
+        GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
+                                           sctx->timeout, sctx->require_found);
+  else
+    sctx->server =
+        GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
+                              sctx->timeout, sctx->require_found);
+
+  if (NULL == sctx->server)
+  {
+    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));
+  GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
+  i = 0;
+  while ((sctx->my_handlers[i].callback != NULL))
+    sctx->my_handlers[i++].callback_cls = sctx;
+  GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
+  return sctx;
+}
+
+
+/**
+ * Obtain the server used by a service.  Note that the server must NOT
+ * be destroyed by the caller.
+ *
+ * @param ctx the service context returned from the start function
+ * @return handle to the server for this service, NULL if there is none
+ */
+struct GNUNET_SERVER_Handle *
+GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx)
+{
+  return ctx->server;
+}
+
+
+/**
+ * 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".
+ *
+ * @param sctx the service context returned from the start function
+ */
+void
+GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx)
+{
+  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->addrs)
+  {
+    i = 0;
+    while (NULL != sctx->addrs[i])
+      GNUNET_free (sctx->addrs[i++]);
+    GNUNET_free (sctx->addrs);
+  }
+  GNUNET_free_non_null (sctx->addrlens);
+  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->v6_allowed);
+  GNUNET_free (sctx);
+}
+
+
+/* end of service.c */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]