+/**
+ * Broadcast our presence on one of our interfaces.
+ *
+ * @param cls a `struct BroadcastInterface`
+ */
+static void
+ifc_broadcast (void *cls)
+{
+ struct BroadcastInterface *bi = cls;
+ struct GNUNET_TIME_Relative delay;
+
+ delay = BROADCAST_FREQUENCY;
+ delay.rel_value_us = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+ delay.rel_value_us);
+ bi->broadcast_task
+ = GNUNET_SCHEDULER_add_delayed (INTERFACE_SCAN_FREQUENCY,
+ &ifc_broadcast,
+ bi);
+
+ switch (bi->sa->sa_family) {
+ case AF_INET:
+ {
+ static int yes = 1;
+ static int no = 0;
+ ssize_t sent;
+
+ if (GNUNET_OK !=
+ GNUNET_NETWORK_socket_setsockopt (udp_sock,
+ SOL_SOCKET,
+ SO_BROADCAST,
+ &yes,
+ sizeof (int)))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "setsockopt");
+ sent = GNUNET_NETWORK_socket_sendto (udp_sock,
+ &bi->bcm,
+ sizeof (bi->bcm),
+ bi->ba,
+ bi->salen);
+ if (-1 == sent)
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "sendto");
+ if (GNUNET_OK !=
+ GNUNET_NETWORK_socket_setsockopt (udp_sock,
+ SOL_SOCKET,
+ SO_BROADCAST,
+ &no,
+ sizeof (int)))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "setsockopt");
+ break;
+ }
+ case AF_INET6:
+ {
+ ssize_t sent;
+ struct sockaddr_in6 dst;
+
+ dst.sin6_family = AF_INET6;
+ dst.sin6_port = htons (my_port);
+ dst.sin6_addr = bi->mcreq.ipv6mr_multiaddr;
+ dst.sin6_scope_id = ((struct sockaddr_in6*) bi->ba)->sin6_scope_id;
+
+ sent = GNUNET_NETWORK_socket_sendto (udp_sock,
+ &bi->bcm,
+ sizeof (bi->bcm),
+ (const struct sockaddr *)
+ &dst,
+ sizeof (dst));
+ if (-1 == sent)
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "sendto");
+ break;
+ }
+ default:
+ GNUNET_break (0);
+ break;
+ }
+}
+
+
+/**
+ * Callback function invoked for each interface found.
+ * Activates/deactivates broadcast interfaces.
+ *
+ * @param cls NULL
+ * @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 BroadcastInterface *bi;
+ enum GNUNET_NetworkType network;
+ struct UdpBroadcastSignature ubs;
+
+ (void) cls;
+ (void) netmask;
+ network = GNUNET_NT_scanner_get_type (is,
+ addr,
+ addrlen);
+ if (GNUNET_NT_LOOPBACK == network)
+ {
+ /* Broadcasting on loopback does not make sense */
+ return GNUNET_YES;
+ }
+ if (NULL == addr)
+ return GNUNET_YES; /* need to know our address! */
+ for (bi = bi_head; NULL != bi; bi = bi->next)
+ {
+ if ( (bi->salen == addrlen) &&
+ (0 == memcmp (addr,
+ bi->sa,
+ addrlen)) )
+ {
+ bi->found = GNUNET_YES;
+ return GNUNET_OK;
+ }
+ }
+
+ if ( (AF_INET6 == addr->sa_family) &&
+ (NULL == broadcast_addr) )
+ return GNUNET_OK; /* broadcast_addr is required for IPv6! */
+ if ( (AF_INET6 == addr->sa_family) &&
+ (GNUNET_YES != have_v6_socket) )
+ return GNUNET_OK; /* not using IPv6 */
+
+ bi = GNUNET_new (struct BroadcastInterface);
+ bi->sa = GNUNET_memdup (addr,
+ addrlen);
+ if (NULL != broadcast_addr)
+ bi->ba = GNUNET_memdup (broadcast_addr,
+ addrlen);
+ bi->salen = addrlen;
+ bi->found = GNUNET_YES;
+ bi->bcm.sender = my_identity;
+ ubs.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_UDP_BROADCAST);
+ ubs.purpose.size = htonl (sizeof (ubs));
+ ubs.sender = my_identity;
+ GNUNET_CRYPTO_hash (addr,
+ addrlen,
+ &ubs.h_address);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign (my_private_key,
+ &ubs.purpose,
+ &bi->bcm.sender_sig));
+ bi->broadcast_task = GNUNET_SCHEDULER_add_now (&ifc_broadcast,
+ bi);
+ GNUNET_CONTAINER_DLL_insert (bi_head,
+ bi_tail,
+ bi);
+ if ( (AF_INET6 == addr->sa_family) &&
+ (NULL != broadcast_addr) )
+ {
+ /* Create IPv6 multicast request */
+ const struct sockaddr_in6 *s6
+ = (const struct sockaddr_in6 *) broadcast_addr;
+
+ GNUNET_assert (1 ==
+ inet_pton (AF_INET6,
+ "FF05::13B",
+ &bi->mcreq.ipv6mr_multiaddr));
+
+ /* 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...).
+ */
+ bi->mcreq.ipv6mr_interface = s6->sin6_scope_id;
+
+ /* Join the multicast group */
+ if (GNUNET_OK !=
+ GNUNET_NETWORK_socket_setsockopt
+ (udp_sock,
+ IPPROTO_IPV6,
+ IPV6_JOIN_GROUP,
+ &bi->mcreq,
+ sizeof (bi->mcreq)))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "setsockopt");
+ }
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Scan interfaces to broadcast our presence on the LAN.
+ *
+ * @param cls NULL, unused
+ */
+static void
+do_broadcast (void *cls)
+{
+ struct BroadcastInterface *bin;
+
+ (void) cls;
+ for (struct BroadcastInterface *bi = bi_head;
+ NULL != bi;
+ bi = bi->next)
+ bi->found = GNUNET_NO;
+ GNUNET_OS_network_interfaces_list (&iface_proc,
+ NULL);
+ for (struct BroadcastInterface *bi = bi_head;
+ NULL != bi;
+ bi = bin)
+ {
+ bin = bi->next;
+ if (GNUNET_NO == bi->found)
+ bi_destroy (bi);
+ }
+ broadcast_task
+ = GNUNET_SCHEDULER_add_delayed (INTERFACE_SCAN_FREQUENCY,
+ &do_broadcast,
+ NULL);
+}
+
+