/**
 * 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;
}
/**
 * Stop broadcasting subsystem.
 *
 * @param plugin
 */
void
stop_broadcast (struct Plugin *plugin)
{
  if (GNUNET_YES == plugin->enable_broadcasting)
  {
    /* Disable broadcasting */
    while (plugin->broadcast_head != NULL)
    {
      struct BroadcastAddress *p = plugin->broadcast_head;

      if (p->broadcast_task != NULL)
      {
        GNUNET_SCHEDULER_cancel (p->broadcast_task);
        p->broadcast_task = NULL;
      }
      if ((GNUNET_YES == plugin->enable_ipv6) &&
          (NULL != plugin->sockv6) &&
          (p->addrlen == sizeof (struct sockaddr_in6)))
      {
        /* Create IPv6 multicast request */
        struct ipv6_mreq multicastRequest;
        const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) p->addr;

        multicastRequest.ipv6mr_multiaddr =
          plugin->ipv6_multicast_address.sin6_addr;
        multicastRequest.ipv6mr_interface = s6->sin6_scope_id;

        /* Leave the multicast group */
        if (GNUNET_OK ==
            GNUNET_NETWORK_socket_setsockopt
            (plugin->sockv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
             &multicastRequest, sizeof (multicastRequest)))
        {
          GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt");
        }
        else
        {
          LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 multicasting stopped\n");
        }
      }

#if LINUX
    GNUNET_DISK_file_close(p->cryogenic_fd);
#endif
      GNUNET_CONTAINER_DLL_remove (plugin->broadcast_head,
                                   plugin->broadcast_tail, p);
      GNUNET_free (p->addr);
      GNUNET_free (p);
    }
  }

  /* Destroy MSTs */
  if (NULL != plugin->broadcast_mst)
  {
    GNUNET_SERVER_mst_destroy (plugin->broadcast_mst);
    plugin->broadcast_mst = NULL;
  }
}
void
stop_broadcast (struct Plugin *plugin)
{
  if (plugin->broadcast_ipv4)
  {
    if (plugin->send_ipv4_broadcast_task != GNUNET_SCHEDULER_NO_TASK)
    {
      GNUNET_SCHEDULER_cancel (plugin->send_ipv4_broadcast_task);
      plugin->send_ipv4_broadcast_task = GNUNET_SCHEDULER_NO_TASK;
    }

    if (plugin->broadcast_ipv4_mst != NULL)
      GNUNET_SERVER_mst_destroy (plugin->broadcast_ipv4_mst);

    while (plugin->ipv4_broadcast_head != NULL)
    {
      struct BroadcastAddress *p = plugin->ipv4_broadcast_head;

      GNUNET_CONTAINER_DLL_remove (plugin->ipv4_broadcast_head,
                                   plugin->ipv4_broadcast_tail, p);
      GNUNET_free (p->addr);
      GNUNET_free (p);
    }
  }

  if (plugin->broadcast_ipv6)
  {
    /* Create IPv6 multicast request */
    struct ipv6_mreq multicastRequest;

    multicastRequest.ipv6mr_multiaddr =
        plugin->ipv6_multicast_address.sin6_addr;
    multicastRequest.ipv6mr_interface = 0;

    /* Join the multicast address */
    if (GNUNET_NETWORK_socket_setsockopt
        (plugin->sockv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
        (char *) &multicastRequest, sizeof (multicastRequest)) != GNUNET_OK)
    {
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, setsockopt);
    }
    else
    {
      LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 Broadcasting stopped\n");
    }

    if (plugin->send_ipv6_broadcast_task != GNUNET_SCHEDULER_NO_TASK)
    {
      GNUNET_SCHEDULER_cancel (plugin->send_ipv6_broadcast_task);
      plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_NO_TASK;
    }
    if (plugin->broadcast_ipv6_mst != NULL)
      GNUNET_SERVER_mst_destroy (plugin->broadcast_ipv6_mst);
  }

}
/**
 * Setup broadcasting subsystem.
 *
 * @param plugin
 * @param server_addrv6
 * @param server_addrv4
 */
