-fix (C) notices
[oweals/gnunet.git] / src / cadet / gnunet-service-cadet_peer.c
index 8827009e2908a9c2fd69f2ea7dce9a713915033b..b2dabf08723a19a75eea533ae07812b1a8a43723 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2013, 2015 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2013, 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
@@ -26,6 +26,7 @@
 #include "gnunet_util_lib.h"
 #include "gnunet_signatures.h"
 #include "gnunet_transport_service.h"
+#include "gnunet_ats_service.h"
 #include "gnunet_core_service.h"
 #include "gnunet_statistics_service.h"
 #include "cadet_protocol.h"
@@ -189,6 +190,18 @@ struct CadetPeer
    * Hello message.
    */
   struct GNUNET_HELLO_Message* hello;
+
+  /**
+   * Handle to us offering the HELLO to the transport.
+   */
+  struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
+
+  /**
+   * Handle to our ATS request asking ATS to suggest an address
+   * to TRANSPORT for this peer (to establish a direct link).
+   */
+  struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
+
 };
 
 
@@ -227,10 +240,15 @@ static unsigned long long max_peers;
 static unsigned long long drop_percent;
 
 /**
- * Handle to communicate with core.
+ * Handle to communicate with CORE.
  */
 static struct GNUNET_CORE_Handle *core_handle;
 
+/**
+ * Handle to communicate with ATS.
+ */
+static struct GNUNET_ATS_ConnectivityHandle *ats_ch;
+
 /**
  * Handle to try to start new connections.
  */
@@ -358,9 +376,8 @@ notify_broken (void *cls,
   struct CadetConnection *c = value;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Notifying %s due to %s\n",
-       GCC_2s (c),
-       GCP_2s (peer));
+       "Notifying %s due to %s disconnect\n",
+       GCC_2s (c), GCP_2s (peer));
   GCC_neighbor_disconnected (c, peer);
   return GNUNET_YES;
 }
@@ -404,7 +421,7 @@ static void
 core_connect (void *cls,
               const struct GNUNET_PeerIdentity *peer)
 {
-  struct CadetPeer *mp;
+  struct CadetPeer *neighbor;
   struct CadetPeerPath *path;
   char own_id[16];
 
@@ -413,8 +430,8 @@ core_connect (void *cls,
                    sizeof (own_id),
                    "%s",
                    GNUNET_i2s (&my_full_id));
-  mp = GCP_get (peer, GNUNET_YES);
-  if (myid == mp->id)
+  neighbor = GCP_get (peer, GNUNET_YES);
+  if (myid == neighbor->id)
   {
     LOG (GNUNET_ERROR_TYPE_INFO,
          "CONNECTED %s (self)\n",
@@ -428,22 +445,25 @@ core_connect (void *cls,
          own_id,
          GNUNET_i2s (peer));
     path = path_new (2);
-    path->peers[1] = mp->id;
-    GNUNET_PEER_change_rc (mp->id, 1);
+    path->peers[1] = neighbor->id;
+    GNUNET_PEER_change_rc (neighbor->id, 1);
   }
   path->peers[0] = myid;
   GNUNET_PEER_change_rc (myid, 1);
-  GCP_add_path (mp, path, GNUNET_YES);
+  GCP_add_path (neighbor, path, GNUNET_YES);
+
+  GNUNET_assert (NULL == neighbor->connections);
+  neighbor->connections = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
+  GNUNET_assert (NULL != neighbor->connections);
+
   GNUNET_STATISTICS_update (stats,
                             "# peers",
                             1,
                             GNUNET_NO);
-  GNUNET_assert (NULL == mp->connections);
-  mp->connections = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
 
-  if ( (NULL != GCP_get_tunnel (mp)) &&
+  if ( (NULL != GCP_get_tunnel (neighbor)) &&
        (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, peer)) )
-    GCP_connect (mp);
+    GCP_connect (neighbor);
   GCC_check_connections ();
 }
 
@@ -740,7 +760,9 @@ peer_destroy (struct CadetPeer *peer)
   while (NULL != p)
   {
     nextp = p->next;
-    GNUNET_CONTAINER_DLL_remove (peer->path_head, peer->path_tail, p);
+    GNUNET_CONTAINER_DLL_remove (peer->path_head,
+                                 peer->path_tail,
+                                 p);
     path_destroy (p);
     p = nextp;
   }
@@ -751,6 +773,18 @@ peer_destroy (struct CadetPeer *peer)
     GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (peer->connections));
     GNUNET_CONTAINER_multihashmap_destroy (peer->connections);
   }
