Пример #1
0
/**
 * Create a connection handle by (asynchronously) connecting to a host.
 * This function returns immediately, even if the connection has not
 * yet been established.  This function only creates TCP connections.
 *
 * @param af_family address family to use
 * @param serv_addr server address
 * @param addrlen length of server address
 * @return the connection handle
 */
struct GNUNET_CONNECTION_Handle *
GNUNET_CONNECTION_create_from_sockaddr (int af_family,
                                        const struct sockaddr *serv_addr,
                                        socklen_t addrlen)
{
  struct GNUNET_NETWORK_Handle *s;
  struct GNUNET_CONNECTION_Handle *connection;

  s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0);
  if (NULL == s)
  {
    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "socket");
    return NULL;
  }
  if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) &&
      (EINPROGRESS != errno))
  {
    /* maybe refused / unsupported address, try next */
    LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect");
    LOG (GNUNET_ERROR_TYPE_INFO, _("Attempt to connect to `%s' failed\n"),
         GNUNET_a2s (serv_addr, addrlen));
    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
    return NULL;
  }
  connection = GNUNET_CONNECTION_create_from_existing (s);
  connection->addr = GNUNET_malloc (addrlen);
  memcpy (connection->addr, serv_addr, addrlen);
  connection->addrlen = addrlen;
  LOG (GNUNET_ERROR_TYPE_INFO, _("Trying to connect to `%s' (%p)\n"),
       GNUNET_a2s (serv_addr, addrlen), connection);
  return connection;
}
Пример #2
0
int
main (int argc, char *argv[])
{
  int ret = 0;
  struct GNUNET_NETWORK_Handle *s = NULL;

  GNUNET_log_setup ("test-service",
                    "WARNING",
                    NULL);
  ret += check ();
  ret += check ();
  // FIXME
#ifndef MINGW
  s = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
#endif
  if (NULL == s)
  {
    if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) ||
        (errno == EACCES))
    {
      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
      return 1;
    }
    FPRINTF (stderr,
             "IPv6 support seems to not be available (%s), not testing it!\n",
             strerror (errno));
  }
  else
  {
    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
    ret += check6 ();
  }
  ret += check_start_stop ();
  return ret;
}
/**
 * Create and initialize a listen socket for the server.
 *
 * @return NULL on error, otherwise the listen socket
 */
static struct GNUNET_NETWORK_Handle *
open_listen_socket ()
{
  const static int on = 1;
  struct sockaddr_in sa;
  struct GNUNET_NETWORK_Handle *desc;

  memset (&sa, 0, sizeof (sa));
#if HAVE_SOCKADDR_IN_SIN_LEN
  sa.sin_len = sizeof (sa);
#endif
  sa.sin_family = AF_INET;
  sa.sin_port = htons (PORT);
  desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
  GNUNET_assert (desc != 0);
  if (GNUNET_NETWORK_socket_setsockopt
      (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt");
  if (GNUNET_OK !=
      GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa,
                                  sizeof (sa)))
  {
    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                         "bind");
    GNUNET_assert (0);
  }
  GNUNET_NETWORK_socket_listen (desc, 5);
  return desc;
}
Пример #4
0
/**
 * Create an IPv4 listen socket bound to our port.
 *
 * @return NULL on error
 */
static struct GNUNET_NETWORK_Handle *
bind_v4 ()
{
  struct GNUNET_NETWORK_Handle *ls;
  struct sockaddr_in sa4;
  int eno;

  memset (&sa4, 0, sizeof (sa4));
  sa4.sin_family = AF_INET;
  sa4.sin_port = htons (port);
#if HAVE_SOCKADDR_IN_SIN_LEN
  sa4.sin_len = sizeof (sa4);
#endif
  ls = GNUNET_NETWORK_socket_create (AF_INET,
                                     SOCK_DGRAM,
                                     0);
  if (NULL == ls)
    return NULL;
  if (GNUNET_OK !=
      GNUNET_NETWORK_socket_bind (ls,
                                  (const struct sockaddr *) &sa4,
                                  sizeof (sa4)))
  {
    eno = errno;
    GNUNET_NETWORK_socket_close (ls);
    errno = eno;
    return NULL;
  }
  return ls;
}
Пример #5
0
/**
 * Try to send 'data' to the
 * IP 'dst_ipv4' at port 'dport' via UDP.
 *
 * @param dst_ipv4 target IP
 * @param dport target port
 * @param data data to send
 */
