gnunet-svn
[Top][All Lists]
Advanced

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

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


From: gnunet
Subject: [GNUnet-SVN] r10625 - gnunet/src/transport
Date: Tue, 16 Mar 2010 18:59:55 +0100

Author: grothoff
Date: 2010-03-16 18:59:55 +0100 (Tue, 16 Mar 2010)
New Revision: 10625

Modified:
   gnunet/src/transport/gnunet-service-transport.c
Log:
trying to fix revalidation PING and connect core notification

Modified: gnunet/src/transport/gnunet-service-transport.c
===================================================================
--- gnunet/src/transport/gnunet-service-transport.c     2010-03-16 16:20:44 UTC 
(rev 10624)
+++ gnunet/src/transport/gnunet-service-transport.c     2010-03-16 17:59:55 UTC 
(rev 10625)
@@ -25,9 +25,6 @@
  *
  * BUGS:
  * - bi-directional nature of TCP is not exploited
- * - re-validation is broken (triggered only on successful validation,
- *   does not consider expiration times)
- * 
  *
  * NOTE:
  * - This code uses 'GNUNET_a2s' for debug printing in many places,
@@ -103,11 +100,6 @@
 #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, 60)
-
-/**
  * Priority to use for PONG messages.
  */
 #define TRANSPORT_PONG_PRIORITY 4
@@ -133,8 +125,18 @@
  */
 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_HOURS, 1)
 
+/**
+ * Maximum frequency for re-evaluating latencies for all transport addresses.
+ */
+#define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_HOURS, 1)
 
 /**
+ * Maximum frequency for re-evaluating latencies for connected addresses.
+ */
+#define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_MINUTES, 1)
+
+
+/**
  * List of addresses of other peers
  */
 struct ForeignAddressList
@@ -172,8 +174,7 @@
   const void *addr;
 
   /**
-   * What was the last latency observed for this plugin
-   * and peer?  Invalid if connected is GNUNET_NO.
+   * What was the last latency observed for this address, plugin and peer?
    */
   struct GNUNET_TIME_Relative latency;
 
@@ -187,39 +188,46 @@
   struct GNUNET_TIME_Absolute timeout;
 
   /**
+   * How often have we tried to connect using this plugin?  Used to
+   * discriminate against addresses that do not work well.
+   * FIXME: not yet used, but should be!
+   */
+  unsigned int connect_attempts;
+
+  /**
+   * DV distance to this peer (1 if no DV is used). 
+   * FIXME: need to set this from transport plugins!
+   */
+  uint32_t distance;
+
+  /**
+   * Have we ever estimated the latency of this address?  Used to
+   * ensure that the first time we add an address, we immediately
+   * probe its latency.
+   */
+  int8_t estimated;
+
+  /**
    * Are we currently connected via this address?  The first time we
    * successfully transmit or receive data to a peer via a particular
    * address, we set this to GNUNET_YES.  If we later get an error
    * (disconnect notification, transmission failure, timeout), we set
    * it back to GNUNET_NO.  
    */
-  int connected;
+  int8_t connected;
 
   /**
    * Is this plugin currently busy transmitting to the specific target?
    * GNUNET_NO if not (initial, default state is GNUNET_NO).   Internal
    * messages do not count as 'in transmit'.
    */
-  int in_transmit;
+  int8_t in_transmit;
 
   /**
    * Has this address been validated yet?
    */
-  int validated;
+  int8_t validated;
 
-  /**
-   * How often have we tried to connect using this plugin?  Used to
-   * discriminate against addresses that do not work well.
-   * FIXME: not yet used, but should be!
-   */
-  unsigned int connect_attempts;
-
-  /**
-   * DV distance to this peer (1 if no DV is used). 
-   * FIXME: need to set this from transport plugins!
-   */
-  uint32_t distance;
-
 };
 
 
@@ -405,6 +413,11 @@
    */
   struct ForeignAddressList *addresses;
 
+  /**
+   * To which neighbour does this ready list belong to?
+   */
+  struct NeighbourList *neighbour;
+
 };
 
 
@@ -444,6 +457,11 @@
   struct GNUNET_PEERINFO_IteratorContext *piter;
 
   /**
+   * Public key for this peer.   Valid only if the respective flag is set 
below.
+   */
+  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
+
+  /**
    * Identity of this neighbour.
    */
   struct GNUNET_PeerIdentity id;
@@ -506,6 +524,11 @@
    */
   int received_pong;
 
+  /**
+   * Do we have a valid public key for this neighbour?
+   */
+  int public_key_valid;
+
 };
 
 /**
@@ -734,33 +757,7 @@
 
 };
 
-/**
- * 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.
  */
@@ -1571,6 +1568,8 @@
             plugin->addresses = pos->next;
           else
             prev->next = pos->next;
