예제 #1
0
/**
 * Convert IP address to string without DNS resolution.
 *
 * @param af address family
 * @param ip the address
 * @param ip_len number of bytes in ip
 * @return address as a string, NULL on error
 */
static char *
no_resolve (int af,
	    const void *ip, socklen_t ip_len)
{
  char buf[INET6_ADDRSTRLEN];

  switch (af)
  {
  case AF_INET:
    if (ip_len != sizeof (struct in_addr))
      return NULL;
    if (NULL ==
        inet_ntop (AF_INET, ip, buf, sizeof (buf)))
    {
      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
      return NULL;
    }
    break;
  case AF_INET6:
    if (ip_len != sizeof (struct in6_addr))
      return NULL;
    if (NULL ==
        inet_ntop (AF_INET6, ip, buf, sizeof (buf)))
    {
      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
      return NULL;
    }
    break;
  default:
    GNUNET_break (0);
    return NULL;
  }
  return GNUNET_strdup (buf);
}
예제 #2
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;
}
예제 #3
0
/**
 * Convert the len characters long character sequence
 * given in input that is in the given input charset
 * to a string in given output charset.
 *
 * @param input input string
 * @param len number of bytes in @a input
 * @param input_charset character set used for @a input
 * @param output_charset desired character set for the return value
 * @return the converted string (0-terminated),
 *  if conversion fails, a copy of the orignal
 *  string is returned.
 */
char *
GNUNET_STRINGS_conv (const char *input,
		     size_t len,
		     const char *input_charset,
		     const char *output_charset)
{
  char *ret;
  uint8_t *u8_string;
  char *encoded_string;
  size_t u8_string_length;
  size_t encoded_string_length;

  u8_string = u8_conv_from_encoding (input_charset,
				     iconveh_error,
				     input, len,
				     NULL, NULL,
				     &u8_string_length);
  if (NULL == u8_string)
  {
    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "u8_conv_from_encoding");
    goto fail;
  }
  if (0 == strcmp (output_charset, "UTF-8"))
  {
    ret = GNUNET_malloc (u8_string_length + 1);
    memcpy (ret, u8_string, u8_string_length);
    ret[u8_string_length] = '\0';
    free (u8_string);
    return ret;
  }
  encoded_string = u8_conv_to_encoding (output_charset, iconveh_error,
					u8_string, u8_string_length,
					NULL, NULL,
					&encoded_string_length);
  free (u8_string);
  if (NULL == encoded_string)
  {
    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "u8_conv_to_encoding");
    goto fail;
  }
  ret = GNUNET_malloc (encoded_string_length + 1);
  memcpy (ret, encoded_string, encoded_string_length);
  ret[encoded_string_length] = '\0';
  free (encoded_string);
  return ret;
 fail:
  LOG (GNUNET_ERROR_TYPE_WARNING, _("Character sets requested were `%s'->`%s'\n"),
       "UTF-8", output_charset);
  ret = GNUNET_malloc (len + 1);
  memcpy (ret, input, len);
  ret[len] = '\0';
  return ret;
}
예제 #4
0
/**
 * Allocate and initialize memory. Checks the return value, aborts if no more
 * memory is available.  Don't use GNUNET_xmemdup_ directly. Use the
 * GNUNET_memdup macro.
 *
 * @param buf buffer to initialize from (must contain size bytes)
 * @param size number of bytes to allocate
 * @param filename where is this call being made (for debugging)
 * @param linenumber line where this call is being made (for debugging)
 * @return allocated memory, never NULL
 */
void *
GNUNET_xmemdup_ (const void *buf, size_t size, const char *filename,
                 int linenumber)
{
  void *ret;

  /* As a security precaution, we generally do not allow very large
   * allocations here */
  GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED, filename, linenumber);
#ifdef W32_MEM_LIMIT
  size += sizeof (size_t);
  if (mem_used + size > W32_MEM_LIMIT)
    return NULL;
#endif
  GNUNET_assert_at (size < INT_MAX, filename, linenumber);
  ret = malloc (size);
  if (ret == NULL)
  {
    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "malloc");
    GNUNET_abort ();
  }
#ifdef W32_MEM_LIMIT
  *((size_t *) ret) = size;
  ret = &((size_t *) ret)[1];
  mem_used += size;
#endif
  memcpy (ret, buf, size);
  return ret;
}
예제 #5
0
파일: connection.c 프로젝트: GNUnet/gnunet
/**
 * Create a connection handle by accepting on a listen socket.  This
 * function may block if the listen socket has no connection ready.
 *
 * @param access_cb function to use to check if access is allowed
 * @param access_cb_cls closure for @a access_cb
 * @param lsock listen socket
 * @return the connection handle, NULL on error
 */