static void
try_send_udp (uint32_t dst_ipv4, uint16_t dport, uint16_t data)
{
  struct GNUNET_NETWORK_Handle *s;
  struct sockaddr_in sa;

  s = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
  if (NULL == s)
  {
    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
    return;
  }
  memset (&sa, 0, sizeof (sa));
  sa.sin_family = AF_INET;
#if HAVE_SOCKADDR_IN_SIN_LEN
  sa.sin_len = sizeof (sa);
#endif
  sa.sin_addr.s_addr = dst_ipv4;
  sa.sin_port = htons (dport);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending UDP packet to `%s'\n",
              GNUNET_a2s ((struct sockaddr *) &sa, sizeof (sa)));
  if (-1 ==
      GNUNET_NETWORK_socket_sendto (s, &data, sizeof (data),
                                    (const struct sockaddr *) &sa, sizeof (sa)))
    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto");
  GNUNET_NETWORK_socket_close (s);
}
void
http_check_ipv6 (struct Plugin *plugin)
{
  struct GNUNET_NETWORK_Handle *desc = NULL;

  if (plugin->ipv6 == GNUNET_YES)
  {
    /* probe IPv6 support */
    desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
    if (NULL == desc)
    {
      if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) ||
          (errno == EACCES))
      {
        GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
      }
      GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
                       _
                       ("Disabling IPv6 since it is not supported on this system!\n"));
      plugin->ipv6 = GNUNET_NO;
    }
    else
    {
      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
      desc = NULL;
    }

    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
                     "Testing IPv6 on this system: %s\n",
                     (plugin->ipv6 == GNUNET_YES) ? "successful" : "failed");
  }
}
Пример #7
0
/**
 * Try to send 'data' to the
 * IP 'dst_ipv4' at port 'dport' via TCP.
 *
 * @param dst_ipv4 target IP
 * @param dport target port
 * @param data data to send
 */
static void
try_send_tcp (uint32_t dst_ipv4, uint16_t dport, uint16_t data)
{
  struct GNUNET_NETWORK_Handle *s;
  struct sockaddr_in sa;
  struct TcpContext *ctx;

  s = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
  if (NULL == s)
  {
    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
    return;
  }
  memset (&sa, 0, sizeof (sa));
  sa.sin_family = AF_INET;
#if HAVE_SOCKADDR_IN_SIN_LEN
  sa.sin_len = sizeof (sa);
#endif
  sa.sin_addr.s_addr = dst_ipv4;
  sa.sin_port = htons (dport);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TCP message to `%s'\n",
              GNUNET_a2s ((struct sockaddr *) &sa, sizeof (sa)));
  if ((GNUNET_OK !=
       GNUNET_NETWORK_socket_connect (s, (const struct sockaddr *) &sa,
                                      sizeof (sa))) && (errno != EINPROGRESS))
  {
    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect");
    GNUNET_NETWORK_socket_close (s);
    return;
  }
  ctx = GNUNET_malloc (sizeof (struct TcpContext));
  ctx->s = s;
  ctx->data = data;
  GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS, s, &tcp_send, ctx);
}
Пример #8
0
/**
 * Create a connection handle by connecting to a UNIX domain service.
 * This function returns immediately, even if the connection has not
 * yet been established.  This function only creates UNIX connections.
 *
 * @param cfg configuration to use
 * @param unixpath path to connect to
 * @return the connection handle, NULL on systems without UNIX support
 */