+
+         
           GNUNET_free (pos);
         }
       else
@@ -1964,7 +1963,16 @@
 }
 
 
+/**
+ * Schedule the job that will cause us to send a PING to the
+ * foreign address to evaluate its validity and latency.
+ *
+ * @param fal address to PING
+ */
+static void
+schedule_next_ping (struct ForeignAddressList *fal);
 
+
 /**
  * Add the given address to the list of foreign addresses
  * available for the given peer (check for duplicates).
@@ -2010,8 +2018,19 @@
                                    1,
                                    GNUNET_NO); 
        }
+      else
+       {
+         fal->expires = GNUNET_TIME_absolute_max (expiration,
+                                                  fal->expires);
+         schedule_next_ping (fal);
+       }
       try = GNUNET_YES;
     }
+  else
+    {
+      fal->expires = GNUNET_TIME_absolute_max (expiration,
+                                              fal->expires);
+    }
   if (fal == NULL)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -2019,8 +2038,6 @@
                  GNUNET_i2s (&n->id));
       return GNUNET_OK;
     }
-  fal->expires = GNUNET_TIME_absolute_max (expiration,
-                                          fal->expires);
   if (fal->validated == GNUNET_NO)
     {
       fal->validated = GNUNET_YES;  
@@ -2069,6 +2086,11 @@
              "HELLO",
              GNUNET_i2s (peer));
 #endif
+  if (GNUNET_YES != n->public_key_valid)
+    {
+      GNUNET_HELLO_get_key (h, &n->publicKey);
+      n->public_key_valid = GNUNET_YES;
+    }
   GNUNET_HELLO_iterate_addresses (h,
                                  GNUNET_NO,
                                  &add_to_foreign_address_list,
@@ -2111,6 +2133,7 @@
       if (tp->api->send != NULL)
         {
           rl = GNUNET_malloc (sizeof (struct ReadyList));
+         rl->neighbour = n;
           rl->next = n->plugins;
           n->plugins = rl;
           rl->plugin = tp;
@@ -2144,48 +2167,31 @@
 send_periodic_ping (void *cls, 
                    const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  struct PeriodicValidationContext *pvc = cls;
-  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey = pvc->publicKey;
-  char *tname = pvc->transport;
-  const void *addr = pvc->foreign_address->addr;
-  size_t addrlen = pvc->foreign_address->addrlen;
+  struct ForeignAddressList *peer_address = cls;
   struct GNUNET_PeerIdentity id;
   struct TransportPlugin *tp;
   struct ValidationEntry *va;
   struct NeighbourList *neighbour;
-  struct ForeignAddressList *peer_address;
   struct TransportPingMessage ping;
   struct CheckAddressExistsClosure caec;
   char * message_buf;
   uint16_t hello_size;
   size_t tsize;
 
-  GNUNET_free (pvc);
+  peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
+    return; 
+  tp = peer_address->ready_list->plugin;
+  neighbour = peer_address->ready_list->neighbour;
+  if (GNUNET_YES != neighbour->public_key_valid)
     {
-      /* We have been shutdown, don't do anything! */
-      GNUNET_free (tname);
-      return; 
-    }
-  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);
-      GNUNET_free (tname);
+      /* no public key yet, try again later */
+      schedule_next_ping (peer_address);     
       return;
     }
-
-  GNUNET_CRYPTO_hash (&publicKey,
-                      sizeof (struct
-                              GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
-                      &id.hashPubKey);
-  caec.addr = addr;
-  caec.addrlen = addrlen;
-  caec.tname = tname;
+  caec.addr = peer_address->addr;
+  caec.addrlen = peer_address->addrlen;
+  caec.tname = tp->short_name;
   caec.exists = GNUNET_NO;
   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
                                          &check_address_exists,
@@ -2199,37 +2205,35 @@
 #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));
+                  GNUNET_a2s (peer_address->addr,
+                             peer_address->addrlen),
+                  tp->short_name,
+                  GNUNET_i2s (&neighbour->id));
 #endif
-      GNUNET_free (tname);
+      schedule_next_ping (peer_address);     
       return;
     }
-  va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
-  va->transport_name = tname;
+  va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
+  va->transport_name = GNUNET_strdup (tp->short_name);
   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));
+  memcpy (&va[1], peer_address->addr, peer_address->addrlen);
+  va->addrlen = peer_address->addrlen;
+
+  memcpy(&va->publicKey,
+        &neighbour->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,
+                                     &neighbour->id.hashPubKey,
                                      va,
                                      
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
-  neighbour = find_neighbour(&id);
-  /* FIXME: can neighbour be NULL here? (why do we still PING?)?  If so,
-     should we even do this? */
-  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);
@@ -2244,9 +2248,10 @@
 #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),
