/** * 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; }
/** * 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; } } }