void
setup_broadcast (struct Plugin *plugin,
                 struct sockaddr_in6 *server_addrv6,
                 struct sockaddr_in *server_addrv4)
{
  if (GNUNET_YES ==
      GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
                                            "topology",
                                            "FRIENDS-ONLY"))
  {
    LOG (GNUNET_ERROR_TYPE_WARNING,
         _("Disabling HELLO broadcasting due to friend-to-friend only configuration!\n"));
    return;
  }

  /* always create tokenizers */
  plugin->broadcast_mst =
    GNUNET_SERVER_mst_create (&broadcast_mst_cb, plugin);

  if (GNUNET_YES != plugin->enable_broadcasting)
    return; /* We do not send, just receive */

  /* create IPv4 broadcast socket */
  if ((GNUNET_YES == plugin->enable_ipv4) && (NULL != plugin->sockv4))
  {
    static int yes = 1;

    if (GNUNET_NETWORK_socket_setsockopt
        (plugin->sockv4, SOL_SOCKET, SO_BROADCAST, &yes,
         sizeof (int)) != GNUNET_OK)
    {
      LOG (GNUNET_ERROR_TYPE_WARNING,
           _("Failed to set IPv4 broadcast option for broadcast socket on port %d\n"),
           ntohs (server_addrv4->sin_port));
    }
  }
  /* create IPv6 multicast socket */
  if ((GNUNET_YES == plugin->enable_ipv6) && (plugin->sockv6 != NULL))
  {
    memset (&plugin->ipv6_multicast_address, 0, sizeof (struct sockaddr_in6));
    GNUNET_assert (1 ==
                   inet_pton (AF_INET6, "FF05::13B",
                              &plugin->ipv6_multicast_address.sin6_addr));
    plugin->ipv6_multicast_address.sin6_family = AF_INET6;
    plugin->ipv6_multicast_address.sin6_port = htons (plugin->port);
  }
  GNUNET_OS_network_interfaces_list (&iface_proc, plugin);
}
/**
 * Callback function invoked for each interface found.
 *
 * @param cls closure with the `struct Plugin`
 * @param name name of the interface (can be NULL for unknown)
 * @param isDefault is this presumably the default interface
 * @param addr address of this interface (can be NULL for unknown or unassigned)
 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
 * @param netmask the network mask (can be NULL for unknown or unassigned)
 * @param addrlen length of the address
 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
 */