+              GNUNET_a2s (peer_address->addr,
+                         peer_address->addrlen),
+              tp->short_name,
+              GNUNET_i2s (&neighbour->id),
               "HELLO", hello_size,
               "PING", sizeof (struct TransportPingMessage));
 #endif
@@ -2260,10 +2265,52 @@
                     message_buf, tsize,
                     GNUNET_YES, neighbour);
   GNUNET_free(message_buf);
+  schedule_next_ping (peer_address);
 }
 
 
 /**
+ * Schedule the job that will cause us to send a PING to the
+ * foreign address to evaluate its validity and latency.
+ *
+ * @param fal address to PING
+ */
+static void
+schedule_next_ping (struct ForeignAddressList *fal)
+{
+  struct GNUNET_TIME_Relative delay;
+
+  if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
+    return;
+  delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
+  delay.value /= 2; /* do before expiration */
+  delay = GNUNET_TIME_relative_min (delay,
+                                   LATENCY_EVALUATION_MAX_DELAY);
+  if (GNUNET_YES != fal->estimated)
+    {
+      delay = GNUNET_TIME_UNIT_ZERO;
+      fal->estimated = GNUNET_YES;
+    }                              
+  if (GNUNET_YES == fal->connected)
+    {
+      delay = GNUNET_TIME_relative_min (delay,
+                                       CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
+    }  
+  /* FIXME: also adjust delay based on how close the last
+     observed latency is to the latency of the best alternative */
+  /* bound how fast we can go */
+  delay = GNUNET_TIME_relative_max (delay,
+                                   GNUNET_TIME_UNIT_SECONDS);
+  /* randomize a bit (to avoid doing all at the same time) */
+  delay.value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
+  fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched, 
+                                                     delay,
+                                                     &send_periodic_ping, 
+                                                     fal);
+}
+
+
+/**
  * Iterator over hash map entries.  Checks if the given validation
  * entry is for the same challenge as what is given in the PONG.
  *
@@ -2286,7 +2333,6 @@
   struct GNUNET_PeerIdentity target;
   struct NeighbourList *n;
   struct ForeignAddressList *fal;
-  struct PeriodicValidationContext *periodic_validation_context;
 
   if (ve->challenge != challenge)
     return GNUNET_YES;
@@ -2319,6 +2365,8 @@
   n = find_neighbour (&target);
   if (n != NULL)
     {
+      n->publicKey = ve->publicKey;
+      n->public_key_valid = GNUNET_YES;
       fal = add_peer_address (n,
                              ve->transport_name,
                              ve->addr,
@@ -2331,21 +2379,7 @@
                                1,
                                GNUNET_NO);      
       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));
-      /* FIXME: this causes all of the revalidation PINGs for the same HELLO
-        to be transmitted in bulk, which is not nice; also,
-        triggering these HERE means that revalidations do NOT happen AT ALL
-        for HELLOs a previous instance of this process validated (since
-        there is no "initial" validation PING => no revalidation => BUG! */
-      fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched, 
-                                                         
TRANSPORT_DEFAULT_REVALIDATION, 
-                                                         &send_periodic_ping, 
-                                                         
periodic_validation_context);
+      schedule_next_ping (fal);
       if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
        n->latency = fal->latency;
       else
@@ -2545,6 +2579,8 @@
   neighbour = find_neighbour(&id);
   if (neighbour == NULL)
     neighbour = setup_new_neighbour(&id);
+  neighbour->publicKey = va->publicKey;
+  neighbour->public_key_valid = GNUNET_YES;
   peer_address = add_peer_address(neighbour, tname, addr, addrlen);
   GNUNET_assert(peer_address != NULL);
   hello_size = GNUNET_HELLO_size(our_hello);
@@ -2844,6 +2880,12 @@
                                      gettext_noop ("# peer addresses 
considered valid"),
                                      -1,
                                      GNUNET_NO);      
+         if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
+           {
+             GNUNET_SCHEDULER_cancel (sched,
+                                      peer_pos->revalidate_task);
+             peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
+           }
           GNUNET_free(peer_pos);
         }
       GNUNET_free (rpos);
@@ -3032,8 +3074,9 @@
          peer_address->distance = distance;
          if (peer_address->connected == GNUNET_NO)
            {
+             /* FIXME: be careful here to not mark
+                MULTIPLE addresses as connected! */
              peer_address->connected = GNUNET_YES;
-             peer_address->connect_attempts++;
              GNUNET_STATISTICS_update (stats,
                                        gettext_noop ("# connected addresses"),
                                        1,
@@ -3043,6 +3086,7 @@
            =
            GNUNET_TIME_relative_to_absolute
            (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
+         schedule_next_ping (peer_address);
        }
       /* update traffic received amount ... */
       msize = ntohs (message->size);      





reply via email to

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