transmit PONGs
authorChristian Grothoff <christian@grothoff.org>
Sat, 6 Aug 2011 19:39:49 +0000 (19:39 +0000)
committerChristian Grothoff <christian@grothoff.org>
Sat, 6 Aug 2011 19:39:49 +0000 (19:39 +0000)
src/transport/gnunet-service-transport-new.c
src/transport/gnunet-service-transport.h
src/transport/gnunet-service-transport_validation.c
src/transport/gnunet-service-transport_validation.h

index afbf328a5a40ef50f5907ac153ffad80acf32d00..061cdd9a302795418e02d61c1be81e5ca6ac8524 100644 (file)
@@ -66,7 +66,7 @@ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded GST_my_public_key;
 /**
  * Our private key.
  */
-static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
+struct GNUNET_CRYPTO_RsaPrivateKey *GST_my_private_key;
 
 
 /**
@@ -140,10 +140,10 @@ shutdown_task (void *cls,
       GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
       GST_stats = NULL;
     }  
-  if (my_private_key != NULL)
+  if (GST_my_private_key != NULL)
     {
-      GNUNET_CRYPTO_rsa_key_free (my_private_key);
-      my_private_key = NULL;
+      GNUNET_CRYPTO_rsa_key_free (GST_my_private_key);
+      GST_my_private_key = NULL;
     }
 }
 
@@ -180,9 +180,9 @@ run (void *cls,
       GNUNET_SCHEDULER_shutdown ();
       return;
     }
-  my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
+  GST_my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
   GNUNET_free (keyfile);
-  if (my_private_key == NULL)
+  if (GST_my_private_key == NULL)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   _("Transport service could not access hostkey.  Exiting.\n"));
@@ -191,7 +191,7 @@ run (void *cls,
     }
   GST_stats = GNUNET_STATISTICS_create ("transport", c);
   GST_peerinfo = GNUNET_PEERINFO_connect (c);
-  GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &GST_my_public_key);
+  GNUNET_CRYPTO_rsa_key_get_public (GST_my_private_key, &GST_my_public_key);
   GNUNET_CRYPTO_hash (&GST_my_public_key,
                       sizeof (GST_my_public_key), &GST_my_identity.hashPubKey);
   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
index d6eda464a067e30425550d6ebac9cb3d7eb0c797..38bd8b85a522c32fc5a83b11e8e039a5d129005a 100644 (file)
@@ -55,5 +55,10 @@ extern struct GNUNET_PEERINFO_Handle *GST_peerinfo;
  */
 extern struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded GST_my_public_key;
 
+/**
+ * Our private key.
+ */
+extern struct GNUNET_CRYPTO_RsaPrivateKey *GST_my_private_key;
+
 #endif
 /* end of file gnunet-service-transport_plugins.h */
index 9583fc1a790dadb5c4252d1f70d66d83cc775f13..d0331c192f1419d232d6a84b727024c58790471a 100644 (file)
@@ -29,6 +29,7 @@
 #include "gnunet-service-transport.h"
 #include "gnunet_hello_lib.h"
 #include "gnunet_peerinfo_service.h"
+#include "gnunet_signatures.h"
 
 
 /**
  */ 
 #define PING_PRIORITY 1
 
