-fix #4025
authorChristian Grothoff <christian@grothoff.org>
Wed, 28 Oct 2015 13:02:55 +0000 (13:02 +0000)
committerChristian Grothoff <christian@grothoff.org>
Wed, 28 Oct 2015 13:02:55 +0000 (13:02 +0000)
src/transport/gnunet-service-transport_clients.c
src/transport/gnunet-service-transport_clients.h
src/transport/gnunet-service-transport_neighbours.c

index 3a7f103375e99b1bb74f796d6ade52ae30420ffb..86c833c5bc41a4764097e6d2d8dbd0dd1047838a 100644 (file)
@@ -171,6 +171,40 @@ struct MonitoringClient
 };
 
 
+/**
+ * Closure for #handle_send_transmit_continuation()
+ */
+struct SendTransmitContinuationContext
+{
+  /**
+   * Client that made the request.
+   */
+  struct GNUNET_SERVER_Client *client;
+
+  /**
+   * Peer that was the target.
+   */
+  struct GNUNET_PeerIdentity target;
+
+  /**
+   * At what time did we receive the message?
+   */
+  struct GNUNET_TIME_Absolute send_time;
+
+  /**
+   * Unique ID, for logging.
+   */
+  unsigned long long uuid;
+
+  /**
+   * Set to #GNUNET_YES if the connection for @e target goes
+   * down and we thus must no longer send the
+   * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK message.
+   */
+  int down;
+};
+
+
 /**
  * Head of linked list of all clients to this service.
  */
@@ -181,6 +215,14 @@ static struct TransportClient *clients_head;
  */
 static struct TransportClient *clients_tail;
 
+/**
+ * Map of peer identities to active send transmit continuation
+ * contexts. Used to flag contexts as 'dead' when a connection goes
+ * down. Values are of type `struct SendTransmitContinuationContext
+ * *`.
+ */
+static struct GNUNET_CONTAINER_MultiPeerMap *active_stccs;
+
 /**
  * Head of linked list of all pending address iterations
  */
@@ -674,33 +716,6 @@ clients_handle_hello (void *cls,
 }
 
 
-/**
- * Closure for #handle_send_transmit_continuation()
- */
-struct SendTransmitContinuationContext
-{
-  /**
-   * Client that made the request.
-   */
-  struct GNUNET_SERVER_Client *client;
-
-  /**
-   * Peer that was the target.
-   */
-  struct GNUNET_PeerIdentity target;
-
-  /**
-   * At what time did we receive the message?
-   */
-  struct GNUNET_TIME_Absolute send_time;
-
-  /**
-   * Unique ID, for logging.
-   */
-  unsigned long long uuid;
-};
-
-
 /**
  * Function called after the transmission is done.  Notify the client that it is
  * OK to send the next message.
@@ -744,7 +759,7 @@ handle_send_transmit_continuation (void *cls,
                 success,
                 (NULL != addr) ? addr->transport_name : "%");
 
-  if (GST_neighbours_test_connected (&stcc->target))
+  if (GNUNET_NO == stcc->down)
   {
     /* Only send confirmation if we are still connected */
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -761,6 +776,10 @@ handle_send_transmit_continuation (void *cls,
                          GNUNET_NO);
   }
   GNUNET_SERVER_client_drop (stcc->client);
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multipeermap_remove (active_stccs,
+                                                       &stcc->target,
+                                                       stcc));
   GNUNET_free (stcc);
 }
 
@@ -842,6 +861,10 @@ clients_handle_send (void *cls,
   stcc->client = client;
   stcc->send_time = GNUNET_TIME_absolute_get ();
   stcc->uuid = uuid_gen++;
+  (void) GNUNET_CONTAINER_multipeermap_put (active_stccs,
+                                            &stcc->target,
+                                            stcc,
+                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
   GNUNET_SERVER_client_keep (client);
   GST_manipulation_send (&obm->peer,
                          obmm,
@@ -1548,6 +1571,8 @@ GST_clients_start (struct GNUNET_SERVER_Handle *server)
      sizeof (struct GNUNET_MessageHeader) },
     {NULL, NULL, 0, 0}
   };
+  active_stccs = GNUNET_CONTAINER_multipeermap_create (128,
+                                                       GNUNET_YES);
   peer_nc = GNUNET_SERVER_notification_context_create (server, 0);
   val_nc = GNUNET_SERVER_notification_context_create (server, 0);
   plugin_nc = GNUNET_SERVER_notification_context_create (server, 0);
@@ -1587,6 +1612,8 @@ GST_clients_stop ()
     GNUNET_SERVER_notification_context_destroy (plugin_nc);
     plugin_nc = NULL;
   }
+  GNUNET_CONTAINER_multipeermap_destroy (active_stccs);
+  active_stccs = NULL;
 }
 
 
@@ -1713,4 +1740,50 @@ GST_clients_broadcast_validation_notification (const struct GNUNET_PeerIdentity
 }
 
 
+/**
+ * Mark the peer as down so we don't call the continuation
+ * context in the future.
+ *
+ * @param cls NULL
+ * @param peer peer that got disconnected
+ * @param value a `struct SendTransmitContinuationContext` to mark
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static int
+mark_peer_down (void *cls,
+                const struct GNUNET_PeerIdentity *peer,
+                void *value)
+{
+  struct SendTransmitContinuationContext *stcc = value;
+
+  stcc->down = GNUNET_YES;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Notify all clients about a disconnect, and cancel
+ * pending SEND_OK messages for this peer.
+ *
+ * @param peer peer that disconnected
+ */
+void
+GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer)
+{
+  struct DisconnectInfoMessage disconnect_msg;
+
+  GNUNET_CONTAINER_multipeermap_get_multiple (active_stccs,
+                                              peer,
+                                              &mark_peer_down,
+                                              NULL);
+  disconnect_msg.header.size = htons (sizeof(struct DisconnectInfoMessage));
+  disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
+  disconnect_msg.reserved = htonl (0);
+  disconnect_msg.peer = *peer;
+  GST_clients_broadcast (&disconnect_msg.header,
+                         GNUNET_NO);
+
+}
+
+
 /* end of file gnunet-service-transport_clients.c */
index a7cfe781586d520e824edb6c37b23fd7a76b98fb..d46fd82ca38f4852d6e14c89542f0da3bf6c8153 100644 (file)
@@ -87,6 +87,16 @@ GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer,
                                          struct GNUNET_TIME_Absolute state_timeout);
 
 
+/**
+ * Notify all clients about a disconnect, and cancel
+ * pending SEND_OK messages for this peer.
+ *
+ * @param peer peer that disconnected
+ */
+void
+GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer);
+
+
 /**
  * Broadcast the new validation changes to all clients monitoring the peer.
  *
index 6664dd332969f009ea867777d4fa9226ee7398c1..9f4982b67248dc87cdbac6b5977ebaa02cd40a1c 100644 (file)
@@ -597,18 +597,11 @@ neighbours_connect_notification (struct NeighbourMapEntry *n)
 static void
 neighbours_disconnect_notification (struct NeighbourMapEntry *n)
 {
-  struct DisconnectInfoMessage disconnect_msg;
-
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Peer `%s' disconnected\n",
               GNUNET_i2s (&n->id));
   GST_manipulation_peer_disconnect (&n->id);
-  disconnect_msg.header.size = htons (sizeof(struct DisconnectInfoMessage));
-  disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
-  disconnect_msg.reserved = htonl (0);
-  disconnect_msg.peer = n->id;
-  GST_clients_broadcast (&disconnect_msg.header,
-                         GNUNET_NO);
+  GST_clients_broadcast_disconnect (&n->id);
 }