struct GNUNET_CONNECTION_Handle *
GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct
                                                   GNUNET_CONFIGURATION_Handle
                                                   *cfg, const char *unixpath)
{
#ifdef AF_UNIX
  struct GNUNET_CONNECTION_Handle *connection;
  struct sockaddr_un *un;
  size_t slen;

  GNUNET_assert (0 < strlen (unixpath));        /* sanity check */
  un = GNUNET_malloc (sizeof (struct sockaddr_un));
  un->sun_family = AF_UNIX;
  slen = strlen (unixpath);
  if (slen >= sizeof (un->sun_path))
    slen = sizeof (un->sun_path) - 1;
  memcpy (un->sun_path, unixpath, slen);
  un->sun_path[slen] = '\0';
  slen = sizeof (struct sockaddr_un);
#if HAVE_SOCKADDR_IN_SIN_LEN
  un->sun_len = (u_char) slen;
#endif
#if LINUX
  un->sun_path[0] = '\0';
#endif
  connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
  connection->cfg = cfg;
  connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
  connection->port = 0;
  connection->hostname = NULL;
  connection->addr = (struct sockaddr *) un;
  connection->addrlen = slen;
  connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
  if (NULL == connection->sock)
  {
    GNUNET_free (connection->addr);
    GNUNET_free (connection->write_buffer);
    GNUNET_free (connection);
    return NULL;
  }
  if (GNUNET_OK !=
      GNUNET_NETWORK_socket_connect (connection->sock, connection->addr, connection->addrlen))
  {
    /* Just return; we expect everything to work eventually so don't fail HARD */
    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock));
    connection->sock = NULL;
    return connection;
  }
  connect_success_continuation (connection);
  return connection;
#else
  return NULL;
#endif
}
Пример #9
0
/**
 * Open source port for sending DNS requests
 *
 * @param af AF_INET or AF_INET6
 * @return GNUNET_OK on success
 */ 
static struct GNUNET_NETWORK_Handle *
open_socket (int af)
{
  struct sockaddr_in a4;
  struct sockaddr_in6 a6;
  struct sockaddr *sa;
  socklen_t alen;
  struct GNUNET_NETWORK_Handle *ret;

  ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0);
  if (NULL == ret)
    return NULL;
  switch (af)
  {
  case AF_INET:
    memset (&a4, 0, alen = sizeof (struct sockaddr_in));
    sa = (struct sockaddr *) &a4;
    break;
  case AF_INET6:
    memset (&a6, 0, alen = sizeof (struct sockaddr_in6));
    sa = (struct sockaddr *) &a6;
    break;
  default:
    GNUNET_break (0);
    GNUNET_NETWORK_socket_close (ret);
    return NULL;
  }
  sa->sa_family = af;
  if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret,
					       sa, 
					       alen))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
		_("Could not bind to any port: %s\n"),
		STRERROR (errno));
    GNUNET_NETWORK_socket_close (ret);
    return NULL;
  }
  return ret;
}
Пример #10
0
/**
 * Try to establish a connection given the specified address.
 * This function is called by the resolver once we have a DNS reply.
 *
 * @param cls our "struct GNUNET_CONNECTION_Handle *"
 * @param addr address to try, NULL for "last call"
 * @param addrlen length of addr
 */
