gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnunet] 03/06: adding broadcast support


From: gnunet
Subject: [GNUnet-SVN] [gnunet] 03/06: adding broadcast support
Date: Wed, 30 Jan 2019 12:39:41 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository gnunet.

commit 31f4c60c63dbd3958da7aac32f81cb20770eab97
Author: Christian Grothoff <address@hidden>
AuthorDate: Wed Jan 30 06:10:39 2019 +0100

    adding broadcast support
---
 src/transport/gnunet-communicator-udp.c | 391 +++++++++++++++++++++++++++++++-
 1 file changed, 388 insertions(+), 3 deletions(-)

diff --git a/src/transport/gnunet-communicator-udp.c 
b/src/transport/gnunet-communicator-udp.c
index d464cd0d1..bbfe2ebec 100644
--- a/src/transport/gnunet-communicator-udp.c
+++ b/src/transport/gnunet-communicator-udp.c
@@ -34,7 +34,7 @@
  * - add and use util/ check for IPv6 availability (#V6)
  * - consider imposing transmission limits in the absence
  *   of ACKs; or: maybe this should be done at TNG service level?
- * - support broadcasting for neighbour discovery (#)
+ * - handle addresses discovered fro broadcasts (#)
  *   (think: what was the story again on address validation?
  *    where is the API for that!?!)
  * - support DNS names in BINDTO option (#5528)
@@ -61,6 +61,16 @@
  */ 
 #define PROTO_QUEUE_TIMEOUT GNUNET_TIME_UNIT_MINUTES
 
+/**
+ * How often do we broadcast our presence on the LAN?
+ */ 
+#define BROADCAST_FREQUENCY GNUNET_TIME_UNIT_MINUTES
+
+/**
+ * How often do we scan for changes to our network interfaces?
+ */ 
+#define INTERFACE_SCAN_FREQUENCY GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_MINUTES, 5)
+
 /**
  * AES key size.
  */
@@ -573,6 +583,60 @@ struct ReceiverAddress
 };
 
 
+/**
+ * Interface we broadcast our presence on.
+ */
+struct BroadcastInterface
+{
+
+  /**
+   * Kept in a DLL.
+   */
+  struct BroadcastInterface *next;
+
+  /**
+   * Kept in a DLL.
+   */
+  struct BroadcastInterface *prev;
+
+  /**
+   * Task for this broadcast interface.
+   */
+  struct GNUNET_SCHEDULER_Task *broadcast_task;
+  
+  /**
+   * Sender's address of the interface.
+   */
+  struct sockaddr *sa;
+  
+  /**
+   * Broadcast address to use on the interface.
+   */
+  struct sockaddr *ba;
+
+  /**
+   * Message we broadcast on this interface.
+   */ 
+  struct UDPBroadcast bcm;
+  
+  /**
+   * If this is an IPv6 interface, this is the request
+   * we use to join/leave the group.
+   */
+  struct ipv6_mreq mcreq;
+  
+  /**
+   * Number of bytes in @e sa.
+   */ 
+  socklen_t salen;
+
+  /**
+   * Was this interface found in the last #iface_proc() scan?
+   */
+  int found;
+};
+
+
 /**
  * Cache of pre-generated key IDs.
  */
@@ -588,6 +652,11 @@ static struct GNUNET_SCHEDULER_Task *read_task;
  */
 static struct GNUNET_SCHEDULER_Task *timeout_task;
 
+/**
+ * ID of master broadcast task
+ */
+static struct GNUNET_SCHEDULER_Task *broadcast_task;
+
 /**
  * For logging statistics.
  */
@@ -618,11 +687,26 @@ static struct GNUNET_CONTAINER_Heap *senders_heap;
  */
 static struct GNUNET_CONTAINER_Heap *receivers_heap;
 
+/**
+ * Broadcast interface tasks. Kept in a DLL.
+ */
+static struct BroadcastInterface *bi_head;
+
+/**
+ * Broadcast interface tasks. Kept in a DLL.
+ */
+static struct BroadcastInterface *bi_tail;
+
 /**
  * Our socket.
  */
 static struct GNUNET_NETWORK_Handle *udp_sock;
 
+/** 
+ * #GNUNET_YES if #udp_sock supports IPv6.
+ */ 
+static int have_v6_socket;
+
 /**
  * Our public key.
  */
@@ -648,10 +732,47 @@ static struct GNUNET_NT_InterfaceScanner *is;
  */
 static struct GNUNET_NAT_Handle *nat;
 
+/**
+ * Port number to which we are actually bound.
+ */ 
+static uint16_t my_port;
+
 
 /**
- * Functions with this signature are called whenever we need
- * to close a receiving state due to timeout.
+ * An interface went away, stop broadcasting on it.
+ *
+ * @param bi entity to close down
+ */
+static void
+bi_destroy (struct BroadcastInterface *bi)
+{
+  if (AF_INET6 == bi->sa->sa_family)
+  {
+    /* Leave the multicast group */
+    if (GNUNET_OK !=
+        GNUNET_NETWORK_socket_setsockopt
+        (udp_sock,
+        IPPROTO_IPV6,
+        IPV6_LEAVE_GROUP,
+         &bi->mcreq,
+        sizeof (bi->mcreq)))
+    {
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                          "setsockopt");
+    }
+  }
+  GNUNET_CONTAINER_DLL_remove (bi_head,
+                              bi_tail,
+                              bi);
+  GNUNET_SCHEDULER_cancel (bi->broadcast_task);
+  GNUNET_free (bi->sa);
+  GNUNET_free_non_null (bi->ba);
+  GNUNET_free (bi);
+}
+
+
+/**
+ * Destroys a receiving state due to timeout or shutdown.
  *
  * @param receiver entity to close down
  */
@@ -2106,6 +2227,13 @@ do_shutdown (void *cls)
      GNUNET_NAT_unregister (nat);
      nat = NULL;
   }
+  while (NULL != bi_head)
+    bi_destroy (bi_head);
+  if (NULL != broadcast_task)
+  {
+    GNUNET_SCHEDULER_cancel (broadcast_task);
+    broadcast_task = NULL;
+  }
   if (NULL != read_task)
   {
     GNUNET_SCHEDULER_cancel (read_task);
@@ -2235,6 +2363,240 @@ nat_address_cb (void *cls,
 }
 
 
+/**
+ * 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);
+}
+
+
 /**
  * Setup communicator and launch network interactions.
  *
@@ -2290,6 +2652,8 @@ run (void *cls,
     GNUNET_free (bindto);
     return;
   }
+  if (AF_INET6 == in->sa_family)
+    have_v6_socket = GNUNET_YES;
   if (GNUNET_OK !=
       GNUNET_NETWORK_socket_bind (udp_sock,
                                   in,
@@ -2324,6 +2688,18 @@ run (void *cls,
              "Bound to `%s'\n",
              GNUNET_a2s ((const struct sockaddr *) &in_sto,
                          sto_len));
+  switch (in->sa_family)
+  {
+  case AF_INET:
+    my_port = ntohs (((struct sockaddr_in *) in)->sin_port);
+    break;
+  case AF_INET6:
+    my_port = ntohs (((struct sockaddr_in6 *) in)->sin6_port);
+    break;
+  default:
+    GNUNET_break (0);
+    my_port = 0;
+  }
   stats = GNUNET_STATISTICS_create ("C-UDP",
                                    cfg);
   senders = GNUNET_CONTAINER_multipeermap_create (32,
@@ -2366,6 +2742,15 @@ run (void *cls,
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
+  /* start broadcasting */
+  if (GNUNET_YES !=
+      GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                           COMMUNICATOR_CONFIG_SECTION,
+                                           "DISABLE_BROADCAST"))
+  {
+    broadcast_task = GNUNET_SCHEDULER_add_now (&do_broadcast,
+                                              NULL);
+  }  
   nat = GNUNET_NAT_register (cfg,
                             COMMUNICATOR_CONFIG_SECTION,
                             IPPROTO_UDP,

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]