-only notify AFTER sending is really close to finished, not before
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh_tunnel.c
index d4ceead50a548422ae62746583826fa668acad0d..e30c8cd978dba1d9a2b55fe0fbcfc4ccdff2e7d3 100644 (file)
@@ -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  ***********************************/
 /******************************************************************************/
@@ -533,8 +555,8 @@ 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,
@@ -556,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);
   }
@@ -580,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)
@@ -589,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);
@@ -741,11 +764,13 @@ 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;
 
   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);
@@ -766,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);
 }
 
@@ -969,10 +996,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,
@@ -991,7 +1018,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);
@@ -1138,7 +1165,7 @@ 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, "  got %u\n", res.nonce);
@@ -1859,12 +1886,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)
@@ -1956,6 +1977,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 +2026,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 +2049,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 +2058,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,7 +2072,7 @@ 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)
@@ -2023,8 +2092,18 @@ GMT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
   }
 
   fwd = GMC_is_origin (c, GNUNET_YES);
-  /* FIXME allow channels to cancel */
-  GMC_send_prebuilt_message (&msg->header, c, fwd, NULL, NULL);
+
+  if (NULL == cont)
+  {
+    (void) GMC_send_prebuilt_message (&msg->header, c, fwd, NULL, NULL);
+    return NULL;
+  }
+  q = GNUNET_new (struct MeshTunnel3Queue);
+  q->q = GMC_send_prebuilt_message (&msg->header, c, fwd, &message_sent, q);
+  q->cont = cont;
+  q->cont_cls = cont_cls;
+
+  return q;
 }
 
 /**