- add callback when we give a message to CORE
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh_peer.c
index 22887f0127b1b7ed16c0fff414a55387aa9c1ade..d700f3aa210e86db453d57e29cd201ee20980ae3 100644 (file)
@@ -23,6 +23,7 @@
 #include "gnunet_util_lib.h"
 
 #include "gnunet_core_service.h"
+#include "gnunet_statistics_service.h"
 
 #include "mesh_protocol_enc.h"
 
 #include "gnunet-service-mesh_dht.h"
 #include "gnunet-service-mesh_connection.h"
 #include "gnunet-service-mesh_local.h"
+#include "gnunet-service-mesh_tunnel.h"
 #include "mesh_path.h"
 
+#define LOG(level, ...) GNUNET_log_from (level,"mesh-p2p",__VA_ARGS__)
+
 /******************************************************************************/
 /********************************   STRUCTS  **********************************/
 /******************************************************************************/
 
+/**
+ * Struct containing info about a queued transmission to this peer
+ */
+struct MeshPeerQueue
+{
+    /**
+      * DLL next
+      */
+  struct MeshPeerQueue *next;
+
+    /**
+      * DLL previous
+      */
+  struct MeshPeerQueue *prev;
+
+    /**
+     * Peer this transmission is directed to.
+     */
+  struct MeshPeer *peer;
+
+    /**
+     * Connection this message belongs to.
+     */
+  struct MeshConnection *c;
+
+    /**
+     * Is FWD in c?
+     */
+  int fwd;
+
+    /**
+     * Channel this message belongs to, if known.
+     */
+  struct MeshChannel *ch;
+
+    /**
+     * Pointer to info stucture used as cls.
+     */
+  void *cls;
+
+    /**
+     * Type of message
+     */
+  uint16_t type;
+
+    /**
+     * Size of the message
+     */
+  size_t size;
+
+    /**
+     * Set when this message starts waiting for CORE.
+     */
+  struct GNUNET_TIME_Absolute start_waiting;
+
+    /**
+     * Function to call on sending.
+     */
+  GMP_sent callback;
+
+    /**
+     * Closure for callback.
+     */
+  void *callback_cls;
+};
+
 /**
  * Struct containing all information regarding a given peer
  */
@@ -102,6 +172,11 @@ struct MeshPeer
 /*******************************   GLOBALS  ***********************************/
 /******************************************************************************/
 
+/**
+ * Global handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
 /**
  * Peers known, indexed by PeerIdentity (MeshPeer).
  */
@@ -813,7 +888,7 @@ path_add_to_peers (struct MeshPeerPath *p, int confirmed)
   {
     struct MeshPeer *aux;
     struct MeshPeerPath *copy;
-    
+
     aux = peer_get_short (p->peers[i]);
     copy = path_duplicate (p);
     copy->length = i + 1;
@@ -968,7 +1043,7 @@ queue_send (void *cls, size_t size, void *buf)
   }
 
   if (0 < drop_percent &&
-      GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent)
+      GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent)
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
                 "Dropping message of type %s\n",
@@ -976,9 +1051,17 @@ queue_send (void *cls, size_t size, void *buf)
     data_size = 0;
   }
 
+  if (NULL != queue->callback)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "*   Calling callback\n");
+    queue->callback (queue->callback_cls,
+                    queue->c,
+                    GNUNET_TIME_absolute_get_duration (queue->start_waiting));
+  }
+
   /* Free queue, but cls was freed by send_core_* */
   ch = queue->ch;
-  queue_destroy (queue, GNUNET_NO);
+  GMP_queue_destroy (queue, GNUNET_NO);
 
   /* Send ACK if needed, after accounting for sent ID in fc->queue_n */
   switch (type)
@@ -1009,6 +1092,7 @@ queue_send (void *cls, size_t size, void *buf)
                                             queue->size,
                                             &queue_send,
                                             peer);
+      queue->start_waiting = GNUNET_TIME_absolute_get ();
     }
     else
     {
@@ -1184,12 +1268,15 @@ GMP_queue_destroy (struct MeshPeerQueue *queue, int clear_cls)
  * @param c Connection this message belongs to (cannot be NULL).
  * @param ch Channel this message belongs to, if applicable (otherwise NULL).
  * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!)
+ * @param callback Function to be called once CORE has taken the message.
+ * @param callback_cls Closure for @c callback.
  */
 void