+/**
+ * Priority to use for PINGs and PONGs
+ */ 
+#define PONG_PRIORITY 1
+
+
 /**
  * Message used to ask a peer to validate receipt (to check an address
  * from a HELLO).  Followed by the address we are trying to validate,
@@ -474,11 +481,55 @@ find_validation_entry (struct GNUNET_PeerIdentity *neighbour,
 }
 
 
+/**
+ * Send the given PONG to the given address.
+ *
+ * @param cls the PONG message
+ * @param target peer this change is about, never NULL
+ * @param valid_until is ZERO if we never validated the address,
+ *                    otherwise a time up to when we consider it (or was) valid
+ * @param validation_block  is FOREVER if the address is for an unsupported plugin (from PEERINFO)
+ *                          is ZERO if the address is considered valid (no validation needed)
+ *                          otherwise a time in the future if we're currently denying re-validation
+ * @param plugin_name name of the plugin
+ * @param plugin_address binary address
+ * @param plugin_address_len length of address
+ */
+static void
+multicast_pong (void *cls,
+               const struct GNUNET_PeerIdentity *target,
+               struct GNUNET_TIME_Absolute valid_until,
+               struct GNUNET_TIME_Absolute validation_block,
+               const char *plugin_name,
+               const void *plugin_address,
+               size_t plugin_address_len)
+{
+  struct TransportPongMessage *pong = cls;
+  struct GNUNET_TRANSPORT_PluginFunctions *papi;
+
+  papi = GST_plugins_find (plugin_name);
+  if (papi == NULL)
+    return;
+  (void) papi->send (papi->cls,
+                    target,
+                    (const char*) pong,
+                    ntohs (pong->header.size),
+                    PONG_PRIORITY,
+                    HELLO_VERIFICATION_TIMEOUT,
+                    NULL,
+                    plugin_address,
+                    plugin_address_len,
+                    GNUNET_YES,
+                    NULL, NULL);
+}
+
+
 /**
  * We've received a PING.  If appropriate, generate a PONG.
  *
  * @param sender peer sending the PING
  * @param hdr the PING
+ * @param session session we got the PING from
  * @param plugin_name name of plugin that received the PING
  * @param sender_address address of the sender as known to the plugin, NULL
  *                       if we did not initiate the connection
@@ -488,9 +539,253 @@ void
 GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
                            const struct GNUNET_MessageHeader *hdr,
                            const char *plugin_name,
+                           struct Session *session,
                            const void *sender_address,
                            size_t sender_address_len)
 {
+
+  const struct TransportPingMessage *ping;
+  struct TransportPongMessage *pong;
+  struct GNUNET_TRANSPORT_PluginFunctions *papi;
+  const char *addr;
+  const char *addrend;
+  size_t alen;
+  size_t slen;
+  ssize_t ret;
+
+  if (ntohs (hdr->size) < sizeof (struct TransportPingMessage))
+    {
+      GNUNET_break_op (0);
+      return;
+    }
+  ping = (const struct TransportPingMessage *) hdr;
+  if (0 != memcmp (&ping->target,
+                   &GST_my_identity,
+                   sizeof (struct GNUNET_PeerIdentity)))
+    {
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
+                 "PING",
+                 (sender_address != NULL)
+                 ? GST_plugin_a2s (plugin_name,
+                                   sender_address,
+                                   sender_address_len)
+                 : "<inbound>",
+                 GNUNET_i2s (&ping->target));
+#endif
+      return;
+    }
+#if DEBUG_TRANSPORT
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+             "Processing `%s' from `%s'\n",
+             "PING",
+             (sender_address != NULL)
+             ? GST_plugin_a2s (plugin_name,
+                               sender_address,
+                               sender_address_len)
+             : "<inbound>");
+#endif
+  GNUNET_STATISTICS_update (GST_stats,
+                           gettext_noop ("# PING messages received"),
+                           1,
+                           GNUNET_NO);
+  addr = (const char*) &ping[1];
+  alen = ntohs (hdr->size) - sizeof (struct TransportPingMessage);
+  if (alen == 0)
+    {
+      /* peer wants to confirm that we have an outbound connection to him */
+      if (sender_address == NULL)
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                     _("Refusing to create PONG since I do initiate the session with `%s'.\n"),
+                     GNUNET_i2s (sender));
+         return;
+       }
+#if DEBUG_TRANSPORT
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Creating PONG indicating that we initiated a connection to peer `%s' using address `%s' \n",
+                 GNUNET_i2s (peer),
+                 GST_plugin_a2s (plugin_name,
+                                 sender_address,
+                                 sender_address_len));
+#endif
+      slen = strlen (plugin_name) + 1;
+      pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
+      pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
+      pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
+      pong->purpose.size =
+       htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+              sizeof (uint32_t) +
+              sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+              sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
+      pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
+      pong->challenge = ping->challenge;
+      pong->addrlen = htonl(sender_address_len + slen);
+      pong->pid = *sender;
+      memcpy (&pong[1],
+             plugin_name,
+             slen);
+      memcpy (&((char*)&pong[1])[slen],
+             sender_address,
+             sender_address_len);
+#if 0
+      /* FIXME: lookup signature! */
+      if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < 
+         PONG_SIGNATURE_LIFETIME.rel_value / 4)
+       {
+         /* create / update cached sig */
+#if DEBUG_TRANSPORT
+         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Creating PONG signature to indicate active connection.\n");
+#endif
+         session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
+         pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
+         GNUNET_assert (GNUNET_OK ==
+                        GNUNET_CRYPTO_rsa_sign (my_private_key,
+                                                &pong->purpose,
+                                                &session_header->pong_signature));
+       }
+      else
+       {
+         pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
+       }
+      memcpy (&pong->signature,
+             &session_header->pong_signature,
+             sizeof (struct GNUNET_CRYPTO_RsaSignature));
+#else
+      pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
+      GNUNET_assert (GNUNET_OK ==
+                    GNUNET_CRYPTO_rsa_sign (GST_my_private_key,
+                                            &pong->purpose,
+                                            &pong->signature));
+#endif
+    }
+  else
+    {
+      /* peer wants to confirm that this is one of our addresses */
+      addrend = memchr (addr, '\0', alen);
+      if (NULL == addrend)
+       {
+         GNUNET_break_op (0);
+         return;
+       }
+      addrend++;
+      slen = strlen(addr);
+      alen -= slen;
+      papi = GST_plugins_find (addr);
+      
+      if ( (NULL == papi) ||
+          (GNUNET_OK !=
+           papi->check_address (papi->cls,
+                                addrend,
+                                alen)) )
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                     _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
+                     GST_plugins_a2s (addr,
+                                      addrend,
+                                      alen));
+         return;
+       }
+
+      pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
+      pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
+      pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
+      pong->purpose.size =
+       htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+              sizeof (uint32_t) +
+              sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+              sizeof (struct GNUNET_PeerIdentity) + alen + slen);
+      pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
+      pong->challenge = ping->challenge;
+      pong->addrlen = htonl(alen + slen);
+      pong->pid = GST_my_identity;
+      memcpy (&pong[1], addr, slen);
+      memcpy (&((char*)&pong[1])[slen], addrend, alen);
+#if 0
+      if ( (oal != NULL) &&
+          (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
+       {
+         /* create / update cached sig */
+#if DEBUG_TRANSPORT
+         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Creating PONG signature to indicate ownership.\n");
+#endif
+         oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
+         pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
+         GNUNET_assert (GNUNET_OK ==
+                        GNUNET_CRYPTO_rsa_sign (my_private_key,
+                                                &pong->purpose,
+                                                &oal->pong_signature));
+         memcpy (&pong->signature,
+                 &oal->pong_signature,
+                 sizeof (struct GNUNET_CRYPTO_RsaSignature));
+       }
+      else if (oal == NULL)
+       {
+#else
+         /* not using cache (typically DV-only) */
+         pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
+         GNUNET_assert (GNUNET_OK ==
+                        GNUNET_CRYPTO_rsa_sign (GST_my_private_key,
+                                                &pong->purpose,
+                                                &pong->signature));
+#endif
+#if 0
+       }
+      else
+       {
+         /* can used cached version */
+         pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
+         memcpy (&pong->signature,
+                 &oal->pong_signature,
+                 sizeof (struct GNUNET_CRYPTO_RsaSignature));
+       }
+#endif
+    }
+
+  /* first see if the session we got this PING from can be used to transmit
+     a response reliably */
+  papi = GST_plugins_find (plugin_name);
+  if (papi == NULL)
+    ret = -1;
+  else
+    ret = papi->send (papi->cls,
+                     sender,
+                     (const char*) pong,
+                     ntohs (pong->header.size),
+                     PONG_PRIORITY,
+                     HELLO_VERIFICATION_TIMEOUT,
+                     session,
+                     sender_address,
+                     sender_address_len,
+                     GNUNET_SYSERR,
+                     NULL, NULL);
+  if (ret != -1)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Transmitted PONG to `%s' via reliable mechanism\n",
+                 GNUNET_i2s (sender));
+      /* done! */
+      GNUNET_STATISTICS_update (GST_stats,
+                               gettext_noop ("# PONGs unicast via reliable transport"),
+                               1,
+                               GNUNET_NO);
+      GNUNET_free (pong);
+      return;
+    }
+  
+  /* no reliable method found, try transmission via all known addresses */
+  GNUNET_STATISTICS_update (GST_stats,
+                           gettext_noop ("# PONGs multicast to all available addresses"),
+                           1,
+                           GNUNET_NO);
+  (void) GST_validation_get_addresses (sender,
+                                      GNUNET_YES,
+                                      &multicast_pong,
+                                      pong);
+  GNUNET_free (pong);
 }
 
 
@@ -571,17 +866,20 @@ validate_address (void *cls,
           ve->addr,
           ve->addrlen);
     papi = GST_plugins_find (ve->transport_name);
-    ret = papi->send (papi->cls,
-                     pid,
-                     message_buf,
-                     tsize,
-                     PING_PRIORITY,
-                     HELLO_VERIFICATION_TIMEOUT,
-                     NULL /* no session */,
-                     ve->addr,
-                     ve->addrlen,
-                     GNUNET_YES,
-                     NULL, NULL);
+    if (papi == NULL)
+      ret = -1;
+    else
+      ret = papi->send (papi->cls,
+                       pid,
+                       message_buf,
+                       tsize,
+                       PING_PRIORITY,
+                       HELLO_VERIFICATION_TIMEOUT,
+                       NULL /* no session */,
+                       ve->addr,
+                       ve->addrlen,
+                       GNUNET_YES,
+                       NULL, NULL);
   }
   if (-1 != ret)
     {
@@ -595,7 +893,6 @@ validate_address (void *cls,
 }
 
 
-
 /**
  * We've received a HELLO, check which addresses are new and trigger
  * validation.
index 218b45457408ab4fa94d86947d2e0aaa56595526..27d30d83a00da70b0b458e613642071397467314 100644 (file)
@@ -27,6 +27,7 @@
 #define GNUNET_SERVICE_TRANSPORT_VALIDATION_H
 
 #include "gnunet_statistics_service.h"
+#include "gnunet_transport_plugin.h"
 #include "gnunet_util_lib.h"
 
 
@@ -50,6 +51,7 @@ GST_validation_stop (void);
  * @param sender peer sending the PING
  * @param hdr the PING
  * @param plugin_name name of plugin that received the PING
+ * @param session session we got the PING from
  * @param sender_address address of the sender as known to the plugin, NULL
  *                       if we did not initiate the connection
  * @param sender_address_len number of bytes in sender_address
@@ -58,6 +60,7 @@ void
 GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
                            const struct GNUNET_MessageHeader *hdr,
                            const char *plugin_name,
+                           struct Session *session,
                            const void *sender_address,
                            size_t sender_address_len);