- log
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh_tunnel.c
index 71bc14d11ee47ab46492be9d3686e2ad2674ac00..a13d88fd53ad3a9ea3111eb5d973cd49fbc1e3f8 100644 (file)
@@ -24,7 +24,7 @@
 #include "gnunet_signatures.h"
 #include "gnunet_statistics_service.h"
 
-#include "mesh_protocol_enc.h"
+#include "mesh_protocol.h"
 #include "mesh_path.h"
 
 #include "gnunet-service-mesh_tunnel.h"
@@ -34,7 +34,7 @@
 
 #define LOG(level, ...) GNUNET_log_from(level,"mesh-tun",__VA_ARGS__)
 
-#define REKEY_WAIT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
+#define REKEY_WAIT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5)
 
 /******************************************************************************/
 /********************************   STRUCTS  **********************************/
@@ -136,21 +136,21 @@ struct MeshTunnel3
   /**
    * Queued messages, to transmit once tunnel gets connected.
    */
-  struct MeshTunnelQueue *tq_head;
-  struct MeshTunnelQueue *tq_tail;
+  struct MeshTunnelDelayed *tq_head;
+  struct MeshTunnelDelayed *tq_tail;
 };
 
 
 /**
- * Struct used to queue messages in a tunnel.
+ * Struct used to save messages in a non-ready tunnel to send once connected.
  */
-struct MeshTunnelQueue
+struct MeshTunnelDelayed
 {
   /**
    * DLL
    */
-  struct MeshTunnelQueue *next;
-  struct MeshTunnelQueue *prev;
+  struct MeshTunnelDelayed *next;
+  struct MeshTunnelDelayed *prev;
 
   /**
    * Channel.
@@ -164,6 +164,28 @@ struct MeshTunnelQueue
 };
 
 
+/**
+ * Handle for messages queued but not yet sent.
+ */
+struct MeshTunnel3Queue
+{
+  /**
+   * Connection queue handle, to cancel if necessary.
+   */
+  struct MeshConnectionQueue *q;
+
+  /**
+   * Continuation to call once sent.
+   */
+  GMT_sent cont;
+
+  /**
+   * Closure for @c cont.
+   */
+  void *cont_cls;
+};
+
+
 /******************************************************************************/
 /*******************************   GLOBALS  ***********************************/
 /******************************************************************************/
@@ -246,8 +268,6 @@ GMT_state2s (enum MeshTunnel3State s)
       return "MESH_TUNNEL3_WAITING";
     case MESH_TUNNEL3_KEY_SENT:
       return "MESH_TUNNEL3_KEY_SENT";
-    case MESH_TUNNEL3_PING_SENT:
-      return "MESH_TUNNEL3_PING_SENT";
     case MESH_TUNNEL3_READY:
       return "MESH_TUNNEL3_READY";
     case MESH_TUNNEL3_RECONNECTING:
@@ -375,7 +395,7 @@ get_connection_allowed (const struct MeshTConnection *tc)
  * @return GNUNET_OK if message is fine, GNUNET_SYSERR otherwise.
  */
 int
-check_ephemeral (struct MeshTunnel3 *t, 
+check_ephemeral (struct MeshTunnel3 *t,
                  const struct GNUNET_MESH_KX_Ephemeral *msg)
 {
   /* Check message size */
@@ -441,7 +461,7 @@ t_decrypt (struct MeshTunnel3 *t,
 {
   struct GNUNET_CRYPTO_SymmetricInitializationVector siv;
 
-  GNUNET_CRYPTO_symmetric_derive_iv (&siv, &t->e_key, &iv, sizeof (uint32_t), NULL);
+  GNUNET_CRYPTO_symmetric_derive_iv (&siv, &t->d_key, &iv, sizeof (uint32_t), NULL);
   return GNUNET_CRYPTO_symmetric_decrypt (src, size, &t->d_key, &siv, dst);
 }
 
@@ -535,13 +555,13 @@ tunnel_get_connection (struct MeshTunnel3 *t)
 static void
 send_queued_data (struct MeshTunnel3 *t)
 {
-  struct MeshTunnelQueue *tq;
-  struct MeshTunnelQueue *next;
+  struct MeshTunnelDelayed *tq;
+  struct MeshTunnelDelayed *next;
   unsigned int room;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-              "GMT_send_queued_data on tunnel %s\n",
-              GMT_2s (t));
+       "GMT_send_queued_data on tunnel %s\n",
+       GMT_2s (t));
 
   if (GMT_is_loopback (t))
   {
@@ -558,7 +578,8 @@ send_queued_data (struct MeshTunnel3 *t)
     room--;
     GNUNET_CONTAINER_DLL_remove (t->tq_head, t->tq_tail, tq);
     GMCH_send_prebuilt_message ((struct GNUNET_MessageHeader *) &tq[1],
-                                tq->ch, GMCH_is_origin (tq->ch, GNUNET_YES));
+                                tq->ch, GMCH_is_origin (tq->ch, GNUNET_YES),
+                                GNUNET_NO);
 
     GNUNET_free (tq);
   }
@@ -582,7 +603,7 @@ queue_data (struct MeshTunnel3 *t,
             struct MeshChannel *ch,
             const struct GNUNET_MessageHeader *msg)
 {
-  struct MeshTunnelQueue *tq;
+  struct MeshTunnelDelayed *tq;
   uint16_t size = ntohs (msg->size);
 
   if (MESH_TUNNEL3_READY == t->state)
@@ -591,7 +612,7 @@ queue_data (struct MeshTunnel3 *t,
     return;
   }
 
-  tq = GNUNET_malloc (sizeof (struct MeshTunnelQueue) + size);
+  tq = GNUNET_malloc (sizeof (struct MeshTunnelDelayed) + size);
 
   tq->ch = ch;
   memcpy (&tq[1], msg, size);
@@ -660,7 +681,8 @@ send_kx (struct MeshTunnel3 *t,
   }
 
   fwd = GMC_is_origin (t->connection_head->c, GNUNET_YES);
-  GMC_send_prebuilt_message (&msg->header, c, fwd);
+  /* TODO save handle and cancel in case of a unneeded retransmission */
+  GMC_send_prebuilt_message (&msg->header, c, fwd, NULL, NULL);
 }
 
 
@@ -697,8 +719,6 @@ send_ping (struct MeshTunnel3 *t)
 
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  sending %u\n", msg.nonce);
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  towards %s\n", GNUNET_i2s (&msg.target));
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  using e %s\n", GNUNET_h2s (&t->e_key));
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  using iv %u\n", msg.iv);
   t_encrypt (t, &msg.target, &msg.target, ping_encryption_size(), msg.iv);
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  e sending %u\n", msg.nonce);
   LOG (GNUNET_ERROR_TYPE_DEBUG, "  e towards %s\n", GNUNET_i2s (&msg.target));
@@ -723,7 +743,9 @@ send_pong (struct MeshTunnel3 *t, uint32_t challenge)
   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_KX_PONG);
   msg.iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
   msg.nonce = challenge;
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  sending %u\n", msg.nonce);
   t_encrypt (t, &msg.nonce, &msg.nonce, sizeof (msg.nonce), msg.iv);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  e sending %u\n", msg.nonce);
 
   send_kx (t, &msg.header);
 }