+  if (NULL != peer->core_transmit)
+    GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit);
+  if (NULL != peer->hello_offer)
+  {
+    GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer);
+    peer->hello_offer = NULL;
+  }
+  if (NULL != peer->connectivity_suggestion)
+  {
+    GNUNET_ATS_connectivity_suggest_cancel (peer->connectivity_suggestion);
+    peer->connectivity_suggestion = NULL;
+  }
   GNUNET_free_non_null (peer->hello);
   GNUNET_free (peer);
   return GNUNET_OK;
@@ -773,7 +807,7 @@ shutdown_peer (void *cls,
 {
   struct CadetPeer *p = value;
   struct CadetTunnel *t = p->tunnel;
-
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "  shutting down %s\n", GCP_2s (p));
   if (NULL != t)
     GCT_destroy (t);
   p->tunnel = NULL;
@@ -1013,8 +1047,8 @@ peer_get_first_message (const struct CadetPeer *peer)
  * paths form the initial tunnel, which can be optimized later.
  * Called on each result obtained for the DHT search.
  *
- * @param cls closure
- * @param path
+ * @param cls Closure (peer towards a path has been found).
+ * @param path Path created from the DHT query. Will be freed afterwards.
  */
 static void
 search_handler (void *cls, const struct CadetPeerPath *path)
@@ -1134,6 +1168,27 @@ fill_buf (struct CadetPeerQueue *queue, void *buf, size_t size, uint32_t *pid)
 }
 
 
+/**
+ * Debug function should NEVER return true in production code, useful to
+ * simulate losses for testcases.
+ *
+ * @param q Queue handle with info about the message.
+ *
+ * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
+ */
+static int
+should_I_drop (struct CadetPeerQueue *q)
+{
+  if (0 == drop_percent)
+    return GNUNET_NO;
+
+  if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent)
+    return GNUNET_YES;
+
+  return GNUNET_NO;
+}
+
+
 /**
  * Core callback to write a queued packet to core buffer
  *
@@ -1215,7 +1270,7 @@ queue_send (void *cls, size_t size, void *buf)
   wait_s = GNUNET_STRINGS_relative_time_to_string (core_wait_time, GNUNET_YES);
   if (core_wait_time.rel_value_us >= 1000000)
   {
-    LOG (GNUNET_ERROR_TYPE_ERROR,
+    LOG (GNUNET_ERROR_TYPE_WARNING,
          " %s: core wait time %s (> 1 second) for %u bytes\n",
          GCP_2s (peer), wait_s, queue->size);
   }
@@ -1233,8 +1288,7 @@ queue_send (void *cls, size_t size, void *buf)
 
     msg_size = fill_buf (queue, (void *) dst, size, &pid);
 
-    if (0 < drop_percent &&
-        GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent)
+    if (should_I_drop (queue))
     {
       LOG (GNUNET_ERROR_TYPE_WARNING, "DD %s (%s %u) on conn %s %s\n",
            GC_m2s (queue->type), GC_m2s (queue->payload_type),
@@ -1244,7 +1298,7 @@ queue_send (void *cls, size_t size, void *buf)
     else
     {
       LOG (GNUNET_ERROR_TYPE_INFO,
-           ">>> %s (%s %4u) on conn %s (%p) %s (%u bytes), after %s\n",
+           ">>> %s (%s %4u) on conn %s (%p) %s [%5u], after %s\n",
            GC_m2s (queue->type), GC_m2s (queue->payload_type),
            queue->payload_id, GCC_2s (c), c,
            GC_f2s (queue->fwd), msg_size, wait_s);
@@ -1397,7 +1451,11 @@ GCP_queue_destroy (struct CadetPeerQueue *queue,
  * @param peer Peer towards which to queue the message.
  * @param cls Closure (@c type dependant). It will be used by queue_send to
  *            build the message to be sent if not already prebuilt.
- * @param type Type of the message, 0 for a raw message.
+ * @param type Type of the message.
+ * @param payload_type Type of the message's payload
+ *                     0 if the message is a retransmission (unknown payload).
+ *                     UINT16_MAX if the message does not have payload.
+ * @param payload_id ID of the payload (MID, ACK #, etc)
  * @param size Size of the message.
  * @param c Connection this message belongs to (can be NULL).
  * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!)
@@ -1534,7 +1592,7 @@ GCP_queue_cancel (struct CadetPeer *peer,
       LOG (GNUNET_ERROR_TYPE_DEBUG,
            "GMP queue cancel %s\n",
            GC_m2s (q->type));
-      GNUNET_break (GNUNET_NO == connection_destroyed);
+      GNUNET_assert (GNUNET_NO == connection_destroyed);
       if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY == q->type)
       {
         q->c = NULL;
@@ -1750,7 +1808,7 @@ GCP_init (const struct GNUNET_CONFIGURATION_Handle *c)
     LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
     LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
   }
-
+  ats_ch = GNUNET_ATS_connectivity_init (c);
   core_handle = GNUNET_CORE_connect (c, /* Main configuration */
                                      NULL,      /* Closure passed to CADET functions */
                                      &core_init,        /* Call core_init once connected */