struct GNUNET_CONNECTION_Handle *
GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
                                      void *access_cb_cls,
                                      struct GNUNET_NETWORK_Handle *lsock)
{
  struct GNUNET_CONNECTION_Handle *connection;
  char addr[128];
  socklen_t addrlen;
  struct GNUNET_NETWORK_Handle *sock;
  int aret;
  struct sockaddr_in *v4;
  struct sockaddr_in6 *v6;
  struct sockaddr *sa;
  void *uaddr;
  struct GNUNET_CONNECTION_Credentials *gcp;
  struct GNUNET_CONNECTION_Credentials gc;
#ifdef SO_PEERCRED
  struct ucred uc;
  socklen_t olen;
#endif

  addrlen = sizeof (addr);
  sock =
      GNUNET_NETWORK_socket_accept (lsock,
				    (struct sockaddr *) &addr,
				    &addrlen);
  if (NULL == sock)
  {
    if (EAGAIN != errno)
      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept");
    return NULL;
  }
  if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t)))
  {
    GNUNET_break (0);
    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
    return NULL;
  }

  sa = (struct sockaddr *) addr;
  v6 = (struct sockaddr_in6 *) addr;
  if ( (AF_INET6 == sa->sa_family) &&
       (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)) )
  {
    /* convert to V4 address */
    v4 = GNUNET_new (struct sockaddr_in);
    memset (v4, 0, sizeof (struct sockaddr_in));
    v4->sin_family = AF_INET;
#if HAVE_SOCKADDR_IN_SIN_LEN
    v4->sin_len = (u_char) sizeof (struct sockaddr_in);
#endif
    GNUNET_memcpy (&v4->sin_addr,
            &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) -
                                       sizeof (struct in_addr)],
            sizeof (struct in_addr));
    v4->sin_port = v6->sin6_port;
    uaddr = v4;
    addrlen = sizeof (struct sockaddr_in);
  }
예제 #6
0
/**
 * Close the connection and free associated resources.  There must
 * not be any pending requests for reading or writing to the
 * connection at this time.
 *
 * @param connection connection to destroy
 */
void
GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection)
{
  struct AddressProbe *pos;

  LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connection (%p)\n", connection);
  GNUNET_assert (NULL == connection->nth.notify_ready);
  GNUNET_assert (NULL == connection->receiver);
  if (GNUNET_SCHEDULER_NO_TASK != connection->write_task)
  {
    GNUNET_SCHEDULER_cancel (connection->write_task);
    connection->write_task = GNUNET_SCHEDULER_NO_TASK;
    connection->write_buffer_off = 0;
  }
  if (GNUNET_SCHEDULER_NO_TASK != connection->read_task)
  {
    GNUNET_SCHEDULER_cancel (connection->read_task);
    connection->read_task = GNUNET_SCHEDULER_NO_TASK;
  }
  if (GNUNET_SCHEDULER_NO_TASK != connection->nth.timeout_task)
  {
    GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
    connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK;
  }
  connection->nth.notify_ready = NULL;
  if (NULL != connection->dns_active)
  {
    GNUNET_RESOLVER_request_cancel (connection->dns_active);
    connection->dns_active = NULL;
  }
  while (NULL != (pos = connection->ap_head))
  {
    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
    GNUNET_SCHEDULER_cancel (pos->task);
    GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, pos);
    GNUNET_free (pos);
  }
  if ( (NULL != connection->sock) &&
       (GNUNET_YES != connection->persist) )
  {
    if ((GNUNET_YES != GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR)) && 
	(ENOTCONN != errno) && 
	(ECONNRESET != errno) )
      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "shutdown");    
  }
  if (NULL != connection->sock)
  {
    if (GNUNET_YES != connection->persist)
      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock));
    else
      GNUNET_free (connection->sock); /* at least no memory leak (we deliberately
				       * leak the socket in this special case) ... */
  }
  GNUNET_free_non_null (connection->addr);
  GNUNET_free_non_null (connection->hostname);
  GNUNET_free (connection->write_buffer);
  GNUNET_free (connection);
}
예제 #7
0
/**
 * Allocate memory. Checks the return value, aborts if no more
 * memory is available.
 *
 * @param size how many bytes of memory to allocate, do NOT use
 *  this function (or GNUNET_malloc) to allocate more than several MB
 *  of memory, if you are possibly needing a very large chunk use
 *  GNUNET_xmalloc_unchecked_ instead.
 * @param filename where in the code was the call to GNUNET_malloc
 * @param linenumber where in the code was the call to GNUNET_malloc
 * @return pointer to size bytes of memory
 */
