gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r10499 - gnunet/src/transport


From: gnunet
Subject: [GNUnet-SVN] r10499 - gnunet/src/transport
Date: Fri, 5 Mar 2010 16:58:40 +0100

Author: nevans
Date: 2010-03-05 16:58:40 +0100 (Fri, 05 Mar 2010)
New Revision: 10499

Modified:
   gnunet/src/transport/gnunet-service-transport.c
Log:
re use validation to keepalive connections.  May need more work/thought

Modified: gnunet/src/transport/gnunet-service-transport.c
===================================================================
--- gnunet/src/transport/gnunet-service-transport.c     2010-03-05 15:43:20 UTC 
(rev 10498)
+++ gnunet/src/transport/gnunet-service-transport.c     2010-03-05 15:58:40 UTC 
(rev 10499)
@@ -97,6 +97,11 @@
 #define TRANSPORT_DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 15)
 
 /**
+ * How often will we re-validate for latency information
+ */
+#define TRANSPORT_DEFAULT_REVALIDATION GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, 15)
+
+/**
  * Priority to use for PONG messages.
  */
 #define TRANSPORT_PONG_PRIORITY 4
@@ -145,6 +150,12 @@
   struct GNUNET_TIME_Absolute expires;
 
   /**
+   * Task used to re-validate addresses, updates latencies and
+   * verifies liveness.
+   */
+  GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
+
+  /**
    * Length of addr.
    */
   size_t addrlen;
@@ -720,7 +731,33 @@
 
 };
 
+/**
+ * Struct for keeping information about addresses to validate
+ * so that we can re-use for sending around ping's and receiving
+ * pongs periodically to keep connections alive and also better
+ * estimate latency of connections.
+ *
+ */
+struct PeriodicValidationContext
+{
 
+  /**
+   * The address we are keeping alive
+   */
+  struct ForeignAddressList *foreign_address;
+
+  /**
+   * The name of the transport
+   */
+  char *transport;
+
+  /**
+   * Public Key of the peer to re-validate
+   */
+  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
+
+};
+
 /**
  * Our HELLO message.
  */
@@ -1751,6 +1788,7 @@
                                   max);
 }
 
+static void send_periodic_ping(void *cls, const struct 
GNUNET_SCHEDULER_TaskContext *tc);
 
 /**
  * Iterator over hash map entries.  Checks if the given
@@ -1758,7 +1796,7 @@
  * is given in the PONG.
  *
  * @param cls the 'struct TransportPongMessage*'
- * @param key peer identity 
+ * @param key peer identity
  * @param value value in the hash map ('struct ValidationEntry')
  * @return GNUNET_YES if we should continue to
  *         iterate (mismatch), GNUNET_NO if not (entry matched)
@@ -1776,10 +1814,11 @@
   struct GNUNET_PeerIdentity target;
   struct NeighbourList *n;
   struct ForeignAddressList *fal;
+  struct PeriodicValidationContext *periodic_validation_context;
 
   if (ve->challenge != challenge)
     return GNUNET_YES;
-  
+
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Confirmed validity of address, peer `%4s' has address `%s' 
(%s).\n",
@@ -1798,18 +1837,25 @@
                               &add_validated_address,
                               &avac);
   GNUNET_PEERINFO_add_peer (cfg, sched,
-                           &target, 
+                           &target,
                            hello);
   GNUNET_free (hello);
   n = find_neighbour (&target);
   if (n != NULL)
     {
-      fal = add_peer_address (n, ve->transport_name, 
+      fal = add_peer_address (n, ve->transport_name,
                              ve->addr,
                              ve->addrlen);
       fal->expires = GNUNET_TIME_relative_to_absolute 
(HELLO_ADDRESS_EXPIRATION);
       fal->validated = GNUNET_YES;
       fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
+
+      periodic_validation_context = GNUNET_malloc(sizeof(struct 
PeriodicValidationContext));
+      periodic_validation_context->foreign_address = fal;
+      periodic_validation_context->transport = strdup(ve->transport_name);
+      memcpy(&periodic_validation_context->publicKey, &ve->publicKey, 
sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
+
+      fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched, 
TRANSPORT_DEFAULT_REVALIDATION, &send_periodic_ping, 
periodic_validation_context);
       if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
        n->latency = fal->latency;
       else
@@ -1824,7 +1870,7 @@
        {
          GNUNET_SCHEDULER_cancel (sched,
                                   n->retry_task);
-         n->retry_task = GNUNET_SCHEDULER_NO_TASK;     
+         n->retry_task = GNUNET_SCHEDULER_NO_TASK;
          try_transmission_to_peer (n);
        }
     }
@@ -1870,7 +1916,7 @@
              "Receiving `%s' message from `%4s'.\n", "PONG",
              GNUNET_i2s (peer));
 #endif
-  if (GNUNET_SYSERR != 
+  if (GNUNET_SYSERR !=
       GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
                                                  &peer->hashPubKey,
                                                  &check_pending_validation,
@@ -1891,15 +1937,15 @@
 #endif
       return;
     }
-  
+
 #if 0
   /* FIXME: add given address to potential pool of our addresses
      (for voting) */
   GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
              _("Another peer saw us using the address `%s' via `%s'.\n"),
              GNUNET_a2s ((const struct sockaddr *) &pong[1],
-                         ntohs(pong->addrlen)), 
-             va->transport_name);  
+                         ntohs(pong->addrlen)),
+             va->transport_name);
 #endif
 }
 