static int
iface_proc (void *cls,
            const char *name,
            int isDefault,
            const struct sockaddr *addr,
            const struct sockaddr *broadcast_addr,
            const struct sockaddr *netmask, socklen_t addrlen)
{
  struct Plugin *plugin = cls;
  struct BroadcastAddress *ba;
  enum GNUNET_ATS_Network_Type network;

  if (NULL == addr)
    return GNUNET_OK;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "address %s for interface %s %p\n ",
              GNUNET_a2s (addr, addrlen), name, addr);
  if (NULL == broadcast_addr)
    return GNUNET_OK;
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "broadcast address %s for interface %s %p\n ",
              GNUNET_a2s (broadcast_addr, addrlen), name, broadcast_addr);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "netmask %s for interface %s %p\n ",
              GNUNET_a2s (netmask, addrlen), name, netmask);

  network = plugin->env->get_address_type (plugin->env->cls, broadcast_addr, addrlen);
  if (GNUNET_ATS_NET_LOOPBACK == network)
  {
    /* Broadcasting on loopback does not make sense */
    return GNUNET_YES;
  }

  ba = GNUNET_new (struct BroadcastAddress);
  ba->plugin = plugin;
  ba->addr = GNUNET_malloc (addrlen);
  GNUNET_memcpy (ba->addr, broadcast_addr, addrlen);
  ba->addrlen = addrlen;

  if ( (GNUNET_YES == plugin->enable_ipv4) &&
       (NULL != plugin->sockv4) &&
       (addrlen == sizeof (struct sockaddr_in)) )
  {
#if LINUX
    /*
     * setup Cryogenic FD for ipv4 broadcasting
     */
    char *filename;

    GNUNET_asprintf (&filename,
                     "/dev/cryogenic/%s",
                     name);
    if (0 == ACCESS (name, R_OK))
    {
      ba->cryogenic_fd =
        GNUNET_DISK_file_open (filename,
                               GNUNET_DISK_OPEN_WRITE,
                               GNUNET_DISK_PERM_NONE);
    }
    GNUNET_free (filename);
#endif
    ba->broadcast_task =
        GNUNET_SCHEDULER_add_now (&udp_ipv4_broadcast_send, ba);
  }
  if ((GNUNET_YES == plugin->enable_ipv6) &&
      (NULL != plugin->sockv6) &&
      (addrlen == sizeof (struct sockaddr_in6)))
  {
    /* Create IPv6 multicast request */
    struct ipv6_mreq multicastRequest;
    const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) broadcast_addr;

    multicastRequest.ipv6mr_multiaddr =
        plugin->ipv6_multicast_address.sin6_addr;
    /* http://tools.ietf.org/html/rfc2553#section-5.2:
     *
     * IPV6_JOIN_GROUP
     *
     * Join a multicast group on a specified local interface.  If the
     * interface index is specified as 0, the kernel chooses the local
     * interface.  For example, some kernels look up the multicast
     * group in the normal IPv6 routing table and using the resulting
     * interface; we do this for each interface, so no need to use
     * zero (anymore...).
     */
    multicastRequest.ipv6mr_interface = s6->sin6_scope_id;

    /* Join the multicast group */
    if (GNUNET_OK !=
        GNUNET_NETWORK_socket_setsockopt
        (plugin->sockv6, IPPROTO_IPV6, IPV6_JOIN_GROUP,
         &multicastRequest, sizeof (multicastRequest)))
    {
      LOG (GNUNET_ERROR_TYPE_WARNING,
      "Failed to join IPv6 multicast group: IPv6 broadcasting not running\n");
    }
    else
    {
#if LINUX
      /*
       * setup Cryogenic FD for ipv6 broadcasting
       */
      char *filename;

      GNUNET_asprintf (&filename,
                       "/dev/cryogenic/%s",
                       name);
      if (0 == ACCESS (name, R_OK))
      {
        ba->cryogenic_fd =
          GNUNET_DISK_file_open (filename,
                                 GNUNET_DISK_OPEN_WRITE,
                                 GNUNET_DISK_PERM_NONE);
      }
      GNUNET_free (filename);
#endif
      ba->broadcast_task =
          GNUNET_SCHEDULER_add_now (&udp_ipv6_broadcast_send, ba);
    }
  }
  GNUNET_CONTAINER_DLL_insert (plugin->broadcast_head,
                               plugin->broadcast_tail, ba);
  return GNUNET_OK;
}
Пример #6
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);
}
void
setup_broadcast (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct sockaddr_in *serverAddrv4)
{
  /* create IPv4 broadcast socket */
  plugin->broadcast_ipv4 = GNUNET_NO;
  if (plugin->sockv4 != NULL)
  {
    int yes = 1;

    if (GNUNET_NETWORK_socket_setsockopt
        (plugin->sockv4, SOL_SOCKET, SO_BROADCAST, &yes,
         sizeof (int)) != GNUNET_OK)
    {
      LOG (GNUNET_ERROR_TYPE_WARNING,
           _
           ("Failed to set IPv4 broadcast option for broadcast socket on port %d\n"),
           ntohs (serverAddrv4->sin_port));
    }
    else
    {
      GNUNET_OS_network_interfaces_list (iface_proc, plugin);
      plugin->send_ipv4_broadcast_task =
          GNUNET_SCHEDULER_add_now (&udp_ipv4_broadcast_send, plugin);

      plugin->broadcast_ipv4_mst =
          GNUNET_SERVER_mst_create (broadcast_ipv4_mst_cb, plugin);

      LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv4 Broadcasting running\n");
      plugin->broadcast_ipv4 = GNUNET_YES;
    }
  }

  plugin->broadcast_ipv6 = GNUNET_NO;
  if (plugin->sockv6 != NULL)
  {
    memset (&plugin->ipv6_multicast_address, 0, sizeof (struct sockaddr_in6));
    GNUNET_assert (1 ==
                   inet_pton (AF_INET6, "FF05::13B",
                              &plugin->ipv6_multicast_address.sin6_addr));

    plugin->ipv6_multicast_address.sin6_family = AF_INET6;
    plugin->ipv6_multicast_address.sin6_port = htons (plugin->port);

    plugin->broadcast_ipv6_mst =
        GNUNET_SERVER_mst_create (broadcast_ipv6_mst_cb, plugin);

    /* Create IPv6 multicast request */
    struct ipv6_mreq multicastRequest;

    multicastRequest.ipv6mr_multiaddr =
        plugin->ipv6_multicast_address.sin6_addr;
    /* TODO: 0 selects the "best" interface, tweak to use all interfaces
     *
     * http://tools.ietf.org/html/rfc2553#section-5.2:
     *
     * IPV6_JOIN_GROUP
     *
     * Join a multicast group on a specified local interface.  If the
     * interface index is specified as 0, the kernel chooses the local
     * interface.  For example, some kernels look up the multicast
     * group in the normal IPv6 routing table and using the resulting
     * interface.
     * */
    multicastRequest.ipv6mr_interface = 0;

    /* Join the multicast group */
    if (GNUNET_NETWORK_socket_setsockopt
        (plugin->sockv6, IPPROTO_IPV6, IPV6_JOIN_GROUP,
         (char *) &multicastRequest, sizeof (multicastRequest)) != GNUNET_OK)
    {
      LOG (GNUNET_ERROR_TYPE_WARNING,
      "Failed to join IPv6 multicast group: IPv6 broadcasting not running\n");
    }
    else
    {
      LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 broadcasting running\n");
      plugin->send_ipv6_broadcast_task =
          GNUNET_SCHEDULER_add_now (&udp_ipv6_broadcast_send, plugin);
      plugin->broadcast_ipv6 = GNUNET_YES;
    }
  }
}