allow empty/NULL context message
[oweals/gnunet.git] / src / transport / gnunet-service-transport_clients.c
index f00f7c93f403e4c44c59a4cbe5fa86ee220e8078..953ea54e51c76b5feca8cdc493c1aaf921e70458 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2010-2015 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2010-2015 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -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,23 +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;
-};
-
-
 /**
  * Function called after the transmission is done.  Notify the client that it is
  * OK to send the next message.
@@ -708,17 +733,53 @@ handle_send_transmit_continuation (void *cls,
 {
   struct SendTransmitContinuationContext *stcc = cls;
   struct SendOkMessage send_ok_msg;
+  struct GNUNET_TIME_Relative delay;
+  const struct GNUNET_HELLO_Address *addr;
 
-  send_ok_msg.header.size = htons (sizeof (send_ok_msg));
-  send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
-  send_ok_msg.bytes_msg = htonl (bytes_payload);
-  send_ok_msg.bytes_physical = htonl (bytes_on_wire);
-  send_ok_msg.success = htonl (success);
-  send_ok_msg.peer = stcc->target;
-  GST_clients_unicast (stcc->client,
-                       &send_ok_msg.header,
-                       GNUNET_NO);
+  delay = GNUNET_TIME_absolute_get_duration (stcc->send_time);
+  addr = GST_neighbour_get_current_address (&stcc->target);
+  if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "It took us %s to send %u/%u bytes to %s (%d, %s)\n",
+                GNUNET_STRINGS_relative_time_to_string (delay,
+                                                        GNUNET_YES),
+                (unsigned int) bytes_payload,
+                (unsigned int) bytes_on_wire,
+                GNUNET_i2s (&stcc->target),
+                success,
+                (NULL != addr) ? addr->transport_name : "%");
+  else
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "It took us %s to send %u/%u bytes to %s (%d, %s)\n",
+                GNUNET_STRINGS_relative_time_to_string (delay,
+                                                        GNUNET_YES),
+                (unsigned int) bytes_payload,
+                (unsigned int) bytes_on_wire,
+                GNUNET_i2s (&stcc->target),
+                success,
+                (NULL != addr) ? addr->transport_name : "%");
+
+  if (GNUNET_NO == stcc->down)
+  {
+    /* Only send confirmation if we are still connected */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Sending SEND_OK for transmission request %llu\n",
+                stcc->uuid);
+    send_ok_msg.header.size = htons (sizeof (send_ok_msg));
+    send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
+    send_ok_msg.bytes_msg = htonl (bytes_payload);
+    send_ok_msg.bytes_physical = htonl (bytes_on_wire);
+    send_ok_msg.success = htonl (success);
+    send_ok_msg.peer = stcc->target;
+    GST_clients_unicast (stcc->client,
+                         &send_ok_msg.header,
+                         GNUNET_NO);
+  }
   GNUNET_SERVER_client_drop (stcc->client);
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multipeermap_remove (active_stccs,
+                                                       &stcc->target,
+                                                       stcc));
   GNUNET_free (stcc);
 }
 
@@ -735,6 +796,7 @@ clients_handle_send (void *cls,
                      struct GNUNET_SERVER_Client *client,
                      const struct GNUNET_MessageHeader *message)
 {
+  static unsigned long long uuid_gen;
   const struct OutboundMessage *obm;
   const struct GNUNET_MessageHeader *obmm;
   struct SendTransmitContinuationContext *stcc;
@@ -787,7 +849,8 @@ clients_handle_send (void *cls,
     return;
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received SEND request for `%s' and first message of type %u and total size %u\n",
+              "Received SEND request %llu for `%s' and first message of type %u and total size %u\n",
+              uuid_gen,
               GNUNET_i2s (&obm->peer),
               ntohs (obmm->type),
               msize);
@@ -796,6 +859,12 @@ clients_handle_send (void *cls,
   stcc = GNUNET_new (struct SendTransmitContinuationContext);
   stcc->target = obm->peer;
   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,
@@ -806,79 +875,6 @@ clients_handle_send (void *cls,
 }
 
 
-/**
- * Handle request connect message
- *
- * @param cls closure (always NULL)
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-clients_handle_request_connect (void *cls,
-                                struct GNUNET_SERVER_Client *client,
-                                const struct GNUNET_MessageHeader *message)
-{
-  const struct TransportRequestConnectMessage *trcm;
-
-  trcm = (const struct TransportRequestConnectMessage *) message;
-  GNUNET_break (0 == ntohl (trcm->reserved));
-  GNUNET_STATISTICS_update (GST_stats,
-                            gettext_noop
-                            ("# REQUEST CONNECT messages received"), 1,
-                            GNUNET_NO);
-  if (0 == memcmp (&trcm->peer,
-                   &GST_my_identity,
-                   sizeof (struct GNUNET_PeerIdentity)))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client,
-                                GNUNET_OK);
-    return;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received a request connect message for peer `%s'\n",
-              GNUNET_i2s (&trcm->peer));
-  GST_neighbours_try_connect (&trcm->peer);
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Handle request disconnect message
- *
- * @param cls closure (always NULL)
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-clients_handle_request_disconnect (void *cls,
-                                   struct GNUNET_SERVER_Client *client,
-                                   const struct GNUNET_MessageHeader *message)
-{
-  const struct TransportRequestDisconnectMessage *trdm;
-
-  trdm = (const struct TransportRequestDisconnectMessage *) message;
-  GNUNET_break (0 == ntohl (trdm->reserved));
-  GNUNET_STATISTICS_update (GST_stats,
-                            gettext_noop
-                            ("# REQUEST DISCONNECT messages received"), 1,
-                            GNUNET_NO);
-  if (0 == memcmp (&trdm->peer,
-                   &GST_my_identity,
-                   sizeof (struct GNUNET_PeerIdentity)))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received a request disconnect message for peer `%s'\n",
-              GNUNET_i2s (&trdm->peer));
-  (void) GST_neighbours_force_disconnect (&trdm->peer);
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
 /**
  * Take the given address and append it to the set of results sent back to
  * the client.  This function may be called serveral times for a single
@@ -1395,7 +1391,7 @@ clients_handle_monitor_validation (void *cls,
  */
 static void
 plugin_session_info_cb (void *cls,
-                       struct Session *session,
+                       struct GNUNET_ATS_Session *session,
                        const struct GNUNET_TRANSPORT_SessionInfo *info)
 {
   struct TransportPluginMonitorMessage *msg;
@@ -1513,12 +1509,6 @@ GST_clients_start (struct GNUNET_SERVER_Handle *server)
      GNUNET_MESSAGE_TYPE_HELLO, 0},
     {&clients_handle_send, NULL,
      GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
-    {&clients_handle_request_connect, NULL,
-     GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT,
-     sizeof (struct TransportRequestConnectMessage)},
-    {&clients_handle_request_disconnect, NULL,
-     GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_DISCONNECT,
-     sizeof (struct TransportRequestDisconnectMessage)},
     {&clients_handle_address_to_string, NULL,
      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING, 0},
     {&clients_handle_monitor_peers, NULL,
@@ -1541,6 +1531,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);
@@ -1580,6 +1572,8 @@ GST_clients_stop ()
     GNUNET_SERVER_notification_context_destroy (plugin_nc);
     plugin_nc = NULL;
   }
+  GNUNET_CONTAINER_multipeermap_destroy (active_stccs);
+  active_stccs = NULL;
 }
 
 
@@ -1706,4 +1700,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 */