static void
try_connect_using_address (void *cls, const struct sockaddr *addr,
                           socklen_t addrlen)
{
  struct GNUNET_CONNECTION_Handle *connection = cls;
  struct AddressProbe *ap;
  struct GNUNET_TIME_Relative delay;

  if (NULL == addr)
  {
    connection->dns_active = NULL;
    if ((NULL == connection->ap_head) && (NULL == connection->sock))
      connect_fail_continuation (connection);
    return;
  }
  if (NULL != connection->sock)
    return;                     /* already connected */
  GNUNET_assert (NULL == connection->addr);
  /* try to connect */
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Trying to connect using address `%s:%u/%s:%u'\n", connection->hostname, connection->port,
       GNUNET_a2s (addr, addrlen), connection->port);
  ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
  ap->addr = (const struct sockaddr *) &ap[1];
  memcpy (&ap[1], addr, addrlen);
  ap->addrlen = addrlen;
  ap->connection = connection;

  switch (ap->addr->sa_family)
  {
  case AF_INET:
    ((struct sockaddr_in *) ap->addr)->sin_port = htons (connection->port);
    break;
  case AF_INET6:
    ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (connection->port);
    break;
  default:
    GNUNET_break (0);
    GNUNET_free (ap);
    return;                     /* not supported by us */
  }
  ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family, SOCK_STREAM, 0);
  if (NULL == ap->sock)
  {
    GNUNET_free (ap);
    return;                     /* not supported by OS */
  }
  LOG (GNUNET_ERROR_TYPE_INFO, _("Trying to connect to `%s' (%p)\n"),
       GNUNET_a2s (ap->addr, ap->addrlen), connection);
  if ((GNUNET_OK !=
       GNUNET_NETWORK_socket_connect (ap->sock, ap->addr, ap->addrlen)) &&
      (EINPROGRESS != errno))
  {
    /* maybe refused / unsupported address, try next */
    LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect");
#if 0
    LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to connect to `%s' (%p)\n"),
         GNUNET_a2s (ap->addr, ap->addrlen), connection);
#endif
    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
    GNUNET_free (ap);
    return;
  }
  GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap);
  delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT;
  if (NULL != connection->nth.notify_ready)
    delay =
        GNUNET_TIME_relative_min (delay,
                                  GNUNET_TIME_absolute_get_remaining (connection->
                                                                      nth.transmit_timeout));
  if (NULL != connection->receiver)
    delay =
        GNUNET_TIME_relative_min (delay,
                                  GNUNET_TIME_absolute_get_remaining
                                  (connection->receive_timeout));
  ap->task =
      GNUNET_SCHEDULER_add_write_net (delay, ap->sock,
                                      &connect_probe_continuation, ap);
}
Пример #11
0
/**
 * 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 task task to run if service is running
 *        (reason will be "PREREQ_DONE" (service running)
 *         or "TIMEOUT" (service not known to be running))
 * @param task_cls closure for task
 */
void
GNUNET_CLIENT_service_test (const char *service,
                            const struct GNUNET_CONFIGURATION_Handle *cfg,
                            struct GNUNET_TIME_Relative timeout,
                            GNUNET_SCHEDULER_Task task, void *task_cls)
{
  char *hostname;
  unsigned long long port;
  struct GNUNET_NETWORK_Handle *sock;
  struct GNUNET_CLIENT_Connection *client;

  LOG (GNUNET_ERROR_TYPE_DEBUG, "Testing if service `%s' is running.\n",
       service);
#ifdef AF_UNIX
  {
    /* probe UNIX support */
    struct sockaddr_un s_un;
    size_t slen;
    char *unixpath;

    unixpath = NULL;
    if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (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);
      }
    }
    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;
	slen = strlen (unixpath) + 1;
	if (slen >= sizeof (s_un.sun_path))
	  slen = sizeof (s_un.sun_path) - 1;
	memcpy (s_un.sun_path, unixpath, slen);
	s_un.sun_path[slen] = '\0';
	slen = sizeof (struct sockaddr_un);
#if LINUX
	s_un.sun_path[0] = '\0';
#endif
#if HAVE_SOCKADDR_IN_SIN_LEN
	s_un.sun_len = (u_char) slen;