@@ -2052,8 +2098,155 @@
   GNUNET_free (va);
 }
 
+/**
+ * Check if the given address is already being validated; if not,
+ * append the given address to the list of entries that are being be
+ * validated and initiate validation.
+ *
+ * @param cls closure ('struct PeriodicValidationContext *')
+ * @param tname name of the transport
+ * @param expiration expiration time
+ * @param addr the address
+ * @param addrlen length of the address
+ * @return GNUNET_OK (always)
+ */
+static int
+rerun_validation (void *cls,
+                const char *tname,
+                struct GNUNET_TIME_Absolute expiration,
+                const void *addr, size_t addrlen)
+{
+  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey = cls;
+  struct GNUNET_PeerIdentity id;
+  struct TransportPlugin *tp;
+  struct ValidationEntry *va;
+  struct NeighbourList *neighbour;
+  struct ForeignAddressList *peer_address;
+  struct TransportPingMessage ping;
+  /*struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;*/
+  struct CheckAddressExistsClosure caec;
+  char * message_buf;
+  uint16_t hello_size;
+  size_t tsize;
 
+  tp = find_transport (tname);
+  if (tp == NULL)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO |
+                  GNUNET_ERROR_TYPE_BULK,
+                  _
+                  ("Transport `%s' not loaded, will not try to validate peer 
address using this transport.\n"),
+                  tname);
+      return GNUNET_OK;
+    }
+
+  GNUNET_CRYPTO_hash (publicKey,
+                      sizeof (struct
+                              GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+                      &id.hashPubKey);
+  caec.addr = addr;
+  caec.addrlen = addrlen;
+  caec.tname = tname;
+  caec.exists = GNUNET_NO;
+  GNUNET_CONTAINER_multihashmap_iterate (validation_map,
+                                         &check_address_exists,
+                                         &caec);
+  if (caec.exists == GNUNET_YES)
+    {
+      /* During validation attempts we will likely trigger the other
+         peer trying to validate our address which in turn will cause
+         it to send us its HELLO, so we expect to hit this case rather
+         frequently.  Only print something if we are very verbose. */
+#if DEBUG_TRANSPORT > 1
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Some validation of address `%s' via `%s' for peer `%4s' 
already in progress.\n",
+                  GNUNET_a2s (addr, addrlen),
+                  tname,
+                  GNUNET_i2s (&id));
+#endif
+      return GNUNET_OK;
+    }
+  va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
+  va->transport_name = GNUNET_strdup (tname);
+  va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                            (unsigned int) -1);
+  va->send_time = GNUNET_TIME_absolute_get();
+  va->addr = (const void*) &va[1];
+  memcpy (&va[1], addr, addrlen);
+  va->addrlen = addrlen;
+  memcpy(&va->publicKey, publicKey, sizeof(struct 
GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
+  va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
+                                                   HELLO_VERIFICATION_TIMEOUT,
+                                                   &timeout_hello_validation,
+                                                   va);
+  GNUNET_CONTAINER_multihashmap_put (validation_map,
+                                     &id.hashPubKey,
+                                     va,
+                                     
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+  neighbour = find_neighbour(&id);
+  if (neighbour == NULL)
+    neighbour = setup_new_neighbour(&id);
+  peer_address = add_peer_address(neighbour, tname, addr, addrlen);
+  GNUNET_assert(peer_address != NULL);
+  hello_size = GNUNET_HELLO_size(our_hello);
+  tsize = sizeof(struct TransportPingMessage) + hello_size;
+  message_buf = GNUNET_malloc(tsize);
+  ping.challenge = htonl(va->challenge);
+  ping.header.size = htons(sizeof(struct TransportPingMessage));
+  ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
+  memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
+  memcpy(message_buf, our_hello, hello_size);
+  memcpy(&message_buf[hello_size],
+         &ping,
+         sizeof(struct TransportPingMessage));
+#if DEBUG_TRANSPORT_REVALIDATION
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Performing re-validation of address `%s' via `%s' for peer 
`%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
+              GNUNET_a2s (addr, addrlen),
+              tname,
+              GNUNET_i2s (&id),
+              "HELLO", hello_size,
+              "PING", sizeof (struct TransportPingMessage));
+#endif
+  transmit_to_peer (NULL, peer_address,
+                    GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+                    HELLO_VERIFICATION_TIMEOUT,
+                    message_buf, tsize,
+                    GNUNET_YES, neighbour);
+  GNUNET_free(message_buf);
+  return GNUNET_OK;
+}
+
+
 /**
+ * Send periodic ping messages to a give foreign address.
+ *
+ * cls closure, can be safely cast to ForeignAddressList
+ * tc task context
+ *
+ * FIXME: Since a _billion_ pongs are sent for every ping,
+ * maybe this should be a special message type or something
+ * that gets discarded on the other side instead of initiating
+ * a flood.
+ */
+static void send_periodic_ping(void *cls, const struct 
GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct PeriodicValidationContext *periodic_validation_context = cls;
+
+  if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
+    {
+      GNUNET_free(periodic_validation_context->transport);
+      GNUNET_free(periodic_validation_context);
+      return; /* We have been shutdown, don't do anything! */
+    }
+
+  rerun_validation(&periodic_validation_context->publicKey, 
periodic_validation_context->transport, 
periodic_validation_context->foreign_address->expires, 
periodic_validation_context->foreign_address->addr, 
periodic_validation_context->foreign_address->addrlen);
+  GNUNET_free(periodic_validation_context->transport);
+  GNUNET_free(periodic_validation_context);
+}
+
+
+/**
  * Check if the given address is already being validated; if not,
  * append the given address to the list of entries that are being be
  * validated and initiate validation.
@@ -2115,12 +2308,12 @@
 #if DEBUG_TRANSPORT > 1
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Validation of address `%s' via `%s' for peer `%4s' already 
in progress.\n",
-                 GNUNET_a2s (addr, addrlen), 
-                 tname, 
+                 GNUNET_a2s (addr, addrlen),
+                 tname,
                  GNUNET_i2s (&id));
 #endif
       return GNUNET_OK;
-    } 
+    }
   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
   va->transport_name = GNUNET_strdup (tname);
   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
@@ -2134,15 +2327,15 @@
   va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
                                                   HELLO_VERIFICATION_TIMEOUT,
                                                   &timeout_hello_validation,
-                                                  va);  
+                                                  va);
   GNUNET_CONTAINER_multihashmap_put (validation_map,
                                     &id.hashPubKey,
                                     va,
                                     
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
-  neighbour = find_neighbour(&id);  
+  neighbour = find_neighbour(&id);
   if (neighbour == NULL)
     neighbour = setup_new_neighbour(&id);
-  peer_address = add_peer_address(neighbour, tname, addr, addrlen);    
+  peer_address = add_peer_address(neighbour, tname, addr, addrlen);
   GNUNET_assert(peer_address != NULL);
   hello_size = GNUNET_HELLO_size(our_hello);
   tsize = sizeof(struct TransportPingMessage) + hello_size;
@@ -2152,28 +2345,30 @@
   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
   memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
   memcpy(message_buf, our_hello, hello_size);
-  memcpy(&message_buf[hello_size], 
-        &ping, 
+  memcpy(&message_buf[hello_size],
+        &ping,
         sizeof(struct TransportPingMessage));
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Performing validation of address `%s' via `%s' for peer `%4s' 
sending `%s' (%u bytes) and `%s' (%u bytes)\n",
-              GNUNET_a2s (addr, addrlen), 
-             tname, 
+              GNUNET_a2s (addr, addrlen),
+             tname,
              GNUNET_i2s (&id),
              "HELLO", hello_size,
              "PING", sizeof (struct TransportPingMessage));
 #endif
-  transmit_to_peer (NULL, peer_address, 
+  transmit_to_peer (NULL, peer_address,
                    GNUNET_SCHEDULER_PRIORITY_DEFAULT,
                    HELLO_VERIFICATION_TIMEOUT,
-                   message_buf, tsize, 
+                   message_buf, tsize,
                    GNUNET_YES, neighbour);
   GNUNET_free(message_buf);
   return GNUNET_OK;
 }
 
 
+
+
 /**
  * Add the given address to the list of foreign addresses
  * available for the given peer (check for duplicates).





reply via email to

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