-GMP_queue_add (void *cls, uint16_t type, size_t size, 
+GMP_queue_add (void *cls, uint16_t type, size_t size,
                struct MeshConnection *c,
                struct MeshChannel *ch,
-               int fwd)
+               int fwd,
+               GMP_sent callback, void *callback_cls)
 {
   struct MeshPeerQueue *queue;
   struct MeshFlowControl *fc;
@@ -1265,6 +1352,8 @@ GMP_queue_add (void *cls, uint16_t type, size_t size,
   queue->c = c;
   queue->ch = ch;
   queue->fwd = fwd;
+  queue->callback = callback;
+  queue->callback_cls = callback_cls;
   if (100 <= priority)
   {
     struct MeshPeerQueue *copy;
@@ -1276,7 +1365,7 @@ GMP_queue_add (void *cls, uint16_t type, size_t size,
       if (copy->type == type && copy->c == c && copy->fwd == fwd)
       {
         /* Example: also a FWD ACK for connection XYZ */
-        queue_destroy (copy, GNUNET_YES);
+        GMP_queue_destroy (copy, GNUNET_YES);
       }
     }
     GNUNET_CONTAINER_DLL_insert (peer->queue_head, peer->queue_tail, queue);
@@ -1303,6 +1392,7 @@ GMP_queue_add (void *cls, uint16_t type, size_t size,
                                            size,
                                            &queue_send,
                                            peer);
+    queue->start_waiting = GNUNET_TIME_absolute_get ();
   }
   else
   {
@@ -1380,6 +1470,12 @@ void
 GMP_shutdown (void)
 {
   GNUNET_CONTAINER_multipeermap_iterate (peers, &shutdown_tunnel, NULL);
+
+  if (core_handle != NULL)
+  {
+    GNUNET_CORE_disconnect (core_handle);
+    core_handle = NULL;
+  }
 }
 
 
@@ -1442,8 +1538,9 @@ GMP_connect (struct MeshPeer *peer)
   {
     GMD_search_stop (peer->search_h);
     peer->search_h = NULL;
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-                "  Stopping DHT GET for peer %s\n", peer2s (peer));
+    LOG (GNUNET_ERROR_TYPE_DEBUG, 
+         "  Stopping DHT GET for peer %s\n",
+         GMP_2s (peer));
   }
 
   if (NULL == peer->search_h)
@@ -1455,10 +1552,120 @@ GMP_connect (struct MeshPeer *peer)
                 "  Starting DHT GET for peer %s\n", peer2s (peer));
     peer->search_h = GMD_search (id, &search_handler, peer);
     if (MESH_TUNNEL_NEW == t->state)
-      tunnel_change_state (t, MESH_TUNNEL_SEARCHING);
+      GMT_change_state (t, MESH_TUNNEL_SEARCHING);
   }
 }
 
+
+/**
+ * Set tunnel.
+ *
+ * @param peer Peer.
+ * @param t Tunnel.
+ */
+void
+GMP_set_tunnel (struct MeshPeer *peer, struct MeshTunnel2 *t)
+{
+  peer->tunnel = t;
+}
+
+
+/**
+ * Chech whether there is a direct (core level)  connection to peer.
+ *
+ * @param peer Peer to check.
+ *
+ * @return GNUNET_YES if there is a direct connection.
+ */
+int
+GMP_is_neighbor (const struct MeshPeer *peer)
+{
+  struct MeshPeerPath *path;
+
+  if (NULL == peer->connections)
+    return GNUNET_NO;
+
+  for (path = peer->path_head; NULL != path; path = path->next)
+  {
+    if (3 > path->length)
+      return GNUNET_YES;
+  }
+
+  GNUNET_break (0); /* Is not a neighbor but connections is not NULL */
+  return GNUNET_NO;
+}
+
+
+/**
+ * Add a connection to a neighboring peer.
+ *
+ * Store that the peer is the first hop of the connection in one
+ * direction and that on peer disconnect the connection must be
+ * notified and destroyed, for it will no longer be valid.
+ *
+ * @param peer Peer to add connection to.
+ * @param c Connection to add.
+ *
+ * @return GNUNET_OK on success.
+ */
+int
+GMP_add_connection (struct MeshPeer *peer,
+                    const struct MeshConnection *c)
+{
+  if (NULL == peer->connections)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_CONTAINER_multihashmap_put (peer->connections,
+                                            GMC_get_id (c),
+                                            c,
+                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+}
+
+
+int
+GMP_remove_connection (struct MeshPeer *peer,
+                       const struct MeshConnection *c)
+{
+  if (NULL == peer || NULL == peer->connections)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_CONTAINER_multihashmap_remove (peer->connections,
+                                               GMC_get_id (c),
+                                               c);
+}
+
+/**
+ * Get the Full ID of a peer.
+ *
+ * @param peer Peer to get from.
+ *
+ * @return Full ID of peer.
+ */
+struct GNUNET_PeerIdentity *
+GMP_get_id (const struct MeshPeer *peer)
+{
+  return GNUNET_PEER_resolve2 (peer->id);
+}
+
+
+/**
+ * Get the Short ID of a peer.
+ *
+ * @param peer Peer to get from.
+ *
+ * @return Short ID of peer.
+ */
+GNUNET_PEER_Id
+GMP_get_short_id (const struct MeshPeer *peer)
+{
+  return peer->id;
+}
+
+
 /**
  * Get the static string for a peer ID.
  *