#endif
	if (GNUNET_OK !=
	    GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_un,
					slen))
        {
	  /* failed to bind => service must be running */
	  GNUNET_free (unixpath);
	  (void) GNUNET_NETWORK_socket_close (sock);
	  GNUNET_SCHEDULER_add_continuation (task, task_cls,
					     GNUNET_SCHEDULER_REASON_PREREQ_DONE);
	  return;
	}
	(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_error (task, task_cls);
    return;
  }

  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);
        GNUNET_SCHEDULER_add_continuation (task, task_cls,
                                           GNUNET_SCHEDULER_REASON_PREREQ_DONE);
        return;
      }
      (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);
        GNUNET_SCHEDULER_add_continuation (task, task_cls,
                                           GNUNET_SCHEDULER_REASON_PREREQ_DONE);
        return;
      }
      (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_error (task, task_cls);
    return;
  }
  GNUNET_free_non_null (hostname);

  /* non-localhost, try 'connect' method */
  client = GNUNET_CLIENT_connect (service, cfg);
  if (NULL == client)
  {
    LOG (GNUNET_ERROR_TYPE_INFO,
         _("Could not connect to service `%s', must not be running.\n"),
         service);
    service_test_error (task, task_cls);
    return;
  }
  client->test_cb = task;
  client->test_cb_cls = task_cls;
  client->test_deadline = GNUNET_TIME_relative_to_absolute (timeout);
  if (NULL == GNUNET_CLIENT_notify_transmit_ready (client,
						   sizeof (struct GNUNET_MessageHeader),
						   timeout, GNUNET_YES, &write_test,
						   client))
  {
    LOG (GNUNET_ERROR_TYPE_WARNING,
         _("Failure to transmit request to service `%s'\n"), service);
    service_test_error (task, task_cls);
    GNUNET_CLIENT_disconnect (client);
    return;
  }
}
Пример #12
0
/**
 * 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;
}
Пример #13
0
/**
 * Creating a listening socket for each of the service's addresses and
 * wait for the first incoming connection to it
 *
 * @param sa address associated with the service
 * @param addr_len length of sa
 * @param sl service entry for the service in question
 */
static void
create_listen_socket (struct sockaddr *sa, socklen_t addr_len,
		      struct ServiceList *sl)
{
  static int on = 1;
  struct GNUNET_NETWORK_Handle *sock;
  struct ServiceListeningInfo *sli;

  switch (sa->sa_family)
    {
    case AF_INET:
      sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0);
      break;
    case AF_INET6:
      sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
      break;
    case AF_UNIX:
      if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0)	/* Do not bind to blank UNIX path! */
	return;
      sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0);
      break;
    default:
      GNUNET_break (0);
      sock = NULL;
      errno = EAFNOSUPPORT;
      break;
    }
  if (NULL == sock)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
		  _("Unable to create socket for service `%s': %s\n"),
		  sl->name, STRERROR (errno));
      GNUNET_free (sa);
      return;
    }
  if (GNUNET_NETWORK_socket_setsockopt
      (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
			 "setsockopt");
#ifdef IPV6_V6ONLY
  if ((sa->sa_family == AF_INET6) &&
      (GNUNET_NETWORK_socket_setsockopt
       (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK))
    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
			 "setsockopt");
#endif

  if (GNUNET_NETWORK_socket_bind
      (sock, (const struct sockaddr *) sa, addr_len) != GNUNET_OK)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
		  _
		  ("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
		  sl->name, GNUNET_a2s (sa, addr_len), STRERROR (errno));
      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
      GNUNET_free (sa);
      return;
    }
  if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK)
    {
      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
      GNUNET_free (sa);
      return;
    }
  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
	      _("ARM now monitors connections to service `%s' at `%s'\n"),
	      sl->name, GNUNET_a2s (sa, addr_len));
  sli = GNUNET_malloc (sizeof (struct ServiceListeningInfo));
  sli->service_addr = sa;
  sli->service_addr_len = addr_len;
  sli->listen_socket = sock;
  sli->sl = sl;
  sli->accept_task =
    GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock,
				   &accept_connection, sli);
  GNUNET_CONTAINER_DLL_insert (sl->listen_head, sl->listen_tail, sli);
}
Пример #14
0
/**
 * Main function that will be run.
 *
 * @param cls closure
 * @param args remaining command-line arguments
 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
 * @param c configuration
 */