@@ -742,15 +764,20 @@ rekey_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 
   t->rekey_task = GNUNET_SCHEDULER_NO_TASK;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Re-key Tunnel\n");
   if (NULL != tc && 0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
     return;
 
-  t->kx_ctx = GNUNET_new (struct MeshTunnelKXCtx);
-  t->kx_ctx->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
-                                                   UINT32_MAX);
-  t->kx_ctx->d_key_old = t->d_key;
+  if (NULL == t->kx_ctx)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "  new kx ctx\n");
+    t->kx_ctx = GNUNET_new (struct MeshTunnelKXCtx);
+    t->kx_ctx->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+                                                     UINT32_MAX);
+    t->kx_ctx->d_key_old = t->d_key;
+  }
   send_ephemeral (t);
-  if (MESH_TUNNEL3_READY == t->state)
+  if (MESH_TUNNEL3_READY == t->state || MESH_TUNNEL3_REKEY == t->state)
   {
     send_ping (t);
     t->state = MESH_TUNNEL3_REKEY;
@@ -764,6 +791,8 @@ rekey_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     LOG (GNUNET_ERROR_TYPE_DEBUG, "Unexpected state %u\n", t->state);
   }
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  next call in %s\n",
+       GNUNET_STRINGS_relative_time_to_string (REKEY_WAIT, GNUNET_YES));
   t->rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_WAIT, &rekey_tunnel, t);
 }
 
