X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftransport%2Fplugin_transport_udp_broadcasting.c;h=e9caa3aa77a90775603f0c3b877829c54243f968;hb=3685629253bb94994449f56871252af24a91b6e7;hp=8c42e374f932ab0d54c1189f493421c43491554d;hpb=9df4cb72d3e3b914caa8e1dc451519715a360026;p=oweals%2Fgnunet.git diff --git a/src/transport/plugin_transport_udp_broadcasting.c b/src/transport/plugin_transport_udp_broadcasting.c index 8c42e374f..e9caa3aa7 100644 --- a/src/transport/plugin_transport_udp_broadcasting.c +++ b/src/transport/plugin_transport_udp_broadcasting.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - (C) 2010, 2011 Christian Grothoff (and other contributing authors) + Copyright (C) 2010, 2011 GNUnet e.V. GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -14,8 +14,8 @@ You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /** @@ -41,6 +41,25 @@ #define LOG(kind,...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__) +/* *********** Cryogenic ********** */ +#if LINUX +#include +#include + +#include +#include +#include + +#define PM_MAGIC 'k' +#define PM_SET_DELAY_AND_TIMEOUT _IOW(PM_MAGIC, 1, struct pm_times) + +struct pm_times { + unsigned long delay_msecs; + unsigned long timeout_msecs; +}; +#endif +/************************************/ + struct UDP_Beacon_Message { @@ -59,94 +78,70 @@ struct UDP_Beacon_Message struct BroadcastAddress { struct BroadcastAddress *next; - struct BroadcastAddress *prev; - void *addr; - socklen_t addrlen; -}; + struct BroadcastAddress *prev; + /** + * ID of select broadcast task + */ + struct GNUNET_SCHEDULER_Task * broadcast_task; -struct Mstv4Context -{ struct Plugin *plugin; - struct IPv4UdpAddress addr; + struct sockaddr *addr; + + socklen_t addrlen; + +#if LINUX /** - * ATS network type in NBO + * Cryogenic handle. */ - uint32_t ats_address_network_type; -}; - -struct Mstv6Context -{ - struct Plugin *plugin; + struct GNUNET_DISK_FileHandle *cryogenic_fd; - struct IPv6UdpAddress addr; /** - * ATS network type in NBO + * Time out for cryogenic. */ - uint32_t ats_address_network_type; + struct pm_times cryogenic_times; +#endif }; -int -broadcast_ipv6_mst_cb (void *cls, void *client, - const struct GNUNET_MessageHeader *message) +/** + * Client-specific context for #broadcast_mst_cb(). + */ +struct MstContext { + struct Plugin *plugin; - struct Plugin *plugin = cls; - struct Mstv6Context *mc = client; - const struct GNUNET_MessageHeader *hello; - const struct UDP_Beacon_Message *msg; - struct GNUNET_ATS_Information atsi; - - msg = (const struct UDP_Beacon_Message *) message; - - if (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON != - ntohs (msg->header.type)) - return GNUNET_OK; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received beacon with %u bytes from peer `%s' via address `%s'\n", - ntohs (msg->header.size), GNUNET_i2s (&msg->sender), - udp_address_to_string (NULL, &mc->addr, sizeof (mc->addr))); - - /* setup ATS */ - atsi.type = htonl (GNUNET_ATS_NETWORK_TYPE); - atsi.value = mc->ats_address_network_type; - GNUNET_break (ntohl(mc->ats_address_network_type) != GNUNET_ATS_NET_UNSPECIFIED); + const union UdpAddress *udp_addr; - hello = (struct GNUNET_MessageHeader *) &msg[1]; - plugin->env->receive (plugin->env->cls, - &msg->sender, - hello, - NULL, - (const char *) &mc->addr, - sizeof (mc->addr)); - plugin->env->update_address_metrics (plugin->env->cls, - &msg->sender, - (const char *) &mc->addr, - sizeof (mc->addr), - NULL, - &atsi, 1); + size_t udp_addr_len; - GNUNET_STATISTICS_update (plugin->env->stats, - _ - ("# IPv6 multicast HELLO beacons received via udp"), - 1, GNUNET_NO); - GNUNET_free (mc); - return GNUNET_OK; -} + /** + * ATS network type. + */ + enum GNUNET_ATS_Network_Type ats_address_network_type; +}; -int -broadcast_ipv4_mst_cb (void *cls, void *client, - const struct GNUNET_MessageHeader *message) +/** + * Parse broadcast message received. + * + * @param cls the `struct Plugin` + * @param client the `struct MstContext` with sender address + * @param message the message we received + * @return #GNUNET_OK (always) + */ +static int +broadcast_mst_cb (void *cls, + void *client, + const struct GNUNET_MessageHeader *message) { struct Plugin *plugin = cls; - struct Mstv4Context *mc = client; + struct MstContext *mc = client; + struct GNUNET_HELLO_Address *address; const struct GNUNET_MessageHeader *hello; const struct UDP_Beacon_Message *msg; - struct GNUNET_ATS_Information atsi; msg = (const struct UDP_Beacon_Message *) message; @@ -155,94 +150,64 @@ broadcast_ipv4_mst_cb (void *cls, void *client, return GNUNET_OK; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received beacon with %u bytes from peer `%s' via address `%s'\n", - ntohs (msg->header.size), GNUNET_i2s (&msg->sender), - udp_address_to_string (NULL, &mc->addr, sizeof (mc->addr))); - - - /* setup ATS */ - atsi.type = htonl (GNUNET_ATS_NETWORK_TYPE); - atsi.value = mc->ats_address_network_type; - GNUNET_break (ntohl(mc->ats_address_network_type) != GNUNET_ATS_NET_UNSPECIFIED); - + ntohs (msg->header.size), + GNUNET_i2s (&msg->sender), + udp_address_to_string (NULL, + mc->udp_addr, + mc->udp_addr_len)); hello = (struct GNUNET_MessageHeader *) &msg[1]; + address = GNUNET_HELLO_address_allocate (&msg->sender, + PLUGIN_NAME, + mc->udp_addr, + mc->udp_addr_len, + GNUNET_HELLO_ADDRESS_INFO_NONE); plugin->env->receive (plugin->env->cls, - &msg->sender, - hello, + address, NULL, - (const char *) &mc->addr, - sizeof (mc->addr)); - - plugin->env->update_address_metrics (plugin->env->cls, - &msg->sender, - (const char *) &mc->addr, - sizeof (mc->addr), - NULL, - &atsi, 1); - + hello); + GNUNET_HELLO_address_free (address); GNUNET_STATISTICS_update (plugin->env->stats, - _ - ("# IPv4 broadcast HELLO beacons received via udp"), + _("# Multicast HELLO beacons received via UDP"), 1, GNUNET_NO); - GNUNET_free (mc); return GNUNET_OK; } +/** + * We received a broadcast message. Process it and all subsequent + * messages in the same packet. + * + * @param plugin the UDP plugin + * @param buf the buffer with the message(s) + * @param size number of bytes in @a buf + * @param udp_addr address of the sender + * @param udp_addr_len number of bytes in @a udp_addr + * @param network_type network type of the sender's address + */ void udp_broadcast_receive (struct Plugin *plugin, - const char * buf, + const char *buf, ssize_t size, - const struct sockaddr *addr, - size_t addrlen) + const union UdpAddress *udp_addr, + size_t udp_addr_len, + enum GNUNET_ATS_Network_Type network_type) { - struct GNUNET_ATS_Information ats; - - if ((GNUNET_YES == plugin->broadcast_ipv4) && (addrlen == sizeof (struct sockaddr_in))) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received IPv4 HELLO beacon broadcast with %i bytes from address %s\n", - size, GNUNET_a2s ((const struct sockaddr *) addr, addrlen)); - struct Mstv4Context *mc; - - mc = GNUNET_malloc (sizeof (struct Mstv4Context)); - struct sockaddr_in *av4 = (struct sockaddr_in *) addr; - - mc->addr.ipv4_addr = av4->sin_addr.s_addr; - mc->addr.u4_port = av4->sin_port; - ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) addr, addrlen); - mc->ats_address_network_type = ats.value; - - GNUNET_assert (NULL != plugin->broadcast_ipv4_mst); - if (GNUNET_OK != - GNUNET_SERVER_mst_receive (plugin->broadcast_ipv4_mst, mc, buf, size, - GNUNET_NO, GNUNET_NO)) - GNUNET_free (mc); - } - else if ((GNUNET_YES == plugin->broadcast_ipv4) && (addrlen == sizeof (struct sockaddr_in6))) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received IPv6 HELLO beacon broadcast with %i bytes from address %s\n", - size, GNUNET_a2s ((const struct sockaddr *) &addr, addrlen)); - struct Mstv6Context *mc; - - mc = GNUNET_malloc (sizeof (struct Mstv6Context)); - struct sockaddr_in6 *av6 = (struct sockaddr_in6 *) addr; - - mc->addr.ipv6_addr = av6->sin6_addr; - mc->addr.u6_port = av6->sin6_port; - ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) addr, addrlen); - mc->ats_address_network_type = ats.value; - GNUNET_assert (NULL != plugin->broadcast_ipv4_mst); - if (GNUNET_OK != - GNUNET_SERVER_mst_receive (plugin->broadcast_ipv6_mst, mc, buf, size, - GNUNET_NO, GNUNET_NO)) - GNUNET_free (mc); - } + struct MstContext mc; + + mc.udp_addr = udp_addr; + mc.udp_addr_len = udp_addr_len; + mc.ats_address_network_type = network_type; + GNUNET_SERVER_mst_receive (plugin->broadcast_mst, + &mc, + buf, size, + GNUNET_NO, + GNUNET_NO); } static unsigned int -prepare_beacon (struct Plugin *plugin, struct UDP_Beacon_Message *msg) +prepare_beacon (struct Plugin *plugin, + struct UDP_Beacon_Message *msg) { uint16_t hello_size; uint16_t msg_size; @@ -261,33 +226,28 @@ prepare_beacon (struct Plugin *plugin, struct UDP_Beacon_Message *msg) msg->sender = *(plugin->env->my_identity); msg->header.size = htons (msg_size); msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON); - memcpy (&msg[1], hello, hello_size); + GNUNET_memcpy (&msg[1], hello, hello_size); return msg_size; } static void -udp_ipv4_broadcast_send (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +udp_ipv4_broadcast_send (void *cls) { - struct Plugin *plugin = cls; + struct BroadcastAddress *baddr = cls; + struct Plugin *plugin = baddr->plugin; int sent; uint16_t msg_size; char buf[65536] GNUNET_ALIGN; - struct BroadcastAddress *baddr; - plugin->send_ipv4_broadcast_task = GNUNET_SCHEDULER_NO_TASK; + baddr->broadcast_task = NULL; msg_size = prepare_beacon(plugin, (struct UDP_Beacon_Message *) &buf); - - baddr = plugin->ipv4_broadcast_head; - /* just IPv4 */ - while ((msg_size > 0) && (baddr != NULL) && (baddr->addrlen == sizeof (struct sockaddr_in))) + if (0 != msg_size) { struct sockaddr_in *addr = (struct sockaddr_in *) baddr->addr; addr->sin_port = htons (plugin->port); - sent = GNUNET_NETWORK_socket_sendto (plugin->sockv4, &buf, msg_size, (const struct sockaddr *) addr, baddr->addrlen); @@ -311,31 +271,68 @@ udp_ipv4_broadcast_send (void *cls, "Sent HELLO beacon broadcast with %i bytes to address %s\n", sent, GNUNET_a2s (baddr->addr, baddr->addrlen)); } - baddr = baddr->next; } - plugin->send_ipv4_broadcast_task = - GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval, - &udp_ipv4_broadcast_send, plugin); +#if LINUX + /* + * Cryogenic + */ + if (NULL != baddr->cryogenic_fd) + { + baddr->cryogenic_times.delay_msecs = (plugin->broadcast_interval.rel_value_us/1000.0)*0.5; + baddr->cryogenic_times.timeout_msecs = (plugin->broadcast_interval.rel_value_us/1000.0)*1.5; + + if (ioctl(baddr->cryogenic_fd->fd, + PM_SET_DELAY_AND_TIMEOUT, + &baddr->cryogenic_times) < 0) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctl"); + baddr->broadcast_task = + GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval, + &udp_ipv4_broadcast_send, baddr); + } + else + GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + baddr->cryogenic_fd, + &udp_ipv4_broadcast_send, + baddr); + + } + else +#endif + baddr->broadcast_task = + GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval, + &udp_ipv4_broadcast_send, baddr); } static void -udp_ipv6_broadcast_send (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +udp_ipv6_broadcast_send (void *cls) { - struct Plugin *plugin = cls; - int sent; + struct BroadcastAddress *baddr = cls; + struct Plugin *plugin = baddr->plugin; + ssize_t sent; uint16_t msg_size; char buf[65536] GNUNET_ALIGN; + const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) baddr->addr; - plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_NO_TASK; + baddr->broadcast_task = NULL; msg_size = prepare_beacon(plugin, (struct UDP_Beacon_Message *) &buf); + /* Note: unclear if this actually works to limit the multicast to + the specified interface as we're not (necessarily) using a + link-local multicast group and the kernel suggests that the + scope ID is only respected for link-local addresses; however, + if the scope ID is ignored, the kernel should just multicast + on ALL interfaces, which is merely slightly less efficient; + in that case, we might want to revert to only doing this + once, and not per interface (hard to test...) */ + plugin->ipv6_multicast_address.sin6_scope_id = s6->sin6_scope_id; sent = GNUNET_NETWORK_socket_sendto (plugin->sockv6, &buf, msg_size, (const struct sockaddr *) &plugin->ipv6_multicast_address, sizeof (struct sockaddr_in6)); + plugin->ipv6_multicast_address.sin6_scope_id = 0; if (sent == GNUNET_SYSERR) { if ((ENETUNREACH == errno) || (ENETDOWN == errno)) @@ -354,200 +351,299 @@ udp_ipv6_broadcast_send (void *cls, else { LOG (GNUNET_ERROR_TYPE_DEBUG, - "Sending IPv6 HELLO beacon broadcast with %i bytes to address %s\n", - sent, + "Sending IPv6 HELLO beacon broadcast with %d bytes to address %s\n", + (int) sent, GNUNET_a2s ((const struct sockaddr *) &plugin->ipv6_multicast_address, sizeof (struct sockaddr_in6))); } - plugin->send_ipv6_broadcast_task = - GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval, - &udp_ipv6_broadcast_send, plugin); +#if LINUX + /* + * Cryogenic + */ + if (NULL != baddr->cryogenic_fd) + { + baddr->cryogenic_times.delay_msecs = (plugin->broadcast_interval.rel_value_us/1000.0)*0.5; + baddr->cryogenic_times.timeout_msecs = (plugin->broadcast_interval.rel_value_us/1000.0)*1.5; + + if (ioctl(baddr->cryogenic_fd->fd, + PM_SET_DELAY_AND_TIMEOUT, + &baddr->cryogenic_times) < 0) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctl"); + baddr->broadcast_task = + GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval, + &udp_ipv6_broadcast_send, baddr); + } + else + GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + baddr->cryogenic_fd, + &udp_ipv4_broadcast_send, + baddr); + } + else +#endif + baddr->broadcast_task = + GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval, + &udp_ipv6_broadcast_send, baddr); } +/** + * 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, +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 (addr != NULL) + 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) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "address %s for interface %s %p\n ", - GNUNET_a2s (addr, addrlen), name, addr); - 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); - - /* Collecting broadcast addresses */ - if (broadcast_addr != NULL) + /* 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)) { - struct BroadcastAddress *ba = - GNUNET_malloc (sizeof (struct BroadcastAddress)); - ba->addr = GNUNET_malloc (addrlen); - memcpy (ba->addr, broadcast_addr, addrlen); - ba->addrlen = addrlen; - GNUNET_CONTAINER_DLL_insert (plugin->ipv4_broadcast_head, - plugin->ipv4_broadcast_tail, ba); + 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; } +/** + * 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) +setup_broadcast (struct Plugin *plugin, + struct sockaddr_in6 *server_addrv6, + struct sockaddr_in *server_addrv4) { - const struct GNUNET_MessageHeader *hello; - hello = plugin->env->get_our_hello (); - - if (GNUNET_YES == GNUNET_HELLO_is_friend_only((const struct GNUNET_HELLO_Message *) hello)) + 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 */ - plugin->broadcast_ipv4 = GNUNET_NO; - if ((GNUNET_YES == plugin->enable_ipv4) && (plugin->sockv4 != NULL)) + if ((GNUNET_YES == plugin->enable_ipv4) && (NULL != plugin->sockv4)) { - int yes = 1; + 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"), + _("Failed to set IPv4 broadcast option for broadcast socket on port %d\n"), ntohs (server_addrv4->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; + /* 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); - - 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; - } } + GNUNET_OS_network_interfaces_list (&iface_proc, plugin); } +/** + * Stop broadcasting subsystem. + * + * @param plugin + */ void stop_broadcast (struct Plugin *plugin) { - if (plugin->broadcast_ipv4) + if (GNUNET_YES == plugin->enable_broadcasting) { - if (plugin->send_ipv4_broadcast_task != GNUNET_SCHEDULER_NO_TASK) + /* Disable broadcasting */ + while (plugin->broadcast_head != NULL) { - 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); + struct BroadcastAddress *p = plugin->broadcast_head; - while (plugin->ipv4_broadcast_head != NULL) - { - struct BroadcastAddress *p = plugin->ipv4_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"); + } + } - GNUNET_CONTAINER_DLL_remove (plugin->ipv4_broadcast_head, - plugin->ipv4_broadcast_tail, p); +#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); } } - if (plugin->broadcast_ipv6) + /* Destroy MSTs */ + if (NULL != plugin->broadcast_mst) { - /* 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); + GNUNET_SERVER_mst_destroy (plugin->broadcast_mst); + plugin->broadcast_mst = NULL; } - } /* end of plugin_transport_udp_broadcasting.c */