@@ -1795,6 +1853,8 @@ GCP_init (const struct GNUNET_CONFIGURATION_Handle *c)
 void
 GCP_shutdown (void)
 {
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Shutting down peer subsystem\n");
   in_shutdown = GNUNET_YES;
   GNUNET_CONTAINER_multipeermap_iterate (peers,
                                          &shutdown_peer,
@@ -1809,6 +1869,11 @@ GCP_shutdown (void)
     GNUNET_TRANSPORT_disconnect (transport_handle);
     transport_handle = NULL;
   }
+  if (NULL != ats_ch)
+  {
+    GNUNET_ATS_connectivity_done (ats_ch);
+    ats_ch = NULL;
+  }
   GNUNET_PEER_change_rc (myid, -1);
   GNUNET_CONTAINER_multipeermap_destroy (peers);
   peers = NULL;
@@ -1871,21 +1936,19 @@ GCP_get_short (const GNUNET_PEER_Id peer, int create)
 
 
 /**
- * Try to connect to a peer on transport level.
+ * Function called once #GNUNET_TRANSPORT_offer_hello() is done.
+ * Marks the operation as finished.
  *
- * @param cls Closure (peer).
+ * @param cls Closure (our `struct CadetPeer`).
  * @param tc TaskContext.
  */
 static void
-try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+hello_offer_done (void *cls,
+                  const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct CadetPeer *peer = cls;
 
-  if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
-    return;
-
-  GNUNET_TRANSPORT_try_connect (transport_handle,
-                                GNUNET_PEER_resolve2 (peer->id), NULL, NULL);
+  peer->hello_offer = NULL;
 }
 
 
@@ -1900,13 +1963,14 @@ void
 GCP_connect (struct CadetPeer *peer)
 {
   struct CadetTunnel *t;
-  struct CadetPeerPath *p;
+  struct CadetPeerPath *path;
   struct CadetConnection *c;
   int rerun_search;
 
   GCC_check_connections ();
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "peer_connect towards %s\n", GCP_2s (peer));
-
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "peer_connect towards %s\n",
+       GCP_2s (peer));
   /* If we have a current hello, try to connect using it. */
   GCP_try_connect (peer);
 
@@ -1917,16 +1981,16 @@ GCP_connect (struct CadetPeer *peer)
   if (NULL != peer->path_head)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "  some path exists\n");