@@ -837,6 +866,27 @@ rekey (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 }
 
 
+/**
+ * Called only on shutdown, destroy every tunnel.
+ *
+ * @param cls Closure (unused).
+ * @param key Current public key.
+ * @param value Value in the hash map (tunnel).
+ *
+ * @return #GNUNET_YES, so we should continue to iterate,
+ */
+static int
+destroy_iterator (void *cls,
+                const struct GNUNET_PeerIdentity *key,
+                void *value)
+{
+  struct MeshTunnel3 *t = value;
+
+  GMT_destroy (t);
+  return GNUNET_YES;
+}
+
+
 /**
  * Demultiplex data per channel and call appropriate channel handler.
  *
@@ -967,10 +1017,10 @@ handle_ch_create (struct MeshTunnel3 *t,
 
 
 /**
- * Handle channel NACK.
+ * Handle channel NACK: check correctness and call channel handler for NACKs.
  *
- * @param t Tunnel on which the data came.
- * @param msg Data message.
+ * @param t Tunnel on which the NACK came.
+ * @param msg NACK message.
  */
 static void
 handle_ch_nack (struct MeshTunnel3 *t,
@@ -989,7 +1039,7 @@ handle_ch_nack (struct MeshTunnel3 *t,
 
   /* Check channel */
   ch = GMT_get_channel (t, ntohl (msg->chid));
-  if (NULL != ch && ! GMT_is_loopback (t))
+  if (NULL == ch)
   {
     GNUNET_STATISTICS_update (stats, "# channel NACK on unknown channel",
                               1, GNUNET_NO);
@@ -1108,7 +1158,7 @@ handle_ephemeral (struct MeshTunnel3 *t,
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  our key was sent, send ping\n");
     send_ping (t);
-    t->state = MESH_TUNNEL3_PING_SENT;
+    t->state = MESH_TUNNEL3_REKEY;
   }
 }
 
@@ -1136,17 +1186,15 @@ handle_ping (struct MeshTunnel3 *t,
   t_decrypt (t, &res.target, &msg->target, ping_encryption_size (), msg->iv);
   if (0 != memcmp (&my_full_id, &res.target, sizeof (my_full_id)))
   {
-    GNUNET_break (0);
+    GNUNET_break_op (0);
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  e got %u\n", msg->nonce);
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  e towards %s\n", GNUNET_i2s (&msg->target));
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  using d %s\n", GNUNET_h2s (&t->d_key));
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  using iv %u\n", msg->iv);
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  got %u\n", res.nonce);
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  towards %s\n", GNUNET_i2s (&res.target));
     return;
   }
 
-  send_pong (t, res.iv);
+  send_pong (t, res.nonce);
 }
 
 
@@ -1175,8 +1223,8 @@ handle_pong (struct MeshTunnel3 *t,
   if (challenge != t->kx_ctx->challenge)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Wrong PONG challenge: %u. Expected: %u.\n",
-         challenge, t->kx_ctx->challenge);
+         "Wrong PONG challenge: %u (e: %u). Expected: %u.\n",
+         challenge, msg->nonce, t->kx_ctx->challenge);
     GNUNET_break_op (0);
     return;
   }
@@ -1370,6 +1418,7 @@ GMT_shutdown (void)
     GNUNET_SCHEDULER_cancel (rekey_task);
     rekey_task = GNUNET_SCHEDULER_NO_TASK;
   }
+  GNUNET_CONTAINER_multipeermap_iterate (tunnels, &destroy_iterator, NULL);
   GNUNET_CONTAINER_multipeermap_destroy (tunnels);
 }
 
@@ -1574,6 +1623,7 @@ GMT_destroy_empty (struct MeshTunnel3 *t)
 {
   struct MeshTConnection *iter;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel empty: destroying scheduled\n");
   for (iter = t->connection_head; NULL != iter; iter = iter->next)
   {
     GMC_send_destroy (iter->c);
@@ -1612,21 +1662,30 @@ GMT_destroy_if_empty (struct MeshTunnel3 *t)
 void
 GMT_destroy (struct MeshTunnel3 *t)
 {
-  struct MeshTConnection *iter;
-  struct MeshTConnection *next;
+  struct MeshTConnection *iter_c;
+  struct MeshTConnection *next_c;
+  struct MeshTChannel *iter_ch;
+  struct MeshTChannel *next_ch;
 
   if (NULL == t)
     return;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying tunnel %s\n", GMP_2s (t->peer));
 
-//   if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove (tunnels, &t->id, t))
-//     GNUNET_break (0);
+  GNUNET_break (GNUNET_YES ==
+                GNUNET_CONTAINER_multipeermap_remove (tunnels,
+                                                      GMP_get_id (t->peer), t));
 
-  for (iter = t->connection_head; NULL != iter; iter = next)
+  for (iter_c = t->connection_head; NULL != iter_c; iter_c = next_c)
   {
-    next = iter->next;
-    GMC_destroy (iter->c);
+    next_c = iter_c->next;
+    GMC_destroy (iter_c->c);
+  }
+  for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = next_ch)
+  {
+    next_ch = iter_ch->next;
+    GMCH_destroy (iter_ch->ch);
+    /* Should only happen on shutdown, but it's ok. */
   }
 
   GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO);
@@ -1859,12 +1918,6 @@ GMT_unchoke_channels (struct MeshTunnel3 *t)
   if (NULL != t->channel_head)
     LOG (GNUNET_ERROR_TYPE_DEBUG, " head ch: %p\n", t->channel_head->ch);
 
-  if (NULL == t)
-  {
-    GNUNET_break (0);
-    return;
-  }
-
   /* Get buffer space */
   buffer = GMT_get_connections_buffer (t);
   if (0 == buffer)
@@ -1912,7 +1965,7 @@ GMT_send_connection_acks (struct MeshTunnel3 *t)
   unsigned int cs;
   unsigned int buffer;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Tunnel send connection ACKs on %s\n",
        GMT_2s (t));
 