void *
GNUNET_xmalloc_ (size_t size, const char *filename, int linenumber)
{
  void *ret;

  /* As a security precaution, we generally do not allow very large
   * allocations using the default 'GNUNET_malloc' macro */
  GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED, filename, linenumber);
  ret = GNUNET_xmalloc_unchecked_ (size, filename, linenumber);
  if (ret == NULL)
  {
    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "malloc");
    GNUNET_abort ();
  }
  return ret;
}
예제 #8
0
/**
 * Looking our own hostname.
 *
 * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any"
 * @param callback function to call with addresses
 * @param cls closure for callback
 * @param timeout how long to try resolving
 * @return handle that can be used to cancel the request, NULL on error
 */
struct GNUNET_RESOLVER_RequestHandle *
GNUNET_RESOLVER_hostname_resolve (int af,
                                  struct GNUNET_TIME_Relative timeout,
                                  GNUNET_RESOLVER_AddressCallback callback,
                                  void *cls)
{
  char hostname[GNUNET_OS_get_hostname_max_length () + 1];

  if (0 != gethostname (hostname, sizeof (hostname) - 1))
  {
    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                  "gethostname");
    return NULL;
  }
  LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolving our hostname `%s'\n", hostname);
  return GNUNET_RESOLVER_ip_get (hostname, af, timeout, callback, cls);
}
예제 #9
0
/**
 * Reallocate memory. Checks the return value, aborts if no more
 * memory is available.
 *
 * @param ptr the pointer to reallocate
 * @param n how many bytes of memory to allocate
 * @param filename where in the code was the call to GNUNET_realloc
 * @param linenumber where in the code was the call to GNUNET_realloc
 * @return pointer to size bytes of memory
 */
void *
GNUNET_xrealloc_ (void *ptr, size_t n, const char *filename, int linenumber)
{
#ifdef W32_MEM_LIMIT
  n += sizeof (size_t);
  ptr = &((size_t *) ptr)[-1];
  mem_used = mem_used - *((size_t *) ptr) + n;
#endif
  ptr = realloc (ptr, n);
  if ((NULL == ptr) && (n > 0))
  {
    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "realloc");
    GNUNET_abort ();
  }
#ifdef W32_MEM_LIMIT
  ptr = &((size_t *) ptr)[1];
#endif
  return ptr;
}
예제 #10
0
/**
 * Get local fully qualified af name
 *
 * @return fqdn
 */
char *
GNUNET_RESOLVER_local_fqdn_get ()
{
  struct hostent *host;
  char hostname[GNUNET_OS_get_hostname_max_length () + 1];

  if (0 != gethostname (hostname, sizeof (hostname) - 1))
  {
    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                  "gethostname");
    return NULL;
  }
  LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolving our FQDN `%s'\n", hostname);
  host = gethostbyname (hostname);
  if (NULL == host)
  {
    LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not resolve our FQDN : %s\n"),
         hstrerror (h_errno));
    return NULL;
  }
  return GNUNET_strdup (host->h_name);
}
예제 #11
0
/**
 * Get local fully qualified af name
 *
 * @return fqdn
 */