static void
run (void *cls,
     char *const *args,
     const char *cfgfile,
     const struct GNUNET_CONFIGURATION_Handle *c)
{
  uint8_t af;
  struct sockaddr *local_sa;
  struct sockaddr *remote_sa;
  socklen_t local_len;
  size_t remote_len;

  if (use_tcp && use_udp)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
		"Cannot use TCP and UDP\n");
    global_ret = 1;
    return;
  }
  proto = 0;
  if (use_tcp)
    proto = IPPROTO_TCP;
  if (use_udp)
    proto = IPPROTO_UDP;

  GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
				 NULL);

  if (0 == proto)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
		"Must specify either TCP or UDP\n");
    global_ret = 1;
    return;
  }
  if (NULL != local_addr)
  {
    local_len = (socklen_t) GNUNET_STRINGS_parse_socket_addr (local_addr,
							      &af,
							      &local_sa);
    if (0 == local_len)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
		  "Invalid socket address `%s'\n",
		  local_addr);
      global_ret = 1;
      return;
    }
  }
  if (NULL != remote_addr)
  {
    remote_len = GNUNET_STRINGS_parse_socket_addr (remote_addr,
						   &af,
						   &remote_sa);
    if (0 == remote_len)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
		  "Invalid socket address `%s'\n",
		  remote_addr);
      global_ret = 1;
      return;
    }
  }

  if (NULL != local_addr)
  {
    if (NULL == section_name)
      section_name = GNUNET_strdup ("undefined");
    nh = GNUNET_NAT_register (c,
			      section_name,
			      proto,
			      1,
			      (const struct sockaddr **) &local_sa,
			      &local_len,
			      &address_cb,
			      (listen_reversal) ? &reversal_cb : NULL,
			      NULL);
  }
  else if (listen_reversal)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
		"Use of `-W` only effective in combination with `-i`\n");    
    global_ret = 1;
    GNUNET_SCHEDULER_shutdown ();
    return;
  }

  if (NULL != remote_addr)
  {
    int ret;
    
    if ( (NULL == nh) ||
	 (sizeof (struct sockaddr_in) != local_len) )
    {
      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
		  "Require IPv4 local address to initiate connection reversal\n");
      global_ret = 1;
      GNUNET_SCHEDULER_shutdown ();
      return;
    }
    if (sizeof (struct sockaddr_in) != remote_len)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
		  "Require IPv4 reversal target address\n");
      global_ret = 1;
      GNUNET_SCHEDULER_shutdown ();
      return;
    }
    GNUNET_assert (AF_INET == local_sa->sa_family);
    GNUNET_assert (AF_INET == remote_sa->sa_family);
    ret = GNUNET_NAT_request_reversal (nh,
				       (const struct sockaddr_in *) local_sa,
				       (const struct sockaddr_in *) remote_sa);
    switch (ret)
    {
    case GNUNET_SYSERR:
      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
		  "Connection reversal internal error\n");
      break;
    case GNUNET_NO:
      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
		  "Connection reversal unavailable\n");
      break;
    case GNUNET_OK:
      /* operation in progress */
      break;
    }
  }
  
  if (do_stun)
  {
    if (NULL == local_addr)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
		  "Require local address to support STUN requests\n");
      global_ret = 1;
      GNUNET_SCHEDULER_shutdown ();
      return;
    }
    if (IPPROTO_UDP != proto)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
		  "STUN only supported over UDP\n");
      global_ret = 1;
      GNUNET_SCHEDULER_shutdown ();
      return;
    }
    ls = GNUNET_NETWORK_socket_create (af,
				       SOCK_DGRAM,
				       IPPROTO_UDP);
    if (GNUNET_OK !=
	GNUNET_NETWORK_socket_bind (ls,
				    local_sa,
				    local_len))
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
		  "Failed to bind to %s: %s\n",
		  GNUNET_a2s (local_sa,
			      local_len),
		  STRERROR (errno));
      global_ret = 1;
      GNUNET_SCHEDULER_shutdown ();
      return;
    }
    rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
					   ls,
					   &stun_read_task,
					   NULL);
  }

  test_finished ();
}
Пример #15
0
/**
 * Start testing if NAT traversal works using the
 * given configuration (IPv4-only).
 *
 * ALL failures are reported directly to the report callback
 *
 * @param cfg configuration for the NAT traversal
 * @param is_tcp #GNUNET_YES to test TCP, #GNUNET_NO to test UDP
 * @param bnd_port port to bind to, 0 for connection reversal
 * @param adv_port externally advertised port to use
 * @param timeout delay after which the test should be aborted
 * @param report function to call with the result of the test
 * @param report_cls closure for @a report
 * @return handle to cancel NAT test or NULL. The error is always indicated via the report callback
 */