@@ -1956,6 +2009,47 @@ GMT_send_connection_acks (struct MeshTunnel3 *t)
 }
 
 
+/**
+ * Callback called when a queued message is sent.
+ *
+ * Calculates the average time and connection packet tracking.
+ *
+ * @param cls Closure (TunnelQueue handle).
+ * @param c Connection this message was on.
+ * @param type Type of message sent.
+ * @param fwd Was this a FWD going message?
+ * @param size Size of the message.
+ */
+static void
+message_sent (void *cls,
+              struct MeshConnection *c,
+              struct MeshConnectionQueue *q,
+              uint16_t type, int fwd, size_t size)
+{
+  struct MeshTunnel3Queue *qt = cls;
+
+  GNUNET_assert (NULL != qt->cont);
+  qt->cont (qt->cont_cls, GMC_get_tunnel (c), qt, type, size);
+  GNUNET_free (qt);
+}
+
+
+/**
+ * Cancel a previously sent message while it's in the queue.
+ *
+ * ONLY can be called before the continuation given to the send function
+ * is called. Once the continuation is called, the message is no longer in the
+ * queue.
+ *
+ * @param q Handle to the queue.
+ */
+void
+GMT_cancel (struct MeshTunnel3Queue *q)
+{
+  GMC_cancel (q->q);
+  /* message_sent() will be called and free q */
+}
+
 /**
  * Sends an already built message on a tunnel, encrypting it and
  * choosing the best connection.
@@ -1964,13 +2058,18 @@ GMT_send_connection_acks (struct MeshTunnel3 *t)
  * @param t Tunnel on which this message is transmitted.
  * @param ch Channel on which this message is transmitted.
  * @param fwd Is this a fwd message on @c ch?
+ * @param cont Continuation to call once message is really sent.
+ * @param cont_cls Closure for @c cont.
+ *
+ * @return Handle to cancel message. NULL if @c cont is NULL.
  */
-void
+struct MeshTunnel3Queue *
 GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
                            struct MeshTunnel3 *t,
-                           struct MeshChannel *ch,
-                           int fwd)
+                           struct MeshChannel *ch, int fwd,
+                           GMT_sent cont, void *cont_cls)
 {
+  struct MeshTunnel3Queue *q;
   struct MeshConnection *c;
   struct GNUNET_MESH_Encrypted *msg;
   size_t size = ntohs (message->size);
@@ -1982,7 +2081,8 @@ GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
   if (MESH_TUNNEL3_READY != t->state)
   {
     queue_data (t, ch, message);
-    return;
+    /* FIXME */
+    return NULL;
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GMT_2s (t));
 
@@ -1990,7 +2090,8 @@ GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  loopback!\n");
     handle_decrypted (t, message, fwd);
-    return;
+    /* FIXME: call cont? */
+    return NULL; /* Already delivered, cannot cancel */
   }
 
   iv = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
@@ -2003,12 +2104,13 @@ GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
   if (NULL == c)
   {
     GNUNET_break (GNUNET_YES == t->destroy);
-    return;
+    return NULL;
   }
   type = ntohs (message->type);
   switch (type)
   {
     case GNUNET_MESSAGE_TYPE_MESH_DATA:
+    case GNUNET_MESSAGE_TYPE_MESH_DATA_ACK:
     case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE:
     case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY:
     case GNUNET_MESSAGE_TYPE_MESH_CHANNEL_ACK:
@@ -2022,7 +2124,18 @@ GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
   }
 
   fwd = GMC_is_origin (c, GNUNET_YES);
-  GMC_send_prebuilt_message (&msg->header, c, fwd);
+
+  if (NULL == cont)
+  {
+    (void) GMC_send_prebuilt_message (&msg->header, c, fwd, NULL, NULL);
+    return NULL;
+  }
+  q = GNUNET_new (struct MeshTunnel3Queue); /* FIXME valgrind: leak*/
+  q->q = GMC_send_prebuilt_message (&msg->header, c, fwd, &message_sent, q);
+  q->cont = cont;
+  q->cont_cls = cont_cls;
+
+  return q;
 }
 
 /**
@@ -2115,4 +2228,4 @@ GMT_2s (const struct MeshTunnel3 *t)
     return "(NULL)";
 
   return GMP_2s (t->peer);
-}
\ No newline at end of file
+}