char *
GNUNET_RESOLVER_local_fqdn_get ()
{
    char hostname[GNUNET_OS_get_hostname_max_length () + 1];

    if (0 != gethostname (hostname, sizeof (hostname) - 1))
    {
        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                      "gethostname");
        return NULL;
    }
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Resolving our FQDN `%s'\n",
         hostname);
#if HAVE_GETADDRINFO
    {
        struct addrinfo *ai;
        int ret;
        char *rval;

        if (0 != (ret = getaddrinfo (hostname, NULL, NULL, &ai)))
        {
            LOG (GNUNET_ERROR_TYPE_ERROR,
                 _("Could not resolve our FQDN: %s\n"),
                 gai_strerror (ret));
            return NULL;
        }
        if (NULL != ai->ai_canonname)
            rval = GNUNET_strdup (ai->ai_canonname);
        else
            rval = GNUNET_strdup (hostname);
        freeaddrinfo (ai);
        return rval;
    }
#elif HAVE_GETHOSTBYNAME2
    {
        struct hostent *host;

        host = gethostbyname2 (hostname, AF_INET);
        if (NULL == host)
            host = gethostbyname2 (hostname, AF_INET6);
        if (NULL == host)
        {
            LOG (GNUNET_ERROR_TYPE_ERROR,
                 _("Could not resolve our FQDN: %s\n"),
                 hstrerror (h_errno));
            return NULL;
        }
        return GNUNET_strdup (host->h_name);
    }
#elif HAVE_GETHOSTBYNAME
    {
        struct hostent *host;

        host = gethostbyname (hostname);
        if (NULL == host)
        {
            LOG (GNUNET_ERROR_TYPE_ERROR,
                 _("Could not resolve our FQDN: %s\n"),
                 hstrerror (h_errno));
            return NULL;
        }
        return GNUNET_strdup (host->h_name);
    }
#else
    /* fallback: just hope name is already FQDN */
    return GNUNET_strdup (hostname);
#endif
}
예제 #12
0
파일: service.c 프로젝트: tg-x/gnunet
/**
 * 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;
}
예제 #13
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);
}
예제 #14
0
/**
 * Create a connection handle by accepting on a listen socket.  This
 * function may block if the listen socket has no connection ready.
 *
 * @param access function to use to check if access is allowed
 * @param access_cls closure for access
 * @param lsock listen socket
 * @return the connection handle, NULL on error
 */
struct GNUNET_CONNECTION_Handle *
GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access,
                                      void *access_cls,
                                      struct GNUNET_NETWORK_Handle *lsock)
{
  struct GNUNET_CONNECTION_Handle *connection;
  char addr[128];
  socklen_t addrlen;
  struct GNUNET_NETWORK_Handle *sock;
  int aret;
  struct sockaddr_in *v4;
  struct sockaddr_in6 *v6;
  struct sockaddr *sa;
  void *uaddr;
  struct GNUNET_CONNECTION_Credentials *gcp;
  struct GNUNET_CONNECTION_Credentials gc;
#ifdef SO_PEERCRED
  struct ucred uc;
  socklen_t olen;
#endif

  addrlen = sizeof (addr);
  sock =
      GNUNET_NETWORK_socket_accept (lsock, (struct sockaddr *) &addr, &addrlen);
  if (NULL == sock)
  {
    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept");
    return NULL;
  }
  if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t)))
  {
    GNUNET_break (0);
    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
    return NULL;
  }

  sa = (struct sockaddr *) addr;
  v6 = (struct sockaddr_in6 *) addr;
  if ((AF_INET6 == sa->sa_family) && (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)))
  {
    /* convert to V4 address */
    v4 = GNUNET_malloc (sizeof (struct sockaddr_in));
    memset (v4, 0, sizeof (struct sockaddr_in));
    v4->sin_family = AF_INET;
#if HAVE_SOCKADDR_IN_SIN_LEN
    v4->sin_len = (u_char) sizeof (struct sockaddr_in);
#endif
    memcpy (&v4->sin_addr,
            &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) -
                                       sizeof (struct in_addr)],
            sizeof (struct in_addr));
    v4->sin_port = v6->sin6_port;
    uaddr = v4;
    addrlen = sizeof (struct sockaddr_in);
  }
  else
  {
    uaddr = GNUNET_malloc (addrlen);
    memcpy (uaddr, addr, addrlen);
  }
  gcp = NULL;
  gc.uid = 0;
  gc.gid = 0;
  if (AF_UNIX == sa->sa_family)
  {
#if HAVE_GETPEEREID
    /* most BSDs */
    if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock), &gc.uid, &gc.gid))
      gcp = &gc;
#else
#ifdef SO_PEERCRED
    /* largely traditional GNU/Linux */
    olen = sizeof (uc);
    if ((0 ==
         getsockopt (GNUNET_NETWORK_get_fd (sock), SOL_SOCKET, SO_PEERCRED, &uc,
                     &olen)) && (olen == sizeof (uc)))
    {
      gc.uid = uc.uid;
      gc.gid = uc.gid;
      gcp = &gc;
    }
#else
#if HAVE_GETPEERUCRED
    /* this is for Solaris 10 */
    ucred_t *uc;

    uc = NULL;
    if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc))
    {
      gc.uid = ucred_geteuid (uc);
      gc.gid = ucred_getegid (uc);
      gcp = &gc;
    }
    ucred_free (uc);
#endif
#endif
#endif
  }

  if ((NULL != access) &&
      (GNUNET_YES != (aret = access (access_cls, gcp, uaddr, addrlen))))
  {
    if (GNUNET_NO == aret)
      LOG (GNUNET_ERROR_TYPE_INFO, _("Access denied to `%s'\n"),
           GNUNET_a2s (uaddr, addrlen));
    GNUNET_break (GNUNET_OK ==
                  GNUNET_NETWORK_socket_shutdown (sock, SHUT_RDWR));
    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
    GNUNET_free (uaddr);
    return NULL;
  }
  connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
  connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
  connection->addr = uaddr;
  connection->addrlen = addrlen;
  connection->sock = sock;
  LOG (GNUNET_ERROR_TYPE_INFO, 
       _("Accepting connection from `%s': %p\n"),
       GNUNET_a2s (uaddr, addrlen), connection);
  return connection;
}
예제 #15
0
파일: service.c 프로젝트: tg-x/gnunet
/**
 * 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.conf");
  else
    cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_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;
}
예제 #16
0
/**
 * Complete filename (a la shell) from abbrevition.
 * @param fil the name of the file, may contain ~/ or
 *        be relative to the current directory
 * @returns the full file name,
 *          NULL is returned on error
 */