-    p = peer_get_best_path (peer);
-    if (NULL != p)
+    path = peer_get_best_path (peer);
+    if (NULL != path)
     {
       char *s;
 
-      s = path_2s (p);
+      s = path_2s (path);
       LOG (GNUNET_ERROR_TYPE_DEBUG, "  path to use: %s\n", s);
       GNUNET_free (s);
 
-      c = GCT_use_path (t, p);
+      c = GCT_use_path (t, path);
       if (NULL == c)
       {
         /* This case can happen when the path includes a first hop that is
@@ -1935,7 +1999,7 @@ GCP_connect (struct CadetPeer *peer)
          * This happens quite often during testing when running cadet
          * under valgrind: core connect notifications come very late
          * and the DHT result has already come and created a valid
-         * path.  In this case, the peer->connections_{pred,succ}
+         * path.  In this case, the peer->connections
          * hashmaps will be NULL and tunnel_use_path will not be able
          * to create a connection from that path.
          *
@@ -1999,6 +2063,7 @@ GCP_is_neighbor (const struct CadetPeer *peer)
   }
 
   /* Is not a neighbor but connections is not NULL, probably disconnecting */
+  GNUNET_break (0);
   return GNUNET_NO;
 }
 
@@ -2062,7 +2127,7 @@ GCP_add_connection (struct CadetPeer *peer,
  * is the shortest.
  *
  * @param peer Destination peer to add the path to.
- * @param path New path to add. Last peer must be the peer in arg 1.
+ * @param path New path to add. Last peer must be @c peer.
  *             Path will be either used of freed if already known.
  * @param trusted Do we trust that this path is real?
  *
@@ -2150,7 +2215,8 @@ GCP_add_path (struct CadetPeer *peer,
 
 finish:
   if (NULL != peer->tunnel
-      && CONNECTIONS_PER_TUNNEL > GCT_count_connections (peer->tunnel))
+      && CONNECTIONS_PER_TUNNEL > GCT_count_connections (peer->tunnel)
+      && 2 < path->length) /* Direct paths are handled by core_connect */
   {
     GCP_connect (peer);
   }
@@ -2201,13 +2267,13 @@ GCP_add_path_to_all (const struct CadetPeerPath *p, int confirmed)
   for (i = 0; i < p->length && p->peers[i] != myid; i++) /* skip'em */ ;
   for (i++; i < p->length; i++)
   {
-    struct CadetPeer *aux;
+    struct CadetPeer *peer;
     struct CadetPeerPath *copy;
 
-    aux = GCP_get_short (p->peers[i], GNUNET_YES);
+    peer = GCP_get_short (p->peers[i], GNUNET_YES);
     copy = path_duplicate (p);
     copy->length = i + 1;
-    GCP_add_path (aux, copy, p->length < 3 ? GNUNET_NO : confirmed);
+    GCP_add_path (peer, copy, 3 > p->length ? GNUNET_NO : confirmed);
   }
   GCC_check_connections ();
 }
@@ -2501,15 +2567,27 @@ GCP_try_connect (struct CadetPeer *peer)
   if (NULL == transport_handle)
     return;
   GCC_check_connections ();
+  if (GNUNET_YES == GCP_is_neighbor (peer))
+    return;
   hello = GCP_get_hello (peer);
   if (NULL == hello)
     return;
 
   mh = GNUNET_HELLO_get_header (hello);
-  GNUNET_TRANSPORT_offer_hello (transport_handle,
-                                mh,
-                                &try_connect,
-                                peer);
+  if (NULL != peer->hello_offer)
+  {
+    GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer);
+    peer->hello_offer = NULL;
+  }
+  peer->hello_offer = GNUNET_TRANSPORT_offer_hello (transport_handle,
+                                                    mh,
+                                                    &hello_offer_done,
+                                                    peer);
+  if (NULL == peer->connectivity_suggestion)
+    peer->connectivity_suggestion
+      = GNUNET_ATS_connectivity_suggest (ats_ch,
+                                         GNUNET_PEER_resolve2 (peer->id),
+                                         1 /* strength */);
   GCC_check_connections ();
 }
 
@@ -2524,8 +2602,8 @@ GCP_try_connect (struct CadetPeer *peer)
  */
 void
 GCP_notify_broken_link (struct CadetPeer *peer,
-                        struct GNUNET_PeerIdentity *peer1,
-                        struct GNUNET_PeerIdentity *peer2)
+                        const struct GNUNET_PeerIdentity *peer1,
+                        const struct GNUNET_PeerIdentity *peer2)
 {
   struct CadetPeerPath *iter;
   struct CadetPeerPath *next;