struct GNUNET_NAT_Test *
GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
                       int is_tcp,
                       uint16_t bnd_port,
                       uint16_t adv_port,
                       struct GNUNET_TIME_Relative timeout,
                       GNUNET_NAT_TestCallback report,
                       void *report_cls)
{
  struct GNUNET_NAT_Test *nh;
  struct sockaddr_in sa;
  const struct sockaddr *addrs[] = { (const struct sockaddr *) &sa };
  const socklen_t addrlens[] = { sizeof (sa) };

  memset (&sa, 0, sizeof (sa));
  sa.sin_family = AF_INET;
  sa.sin_port = htons (bnd_port);
#if HAVE_SOCKADDR_IN_SIN_LEN
  sa.sin_len = sizeof (sa);
#endif

  nh = GNUNET_new (struct GNUNET_NAT_Test);
  nh->cfg = cfg;
  nh->is_tcp = is_tcp;
  nh->data = bnd_port;
  nh->adv_port = adv_port;
  nh->report = report;
  nh->report_cls = report_cls;
  nh->status = GNUNET_NAT_ERROR_SUCCESS;
  if (0 == bnd_port)
  {
    nh->nat 
      = GNUNET_NAT_register (cfg, is_tcp, 0, 0, 
			     NULL, NULL,
			     &addr_cb,
                             &reversal_cb, nh, NULL);
  }
  else
  {
    nh->lsock =
        GNUNET_NETWORK_socket_create (AF_INET,
                                      (is_tcp ==
                                       GNUNET_YES) ? SOCK_STREAM : SOCK_DGRAM,
                                      0);
    if ((nh->lsock == NULL) ||
        (GNUNET_OK !=
         GNUNET_NETWORK_socket_bind (nh->lsock, (const struct sockaddr *) &sa,
                                     sizeof (sa))))
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("Failed to create listen socket bound to `%s' for NAT test: %s\n"),
                  GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa)),
                  STRERROR (errno));
      if (NULL != nh->lsock)
      {
        GNUNET_NETWORK_socket_close (nh->lsock);
        nh->lsock = NULL;
      }
      nh->status = GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR;
      nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout, nh);
      return nh;
    }
    if (GNUNET_YES == is_tcp)
    {
      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_listen (nh->lsock, 5));
      nh->ltask =
          GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
                                         nh->lsock, &do_accept, nh);
    }
    else
    {
      nh->ltask =
          GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
                                         nh->lsock, &do_udp_read, nh);
    }
    LOG (GNUNET_ERROR_TYPE_INFO,
	 "NAT test listens on port %u (%s)\n",
	 bnd_port,
	 (GNUNET_YES == is_tcp) ? "tcp" : "udp");
    nh->nat = GNUNET_NAT_register (cfg, is_tcp, adv_port, 1,
                                   addrs, addrlens,
                                   &addr_cb, NULL, nh, NULL);
    if (NULL == nh->nat)
    {
      LOG (GNUNET_ERROR_TYPE_INFO,
          _("NAT test failed to start NAT library\n"));
      if (NULL != nh->ltask)
      {
        GNUNET_SCHEDULER_cancel (nh->ltask);
        nh->ltask = NULL;
      }
      if (NULL != nh->lsock)
      {
        GNUNET_NETWORK_socket_close (nh->lsock);
        nh->lsock = NULL;
      }
      nh->status = GNUNET_NAT_ERROR_NAT_REGISTER_FAILED;
      nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout, nh);
      return nh;
    }
  }
  nh->ttask = GNUNET_SCHEDULER_add_delayed (timeout, &do_timeout, nh);
  return nh;
}
Пример #16
0
/**
 * 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]);
        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]);
        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;
}