char *
GNUNET_STRINGS_filename_expand (const char *fil)
{
  char *buffer;
#ifndef MINGW
  size_t len;
  size_t n;
  char *fm;
  const char *fil_ptr;
#else
  char *fn;
  long lRet;
#endif

  if (fil == NULL)
    return NULL;

#ifndef MINGW
  if (fil[0] == DIR_SEPARATOR)
    /* absolute path, just copy */
    return GNUNET_strdup (fil);
  if (fil[0] == '~')
  {
    fm = getenv ("HOME");
    if (fm == NULL)
    {
      LOG (GNUNET_ERROR_TYPE_WARNING,
           _("Failed to expand `$HOME': environment variable `HOME' not set"));
      return NULL;
    }
    fm = GNUNET_strdup (fm);
    /* do not copy '~' */
    fil_ptr = fil + 1;

    /* skip over dir seperator to be consistent */
    if (fil_ptr[0] == DIR_SEPARATOR)
      fil_ptr++;
  }
  else
  {
    /* relative path */
    fil_ptr = fil;
    len = 512;
    fm = NULL;
    while (1)
    {
      buffer = GNUNET_malloc (len);
      if (getcwd (buffer, len) != NULL)
      {
        fm = buffer;
        break;
      }
      if ((errno == ERANGE) && (len < 1024 * 1024 * 4))
      {
        len *= 2;
        GNUNET_free (buffer);
        continue;
      }
      GNUNET_free (buffer);
      break;
    }
    if (fm == NULL)
    {
      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "getcwd");
      buffer = getenv ("PWD");  /* alternative */
      if (buffer != NULL)
        fm = GNUNET_strdup (buffer);
    }
    if (fm == NULL)
      fm = GNUNET_strdup ("./");        /* give up */
  }
  n = strlen (fm) + 1 + strlen (fil_ptr) + 1;
  buffer = GNUNET_malloc (n);
  GNUNET_snprintf (buffer, n, "%s%s%s", fm,
                   (fm[strlen (fm) - 1] ==
                    DIR_SEPARATOR) ? "" : DIR_SEPARATOR_STR, fil_ptr);
  GNUNET_free (fm);
  return buffer;
#else
  fn = GNUNET_malloc (MAX_PATH + 1);

  if ((lRet = plibc_conv_to_win_path (fil, fn)) != ERROR_SUCCESS)
  {
    SetErrnoFromWinError (lRet);
    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "plibc_conv_to_win_path");
    return NULL;
  }
  /* is the path relative? */
  if ((strncmp (fn + 1, ":\\", 2) != 0) && (strncmp (fn, "\\\\", 2) != 0))
  {
    char szCurDir[MAX_PATH + 1];

    lRet = GetCurrentDirectory (MAX_PATH + 1, szCurDir);
    if (lRet + strlen (fn) + 1 > (MAX_PATH + 1))
    {
      SetErrnoFromWinError (ERROR_BUFFER_OVERFLOW);
      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "GetCurrentDirectory");
      return NULL;
    }
    buffer = GNUNET_malloc (MAX_PATH + 1);
    GNUNET_snprintf (buffer, MAX_PATH + 1, "%s\\%s", szCurDir, fn);
    GNUNET_free (fn);
    fn = buffer;
  }

  return fn;
#endif
}
예제 #17
0
파일: service.c 프로젝트: tg-x/gnunet
/**
 * 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;
}