gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnunet] branch master updated: more work on peers, paths a


From: gnunet
Subject: [GNUnet-SVN] [gnunet] branch master updated: more work on peers, paths and tunnels
Date: Mon, 16 Jan 2017 18:13:28 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository gnunet.

The following commit(s) were added to refs/heads/master by this push:
     new d55c86988 more work on peers, paths and tunnels
d55c86988 is described below

commit d55c8698825605630770157c786e064af0c20467
Author: Christian Grothoff <address@hidden>
AuthorDate: Mon Jan 16 18:13:09 2017 +0100

    more work on peers, paths and tunnels
---
 src/cadet/gnunet-service-cadet-new.c            |  16 +-
 src/cadet/gnunet-service-cadet-new.h            |  26 ++-
 src/cadet/gnunet-service-cadet-new_connection.c | 136 +++++++++++++
 src/cadet/gnunet-service-cadet-new_connection.h |  58 ++++++
 src/cadet/gnunet-service-cadet-new_paths.c      | 174 +++++++++++++++--
 src/cadet/gnunet-service-cadet-new_paths.h      |  75 ++++++-
 src/cadet/gnunet-service-cadet-new_peer.c       | 105 +++++++---
 src/cadet/gnunet-service-cadet-new_peer.h       |  51 +++--
 src/cadet/gnunet-service-cadet-new_tunnels.c    | 248 ++++++++++++++++++++++--
 src/cadet/gnunet-service-cadet-new_tunnels.h    |  15 ++
 10 files changed, 797 insertions(+), 107 deletions(-)

diff --git a/src/cadet/gnunet-service-cadet-new.c 
b/src/cadet/gnunet-service-cadet-new.c
index f367c4c73..74296a27e 100644
--- a/src/cadet/gnunet-service-cadet-new.c
+++ b/src/cadet/gnunet-service-cadet-new.c
@@ -271,8 +271,7 @@ GSC_bind (struct CadetClient *c,
   msg->channel_id = lid;
   msg->port = *port;
   msg->opt = htonl (options);
-  GCP_id (dest,
-          &msg->peer);
+  msg->peer = *GCP_get_id (dest);
   GSC_send_to_client (c,
                       env);
   return lid;
@@ -732,15 +731,15 @@ handle_get_peers (void *cls,
  * Message contains blocks of peers, first not included.
  *
  * @param cls message queue for transmission
- * @param peer Peer this path is towards.
  * @param path Path itself
+ * @param off offset of the peer on @a path
  * @return #GNUNET_YES if should keep iterating.
  *         #GNUNET_NO otherwise.
  */
 static int
 path_info_iterator (void *cls,
-                    struct CadetPeer *peer,
-                    struct CadetPeerPath *path)
+                    struct CadetPeerPath *path,
+                    unsigned int off)
 {
   struct GNUNET_MQ_Handle *mq = cls;
   struct GNUNET_MQ_Envelope *env;
@@ -767,10 +766,9 @@ path_info_iterator (void *cls,
   /* Don't copy first peer.  First peer is always the local one.  Last
    * peer is always the destination (leave as 0, EOL).
    */
-  for (i = 0; i < path_length - 1; i++)
-    GCPP_get_pid_at_offset (path,
-                            i + 1,
-                            &id[i]);
+  for (i = 0; i < off; i++)
+    id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path,
+                                                  i + 1));
   GNUNET_MQ_send (mq,
                   env);
   return GNUNET_YES;
diff --git a/src/cadet/gnunet-service-cadet-new.h 
b/src/cadet/gnunet-service-cadet-new.h
index 2b68862b7..9521b6363 100644
--- a/src/cadet/gnunet-service-cadet-new.h
+++ b/src/cadet/gnunet-service-cadet-new.h
@@ -31,27 +31,32 @@
 #include "gnunet_util_lib.h"
 
 /**
- * A client to the CADET service.
+ * A client to the CADET service.  Each client gets a unique handle.
  */
 struct CadetClient;
 
 /**
- * A peer in the GNUnet network.
+ * A peer in the GNUnet network.  Each peer we care about must have one 
globally
+ * unique such handle within this process.
  */
 struct CadetPeer;
 
 /**
- * Tunnel from us to another peer.
+ * Tunnel from us to another peer.  There can only be at most one
+ * tunnel per peer.
  */
 struct CadetTunnel;
 
 /**
- * Entry in the message queue of a `struct CadetTunnel`
+ * Entry in the message queue of a `struct CadetTunnel`.
  */
 struct CadetTunnelQueueEntry;
 
 /**
- * A path of peer in the GNUnet network.
+ * A path of peer in the GNUnet network.  There must only be at most
+ * once such path.  Paths may share disjoint prefixes, but must all
+ * end at a unique suffix.  Paths must also not be proper subsets of
+ * other existing paths.
  */
 struct CadetPeerPath;
 
@@ -81,6 +86,11 @@ struct CadetPeerPathEntry
   struct CadetPeerPath *path;
 
   /**
+   * Connection using this path, or NULL for none.
+   */
+  struct CadetConnection *cc;
+
+  /**
    * Path's historic score up to this point.  Basically, how often did
    * we succeed or fail to use the path up to this entry in a
    * connection.  Positive values indicate good experiences, negative
@@ -93,12 +103,14 @@ struct CadetPeerPathEntry
 
 
 /**
- * Active path through the network (used by a tunnel).
+ * Active path through the network (used by a tunnel).  There may
+ * be at most one connection per path.
  */
 struct CadetConnection;
 
 /**
- * Logical end-to-end conenction between clients.
+ * Logical end-to-end conenction between clients.  There can be
+ * any number of channels between clients.
  */
 struct CadetChannel;
 
diff --git a/src/cadet/gnunet-service-cadet-new_connection.c 
b/src/cadet/gnunet-service-cadet-new_connection.c
index b24e4bd49..ea0b2c6e5 100644
--- a/src/cadet/gnunet-service-cadet-new_connection.c
+++ b/src/cadet/gnunet-service-cadet-new_connection.c
@@ -26,10 +26,146 @@
  * @author Christian Grothoff
  */
 #include "platform.h"
+#include "gnunet-service-cadet-new_channel.h"
+#include "gnunet-service-cadet-new_paths.h"
+#include "gnunet-service-cadet-new_peer.h"
 #include "gnunet-service-cadet-new_connection.h"
 
 
 /**
+ * Low-level connection to a destination.
+ */
+struct CadetConnection
+{
+  /**
+   * To which peer does this connection go?
+   */
+  struct CadetPeer *destination;
+
+  /**
+   * Path we are using to our destination.
+   */
+  struct CadetPeerPath *path;
+
+  /**
+   * Function to call once we are ready to transmit.
+   */
+  GNUNET_SCHEDULER_TaskCallback ready_cb;
+
+  /**
+   * Closure for @e ready_cb.
+   */
+  void *ready_cb_cls;
+
+  /**
+   * Offset of our @e destination in @e path.
+   */
+  unsigned int off;
+
+};
+
+
+/**
+ * Is the given connection currently ready for transmission?
+ *
+ * @param cc connection to transmit on
+ * @return #GNUNET_YES if we could transmit
+ */
+int
+GCC_is_ready (struct CadetConnection *cc)
+{
+  GNUNET_break (0);
+  return GNUNET_NO;
+}
+
+
+/**
+ * Destroy a connection.
+ *
+ * @param cc connection to destroy
+ */
+void
+GCC_destroy (struct CadetConnection *cc)
+{
+  GCPP_del_connection (cc->path,
+                       cc->off,
+                       cc);
+  GNUNET_assert (0); // FIXME: incomplete implementation!
+  GNUNET_free (cc);
+}
+
+
+/**
+ * Create a connection to @a destination via @a path and
+ * notify @a cb whenever we are ready for more data.
+ *
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param ready_cb function to call when ready to transmit
+ * @param ready_cb_cls closure for @a cb
+ */
+struct CadetConnection *
+GCC_create (struct CadetPeer *destination,
+            struct CadetPeerPath *path,
+            GNUNET_SCHEDULER_TaskCallback ready_cb,
+            void *ready_cb_cls)
+{
+  struct CadetConnection *cc;
+  unsigned int off;
+
+  off = GCPP_find_peer (path,
+                        destination);
+  GNUNET_assert (UINT_MAX > off);
+
+  GNUNET_assert (0); // fIXME: unfinished
+
+  cc = GNUNET_new (struct CadetConnection);
+  cc->path = path;
+  cc->off = off;
+  GCPP_add_connection (path,
+                       off,
+                       cc);
+  for (unsigned int i=0;i<off;i++)
+  {
+    // FIXME: remember existence of this connection with
+    // ALL peers on the path!
+    // (and remove on destruction of connection!)
+  }
+  return cc;
+}
+
+
+/**
+ * Transmit message @a msg via connection @a cc.  Must only be called
+ * (once) after the connection has signalled that it is ready via the
+ * `ready_cb`.  Clients can also use #GCC_is_ready() to check if the
+ * connection is right now ready for transmission.
+ *
+ * @param cc connection identification
+ * @param msg message to transmit
+ */
+void
+GCC_transmit (struct CadetConnection *cc,
+              const struct GNUNET_MessageHeader *msg)
+{
+  GNUNET_assert (0); // FIXME
+}
+
+
+/**
+ * Obtain the path used by this connection.
+ *
+ * @param cc connection
+ * @return path to @a cc
+ */
+struct CadetPeerPath *
+GCC_get_path (struct CadetConnection *cc)
+{
+  return cc->path;
+}
+
+
+/**
  * Obtain unique ID for the connection.
  *
  * @param cc connection.
diff --git a/src/cadet/gnunet-service-cadet-new_connection.h 
b/src/cadet/gnunet-service-cadet-new_connection.h
index 7745e4fec..c11e34024 100644
--- a/src/cadet/gnunet-service-cadet-new_connection.h
+++ b/src/cadet/gnunet-service-cadet-new_connection.h
@@ -33,6 +33,64 @@
 #include "gnunet-service-cadet-new_peer.h"
 
 
+/**
+ * Is the given connection currently ready for transmission?
+ *
+ * @param cc connection to transmit on
+ * @return #GNUNET_YES if we could transmit
+ */
+int
+GCC_is_ready (struct CadetConnection *cc);
+
+
+/**
+ * Destroy a connection.
+ *
+ * @param cc connection to destroy
+ */
+void
+GCC_destroy (struct CadetConnection *cc);
+
+
+/**
+ * Create a connection to @a destination via @a path and
+ * notify @a cb whenever we are ready for more data.
+ *
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param ready_cb function to call when ready to transmit
+ * @param ready_cb_cls closure for @a cb
+ */
+struct CadetConnection *
+GCC_create (struct CadetPeer *destination,
+            struct CadetPeerPath *path,
+            GNUNET_SCHEDULER_TaskCallback ready_cb,
+            void *ready_cb_cls);
+
+
+/**
+ * Transmit message @a msg via connection @a cc.  Must only be called
+ * (once) after the connection has signalled that it is ready via the
+ * `ready_cb`.  Clients can also use #GCC_is_ready() to check if the
+ * connection is right now ready for transmission.
+ *
+ * @param cc connection identification
+ * @param msg message to transmit
+ */
+void
+GCC_transmit (struct CadetConnection *cc,
+              const struct GNUNET_MessageHeader *msg);
+
+
+/**
+ * Obtain the path used by this connection.
+ *
+ * @param cc connection
+ * @return path to @a cc
+ */
+struct CadetPeerPath *
+GCC_get_path (struct CadetConnection *cc);
+
 
 /**
  * Obtain unique ID for the connection.
diff --git a/src/cadet/gnunet-service-cadet-new_paths.c 
b/src/cadet/gnunet-service-cadet-new_paths.c
index 663ce317f..005d8e807 100644
--- a/src/cadet/gnunet-service-cadet-new_paths.c
+++ b/src/cadet/gnunet-service-cadet-new_paths.c
@@ -86,7 +86,7 @@ struct CadetPeerPath
 GNUNET_CONTAINER_HeapCostType
 GCPP_get_desirability (const struct CadetPeerPath *path)
 {
-  GNUNET_assert (0);
+  GNUNET_break (0);
   return 0;
 }
 
@@ -98,16 +98,100 @@ GCPP_get_desirability (const struct CadetPeerPath *path)
  * the path desirable).
  *
  * @param path the path that is being released
- * @param cp original final destination of @a path
  * @param node entry in the heap of @a cp where this path is anchored
  *             should be used for updates to the desirability of this path
  */
 void
 GCPP_acquire (struct CadetPeerPath *path,
-              struct CadetPeer *cp,
               struct GNUNET_CONTAINER_HeapNode *node)
 {
-  GNUNET_assert (0);
+  GNUNET_assert (NULL == path->hn);
+  path->hn = node;
+}
+
+
+/**
+ * Return connection to @a destination using @a path, or return
+ * NULL if no such connection exists.
+ *
+ * @param path path to traverse
+ * @param destination destination node to get to, must be on path
+ * @param off offset of @a destination on @a path
+ * @return NULL if @a create is NO and we have no existing connection
+ *         otherwise connection from us to @a destination via @a path
+ */
+struct CadetConnection *
+GCPP_get_connection (struct CadetPeerPath *path,
+                     struct CadetPeer *destination,
+                     unsigned int off)
+{
+  struct CadetPeerPathEntry *entry;
+
+  GNUNET_assert (off < path->entries_length);
+  entry = &path->entries[off];
+  GNUNET_assert (entry->peer == destination);
+  return entry->cc;
+}
+
+
+/**
+ * Notify @a path that it is used for connection @a cc
+ * which ends at the path's offset @a off.
+ *
+ * @param path the path to remember the @a cc
+ * @param off the offset where the @a cc ends
+ * @param cc the connection to remember
+ */
+void
+GCPP_add_connection (struct CadetPeerPath *path,
+                     unsigned int off,
+                     struct CadetConnection *cc)
+{
+  struct CadetPeerPathEntry *entry;
+
+  GNUNET_assert (off < path->entries_length);
+  entry = &path->entries[off];
+  GNUNET_assert (NULL == entry->cc);
+  entry->cc = cc;
+}
+
+
+
+/**
+ * Notify @a path that it is no longer used for connection @a cc which
+ * ended at the path's offset @a off.
+ *
+ * @param path the path to forget the @a cc
+ * @param off the offset where the @a cc ended
+ * @param cc the connection to forget
+ */
+void
+GCPP_del_connection (struct CadetPeerPath *path,
+                     unsigned int off,
+                     struct CadetConnection *cc)
+{
+  struct CadetPeerPathEntry *entry;
+
+  GNUNET_assert (off < path->entries_length);
+  entry = &path->entries[off];
+  GNUNET_assert (cc == entry->cc);
+  entry->cc = NULL;
+}
+
+
+/**
+ * This path is no longer needed, free resources.
+ *
+ * @param path path resources to free
+ */
+static void
+path_destroy (struct CadetPeerPath *path)
+{
+  GNUNET_assert (0 ==
+                 GNUNET_CONTAINER_multipeermap_size (path->connections));
+  GNUNET_CONTAINER_multipeermap_destroy (path->connections);
+  GNUNET_free (path->entries);
+  GNUNET_free (path);
 }
 
 
@@ -121,7 +205,34 @@ GCPP_acquire (struct CadetPeerPath *path,
 void
 GCPP_release (struct CadetPeerPath *path)
 {
-  GNUNET_assert (0);
+  struct CadetPeerPathEntry *entry;
+
+  path->hn = NULL;
+  entry = &path->entries[path->entries_length - 1];
+  while (1)
+  {
+    /* cut 'off' end of path, verifying it is not in use */
+    GNUNET_assert (NULL ==
+                   GNUNET_CONTAINER_multipeermap_get (path->connections,
+                                                      GCP_get_id 
(entry->peer)));
+    GCP_path_entry_remove (entry->peer,
+                           entry,
+                           path->entries_length - 1);
+    path->entries_length--; /* We don't bother shrinking the 'entries' array,
+                               as it's probably not worth it. */
+    if (0 == path->entries_length)
+      break; /* the end */
+
+    /* see if new peer at the end likes this path any better */
+    entry = &path->entries[path->entries_length - 1];
+    path->hn = GCP_attach_path (entry->peer,
+                                path);
+    if (NULL != path->hn)
+      return; /* yep, got attached, we are done. */
+  }
+
+  /* nobody wants us, discard the path */
+  path_destroy (path);
 }
 
 
@@ -165,6 +276,16 @@ GCPP_update_score (struct CadetPeerPath *path,
 
 /**
  * Create a peer path based on the result of a DHT lookup.
+ * If we already know this path, or one that is longer,
+ * simply return NULL.
+ *
+ * FIXME: change API completely!
+ * Should in here create path transiently, then call
+ * callback, and then do path destroy (if applicable)
+ * without returning in the middle.
+ *
+ * FIXME: also need to nicely handle case that this path
+ * extends (lengthens!) an existing path.
  *
  * @param get_path path of the get request
  * @param get_path_length lenght of @a get_path
@@ -208,9 +329,11 @@ GCPP_path_from_dht (const struct GNUNET_PeerIdentity 
*get_path,
  * @param p path to destroy.
  */
 void
-GCPP_path_destroy (struct CadetPeerPath *p)
+GCPP_path_destroy (struct CadetPeerPath *path)
 {
-  GNUNET_assert (0);
+  if (NULL != path->hn)
+    return; /* path was attached, to be kept! */
+  path_destroy (path);
 }
 
 
@@ -224,24 +347,43 @@ GCPP_path_destroy (struct CadetPeerPath *p)
 unsigned int
 GCPP_get_length (struct CadetPeerPath *path)
 {
-  GNUNET_assert (0);
-  return -1;
+  return path->entries_length;
 }
 
 
 /**
- * Obtain the identity of the peer at offset @a off in @a path.
+ * Find peer's offset on path.
+ *
+ * @param path path to search
+ * @param cp peer to look for
+ * @return offset of @a cp on @a path, or UINT_MAX if not found
+ */
+unsigned int
+GCPP_find_peer (struct CadetPeerPath *path,
+                struct CadetPeer *cp)
+{
+  for (unsigned int off = 0;
+       off < path->entries_length;
+       off++)
+    if (cp == GCPP_get_peer_at_offset (path,
+                                       off))
+      return off;
+  return UINT_MAX;
+}
+
+
+/**
+ * Obtain the peer at offset @a off in @a path.
  *
  * @param path peer path to inspect
  * @param off offset to return, must be smaller than path length
- * @param[out] pid where to write the pid, must not be NULL
+ * @return the peer at offset @a off
  */
-void
-GCPP_get_pid_at_offset (struct CadetPeerPath *path,
-                        unsigned int off,
-                        struct GNUNET_PeerIdentity *pid)
+struct CadetPeer *
+GCPP_get_peer_at_offset (struct CadetPeerPath *path,
+                         unsigned int off)
 {
-  GNUNET_assert (0);
+  return path->entries[off].peer;
 }
 
 
diff --git a/src/cadet/gnunet-service-cadet-new_paths.h 
b/src/cadet/gnunet-service-cadet-new_paths.h
index e00b05a3d..4b47784a0 100644
--- a/src/cadet/gnunet-service-cadet-new_paths.h
+++ b/src/cadet/gnunet-service-cadet-new_paths.h
@@ -33,6 +33,8 @@
 
 /**
  * Create a peer path based on the result of a DHT lookup.
+ * If we already know this path, or one that is longer,
+ * simply return NULL.
  *
  * @param get_path path of the get request
  * @param get_path_length lenght of @a get_path
@@ -50,10 +52,10 @@ GCPP_path_from_dht (const struct GNUNET_PeerIdentity 
*get_path,
 /**
  * Destroy a path, we no longer need it.
  *
- * @param p path to destroy.
+ * @param path path to destroy.
  */
 void
-GCPP_path_destroy (struct CadetPeerPath *p);
+GCPP_path_destroy (struct CadetPeerPath *path);
 
 
 /**
@@ -68,6 +70,62 @@ GCPP_get_length (struct CadetPeerPath *path);
 
 
 /**
+ * Return connection to @a destination using @a path, or return
+ * NULL if no such connection exists.
+ *
+ * @param path path to traverse
+ * @param destination destination node to get to, must be on path
+ * @param off offset of @a destination on @a path
+ * @return NULL if @a create is NO and we have no existing connection
+ *         otherwise connection from us to @a destination via @a path
+ */
+struct CadetConnection *
+GCPP_get_connection (struct CadetPeerPath *path,
+                     struct CadetPeer *destination,
+                     unsigned int off);
+
+
+/**
+ * Notify @a path that it is used for connection @a cc
+ * which ends at the path's offset @a off.
+ *
+ * @param path the path to remember the @a cc
+ * @param off the offset where the @a cc ends
+ * @param cc the connection to remember
+ */
+void
+GCPP_add_connection (struct CadetPeerPath *path,
+                     unsigned int off,
+                     struct CadetConnection *cc);
+
+
+/**
+ * Notify @a path that it is no longer used for connection @a cc which
+ * ended at the path's offset @a off.
+ *
+ * @param path the path to forget the @a cc
+ * @param off the offset where the @a cc ended
+ * @param cc the connection to forget
+ */
+void
+GCPP_del_connection (struct CadetPeerPath *path,
+                     unsigned int off,
+                     struct CadetConnection *cc);
+
+
+/**
+ * Find peer's offset on path.
+ *
+ * @param path path to search
+ * @param cp peer to look for
+ * @return offset of @a cp on @a path, or UINT_MAX if not found
+ */
+unsigned int
+GCPP_find_peer (struct CadetPeerPath *path,
+                struct CadetPeer *cp);
+
+
+/**
  * Return how much we like keeping the path.  This is an aggregate
  * score based on various factors, including the age of the path
  * (older == better), and the value of this path to all of its ajacent
@@ -91,13 +149,11 @@ GCPP_get_desirability (const struct CadetPeerPath *path);
  * the path desirable).
  *
  * @param path the path that is being released
- * @param cp original final destination of @a path
  * @param node entry in the heap of @a cp where this path is anchored
  *             should be used for updates to the desirability of this path
  */
 void
 GCPP_acquire (struct CadetPeerPath *path,
-              struct CadetPeer *cp,
               struct GNUNET_CONTAINER_HeapNode *node);
 
 
@@ -114,16 +170,15 @@ GCPP_release (struct CadetPeerPath *path);
 
 
 /**
- * Obtain the identity of the peer at offset @a off in @a path.
+ * Obtain the peer at offset @a off in @a path.
  *
  * @param path peer path to inspect
  * @param off offset to return, must be smaller than path length
- * @param[out] pid where to write the pid, must not be NULL
+ * @return peer at offset @a off
  */
-void
-GCPP_get_pid_at_offset (struct CadetPeerPath *path,
-                        unsigned int off,
-                        struct GNUNET_PeerIdentity *pid);
+struct CadetPeer *
+GCPP_get_peer_at_offset (struct CadetPeerPath *path,
+                         unsigned int off);
 
 
 #endif
diff --git a/src/cadet/gnunet-service-cadet-new_peer.c 
b/src/cadet/gnunet-service-cadet-new_peer.c
index 0ef65b7b6..8c8b23820 100644
--- a/src/cadet/gnunet-service-cadet-new_peer.c
+++ b/src/cadet/gnunet-service-cadet-new_peer.c
@@ -350,6 +350,13 @@ GCP_path_entry_add (struct CadetPeer *cp,
                                cp->path_tails[off],
                                entry);
   cp->num_paths++;
+
+  /* If we have a tunnel to this peer, tell the tunnel that there is a
+     new path available. */
+  if (NULL != cp->t)
+    GCT_consider_path (cp->t,
+                       entry->path,
+                       off);
 }
 
 
@@ -374,19 +381,22 @@ GCP_path_entry_remove (struct CadetPeer *cp,
 
 
 /**
- * Function called when the DHT finds a @a path to the peer (@a cls).
+ * Try adding a @a path to this @a peer.  If the peer already
+ * has plenty of paths, return NULL.
  *
- * @param cls the `struct CadetPeer`
- * @param path the path that was found
+ * @param cp peer to which the @a path leads to
+ * @param path a path looking for an owner
+ * @return NULL if this peer does not care to become a new owner,
+ *         otherwise the node in the peer's path heap for the @a path.
  */
-static void
-dht_result_cb (void *cls,
-               struct CadetPeerPath *path)
+struct GNUNET_CONTAINER_HeapNode *
+GCP_attach_path (struct CadetPeer *cp,
+                 struct CadetPeerPath *path)
 {
-  struct CadetPeer *cp = cls;
   GNUNET_CONTAINER_HeapCostType desirability;
   struct CadetPeerPath *root;
   GNUNET_CONTAINER_HeapCostType root_desirability;
+  struct GNUNET_CONTAINER_HeapNode *hn;
 
   desirability = GCPP_get_desirability (path);
   if (GNUNET_NO ==
@@ -397,23 +407,60 @@ dht_result_cb (void *cls,
     root = NULL;
     root_desirability = 0;
   }
-  if ( (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) ||
-       (desirability >= root_desirability) )
-  {
-    /* Yes, we'd like to add this path, add to our heap */
-    GCPP_acquire (path,
-                  cp,
-                  GNUNET_CONTAINER_heap_insert (cp->path_heap,
-                                                (void *) path,
-                                                desirability));
-  }
+
+  if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
+       (desirability < root_desirability) )
+    return NULL;
+
+  /* Yes, we'd like to add this path, add to our heap */
+  hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
+                                     (void *) cp,
+                                     desirability);
+
+  /* Consider maybe dropping other paths because of the new one */
   if (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
       2 * DESIRED_CONNECTIONS_PER_TUNNEL)
   {
-    /* Now we have way too many, drop least desirable */
-    root = GNUNET_CONTAINER_heap_remove_root (cp->path_heap);
-    GCPP_release (path);
+    /* Now we have way too many, drop least desirable UNLESS it is in use!
+       (Note that this intentionally keeps highly desireable, but currently
+       unused paths around in the hope that we might be able to switch, even
+       if the number of paths exceeds the threshold.) */
+    root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
+    if (NULL ==
+        GCPP_get_connection (root,
+                             cp,
+                             GCPP_get_length (root) - 1))
+    {
+      /* Got plenty of paths to this destination, and this is a low-quality
+         one that we don't care, allow it to die. */
+      GNUNET_assert (root ==
+                     GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
+      GCPP_release (root);
+    }
   }
+  return hn;
+}
+
+
+/**
+ * Function called when the DHT finds a @a path to the peer (@a cls).
+ *
+ * @param cls the `struct CadetPeer`
+ * @param path the path that was found
+ */
+static void
+dht_result_cb (void *cls,
+               struct CadetPeerPath *path)
+{
+  struct CadetPeer *cp = cls;
+  struct GNUNET_CONTAINER_HeapNode *hn;
+
+  hn = GCP_attach_path (cp,
+                        path);
+  if (NULL == hn)
+    return;
+  GCPP_acquire (path,
+                hn);
 }
 
 
@@ -508,9 +555,6 @@ GCP_get (const struct GNUNET_PeerIdentity *peer_id,
   cp->connections = GNUNET_CONTAINER_multihashmap_create (32,
                                                           GNUNET_YES);
   cp->path_heap = GNUNET_CONTAINER_heap_create 
(GNUNET_CONTAINER_HEAP_ORDER_MIN);
-  cp->search_h = NULL; // FIXME: start search immediately!?
-  cp->connectivity_suggestion = NULL; // FIXME: request with ATS!?
-
   GNUNET_assert (GNUNET_YES ==
                  GNUNET_CONTAINER_multipeermap_put (peers,
                                                     &cp->pid,
@@ -524,13 +568,12 @@ GCP_get (const struct GNUNET_PeerIdentity *peer_id,
  * Obtain the peer identity for a `struct CadetPeer`.
  *
  * @param cp our peer handle
- * @param[out] peer_id where to write the peer identity
+ * @return the peer identity
  */
-void
-GCP_id (struct CadetPeer *cp,
-        struct GNUNET_PeerIdentity *peer_id)
+const struct GNUNET_PeerIdentity *
+GCP_get_id (struct CadetPeer *cp)
 {
-  *peer_id = cp->pid;
+  return &cp->pid;
 }
 
 
@@ -586,8 +629,8 @@ GCP_iterate_paths (struct CadetPeer *peer,
     {
       if (GNUNET_NO ==
           callback (callback_cls,
-                    peer,
-                    pe->path))
+                    pe->path,
+                    i))
         return ret;
       ret++;
     }
@@ -629,7 +672,7 @@ void
 GCP_set_hello (struct CadetPeer *peer,
                const struct GNUNET_HELLO_Message *hello)
 {
-  /* FIXME! */
+  /* FIXME: keep HELLO, possibly offer to TRANSPORT... */
 
   consider_peer_destroy (peer);
 }
diff --git a/src/cadet/gnunet-service-cadet-new_peer.h 
b/src/cadet/gnunet-service-cadet-new_peer.h
index cc9a347fd..e1c8476d1 100644
--- a/src/cadet/gnunet-service-cadet-new_peer.h
+++ b/src/cadet/gnunet-service-cadet-new_peer.h
@@ -63,11 +63,10 @@ GCP_get (const struct GNUNET_PeerIdentity *peer_id,
  * Obtain the peer identity for a `struct CadetPeer`.
  *
  * @param cp our peer handle
- * @param[out] peer_id where to write the peer identity
+ * @return the peer identity
  */
-void
-GCP_id (struct CadetPeer *cp,
-        struct GNUNET_PeerIdentity *peer_id);
+const struct GNUNET_PeerIdentity *
+GCP_get_id (struct CadetPeer *cp);
 
 
 /**
@@ -84,40 +83,38 @@ GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
 /**
  * Count the number of known paths toward the peer.
  *
- * @param peer Peer to get path info.
+ * @param cp Peer to get path info.
  * @return Number of known paths.
  */
 unsigned int
-GCP_count_paths (const struct CadetPeer *peer);
+GCP_count_paths (const struct CadetPeer *cp);
 
 
 /**
  * Peer path iterator.
  *
  * @param cls Closure.
- * @param peer Peer this path is towards.
  * @param path Path itself
+ * @param off offset of the target peer in @a path
  * @return #GNUNET_YES if should keep iterating.
  *         #GNUNET_NO otherwise.
- *
- * FIXME: peer argument should be redundant; remove!
  */
 typedef int
 (*GCP_PathIterator) (void *cls,
-                     struct CadetPeer *peer,
-                     struct CadetPeerPath *path);
+                     struct CadetPeerPath *path,
+                     unsigned int off);
 
 
 /**
  * Iterate over the paths to a peer.
  *
- * @param peer Peer to get path info.
+ * @param cp Peer to get path info.
  * @param callback Function to call for every path.
  * @param callback_cls Closure for @a callback.
  * @return Number of iterated paths.
  */
 unsigned int
-GCP_iterate_paths (struct CadetPeer *peer,
+GCP_iterate_paths (struct CadetPeer *cp,
                    GCP_PathIterator callback,
                    void *callback_cls);
 
@@ -151,12 +148,12 @@ GCP_path_entry_add (struct CadetPeer *cp,
 /**
  * Get the tunnel towards a peer.
  *
- * @param peer Peer to get from.
+ * @param cp Peer to get from.
  * @param create #GNUNET_YES to create a tunnel if we do not have one
  * @return Tunnel towards peer.
  */
 struct CadetTunnel *
-GCP_get_tunnel (struct CadetPeer *peer,
+GCP_get_tunnel (struct CadetPeer *cp,
                 int create);
 
 
@@ -164,23 +161,37 @@ GCP_get_tunnel (struct CadetPeer *peer,
  * The tunnel to the given peer no longer exists, remove it from our
  * data structures, and possibly clean up the peer itself.
  *
- * @param peer the peer affected
+ * @param cp the peer affected
  * @param t the dead tunnel
  */
 void
-GCP_drop_tunnel (struct CadetPeer *peer,
+GCP_drop_tunnel (struct CadetPeer *cp,
                  struct CadetTunnel *t);
 
 
 /**
- * We got a HELLO for a @a peer, remember it, and possibly
+ * Try adding a @a path to this @a cp.  If the peer already
+ * has plenty of paths, return NULL.
+ *
+ * @param cp peer to which the @a path leads to
+ * @param path a path looking for an owner
+ * @return NULL if this peer does not care to become a new owner,
+ *         otherwise the node in the peer's path heap for the @a path.
+ */
+struct GNUNET_CONTAINER_HeapNode *
+GCP_attach_path (struct CadetPeer *cp,
+                 struct CadetPeerPath *path);
+
+
+/**
+ * We got a HELLO for a @a cp, remember it, and possibly
  * trigger adequate actions (like trying to connect).
  *
- * @param peer the peer we got a HELLO for
+ * @param cp the peer we got a HELLO for
  * @param hello the HELLO to remember
  */
 void
-GCP_set_hello (struct CadetPeer *peer,
+GCP_set_hello (struct CadetPeer *cp,
                const struct GNUNET_HELLO_Message *hello);
 
 
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.c 
b/src/cadet/gnunet-service-cadet-new_tunnels.c
index 4299d5bf7..1a07140f2 100644
--- a/src/cadet/gnunet-service-cadet-new_tunnels.c
+++ b/src/cadet/gnunet-service-cadet-new_tunnels.c
@@ -24,6 +24,11 @@
  * @brief Information we track per tunnel.
  * @author Bartlomiej Polot
  * @author Christian Grothoff
+ *
+ * FIXME:
+ * - when managing connections, distinguish those that
+ *   have (recently) had traffic from those that were
+ *   never ready (or not recently)
  */
 #include "platform.h"
 #include "gnunet_util_lib.h"
@@ -35,6 +40,7 @@
 #include "gnunet-service-cadet-new_connection.h"
 #include "gnunet-service-cadet-new_tunnels.h"
 #include "gnunet-service-cadet-new_peer.h"
+#include "gnunet-service-cadet-new_paths.h"
 
 
 /**
@@ -212,7 +218,12 @@ struct CadetTConnection
   /**
    * Connection handle.
    */
-  struct CadetConnection *c;
+  struct CadetConnection *cc;
+
+  /**
+   * Tunnel this connection belongs to.
+   */
+  struct CadetTunnel *t;
 
   /**
    * Creation time, to keep oldest connection alive.
@@ -269,9 +280,9 @@ struct CadetTunnelQueueEntry
 struct CadetTunnel
 {
   /**
-   * Endpoint of the tunnel.
+   * Destination of the tunnel.
    */
-  struct CadetPeer *peer;
+  struct CadetPeer *destination;
 
   /**
    * Peer's ephemeral key, to recreate @c e_key and @c d_key when own
@@ -348,7 +359,7 @@ struct CadetTunnel
   /**
    * Task to trim connections if too many are present.
    */
-  struct GNUNET_SCHEDULER_Task *trim_connections_task;
+  struct GNUNET_SCHEDULER_Task *maintain_connections_task;
 
   /**
    * Ephemeral message in the queue (to avoid queueing more than one).
@@ -390,7 +401,7 @@ GCT_2s (const struct CadetTunnel *t)
   GNUNET_snprintf (buf,
                    sizeof (buf),
                    "T(%s)",
-                   GCP_2s (t->peer));
+                   GCP_2s (t->destination));
   return buf;
 }
 
@@ -404,7 +415,7 @@ GCT_2s (const struct CadetTunnel *t)
 struct CadetPeer *
 GCT_get_destination (struct CadetTunnel *t)
 {
-  return t->peer;
+  return t->destination;
 }
 
 
@@ -503,17 +514,219 @@ static void
 destroy_tunnel (void *cls)
 {
   struct CadetTunnel *t = cls;
+  struct CadetTConnection *ct;
+  struct CadetTunnelQueueEntry *tqe;
 
   t->destroy_task = NULL;
-
-  // FIXME: implement!
-  GCP_drop_tunnel (t->peer,
+  GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (t->channels));
+  while (NULL != (ct = t->connection_head))
+  {
+    GNUNET_assert (ct->t == t);
+    GNUNET_CONTAINER_DLL_remove (t->connection_head,
+                                 t->connection_tail,
+                                 ct);
+    GCC_destroy (ct->cc);
+    GNUNET_free (ct);
+  }
+  while (NULL != (tqe = t->tq_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (t->tq_head,
+                                 t->tq_tail,
+                                 tqe);
+    // FIXME: implement!
+    GNUNET_free (tqe);
+  }
+  GCP_drop_tunnel (t->destination,
                    t);
+  GNUNET_CONTAINER_multihashmap32_destroy (t->channels);
+  if (NULL != t->maintain_connections_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->maintain_connections_task);
+    t->maintain_connections_task = NULL;
+  }
   GNUNET_free (t);
 }
 
 
 /**
+ * A connection is ready for transmission.  Looks at our message queue
+ * and if there is a message, sends it out via the connection.
+ *
+ * @param cls the `struct CadetTConnection` that is ready
+ */
+static void
+connection_ready_cb (void *cls)
+{
+  struct CadetTConnection *ct = cls;
+  struct CadetTunnel *t = ct->t;
+  struct CadetTunnelQueueEntry *tq = t->tq_head;
+
+  if (NULL == tq)
+    return; /* no messages pending right now */
+
+  /* ready to send message 'tq' on tunnel 'ct' */
+  GNUNET_assert (t == tq->t);
+  GNUNET_CONTAINER_DLL_remove (t->tq_head,
+                               t->tq_tail,
+                               tq);
+  GCC_transmit (ct->cc,
+                (const struct GNUNET_MessageHeader *) &tq[1]);
+  tq->cont (tq->cont_cls);
+  GNUNET_free (tq);
+}
+
+
+/**
+ * Called when either we have a new connection, or a new message in the
+ * queue, or some existing connection has transmission capacity.  Looks
+ * at our message queue and if there is a message, picks a connection
+ * to send it on.
+ *
+ * @param t tunnel to process messages on
+ */
+static void
+trigger_transmissions (struct CadetTunnel *t)
+{
+  struct CadetTConnection *ct;
+
+  if (NULL == t->tq_head)
+    return; /* no messages pending right now */
+  for (ct = t->connection_head;
+       NULL != ct;
+       ct = ct->next)
+    if (GNUNET_YES == GCC_is_ready (ct->cc))
+      break;
+  if (NULL == ct)
+    return; /* no connections ready */
+  connection_ready_cb (ct);
+}
+
+
+/**
+ * Function called to maintain the connections underlying our tunnel.
+ * Tries to maintain (incl. tear down) connections for the tunnel, and
+ * if there is a significant change, may trigger transmissions.
+ *
+ * Basically, needs to check if there are connections that perform
+ * badly, and if so eventually kill them and trigger a replacement.
+ * The strategy is to open one more connection than
+ * #DESIRED_CONNECTIONS_PER_TUNNEL, and then periodically kick out the
+ * least-performing one, and then inquire for new ones.
+ *
+ * @param cls the `struct CadetTunnel`
+ */
+static void
+maintain_connections_cb (void *cls)
+{
+  struct CadetTunnel *t = cls;
+
+  GNUNET_break (0); // FIXME: implement!
+}
+
+
+/**
+ * Consider using the path @a p for the tunnel @a t.
+ * The tunnel destination is at offset @a off in path @a p.
+ *
+ * @param cls our tunnel
+ * @param path a path to our destination
+ * @param off offset of the destination on path @a path
+ * @return #GNUNET_YES (should keep iterating)
+ */
+static int
+consider_path_cb (void *cls,
+                  struct CadetPeerPath *path,
+                  unsigned int off)
+{
+  struct CadetTunnel *t = cls;
+  unsigned int min_length = UINT_MAX;
+  GNUNET_CONTAINER_HeapCostType max_desire = 0;
+  struct CadetTConnection *ct;
+
+  /* Check if we care about the new path. */
+  for (ct = t->connection_head;
+       NULL != ct;
+       ct = ct->next)
+  {
+    struct CadetPeerPath *ps;
+
+    ps = GCC_get_path (ct->cc);
+    if (ps == path)
+      return GNUNET_YES; /* duplicate */
+    min_length = GNUNET_MIN (min_length,
+                             GCPP_get_length (ps));
+    max_desire = GNUNET_MAX (max_desire,
+                             GCPP_get_desirability (ps));
+  }
+
+  /* FIXME: not sure we should really just count
+     'num_connections' here, as they may all have
+     consistently failed to connect. */
+
+  /* We iterate by increasing path length; if we have enough paths and
+     this one is more than twice as long than what we are currently
+     using, then ignore all of these super-long ones! */
+  if ( (t->num_connections > DESIRED_CONNECTIONS_PER_TUNNEL) &&
+       (min_length * 2 < off) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Ignoring paths of length %u, they are way too long.\n",
+                min_length * 2);
+    return GNUNET_NO;
+  }
+  /* If we have enough paths and this one looks no better, ignore it. */
+  if ( (t->num_connections >= DESIRED_CONNECTIONS_PER_TUNNEL) &&
+       (min_length < GCPP_get_length (path)) &&
+       (max_desire > GCPP_get_desirability (path)) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Ignoring path (%u/%llu) to %s, got something better 
already.\n",
+                GCPP_get_length (path),
+                (unsigned long long) GCPP_get_desirability (path),
+                GCP_2s (t->destination));
+    return GNUNET_YES;
+  }
+
+  /* Path is interesting (better by some metric, or we don't have
+     enough paths yet). */
+  ct = GNUNET_new (struct CadetTConnection);
+  ct->created = GNUNET_TIME_absolute_get ();
+  ct->t = t;
+  ct->cc = GCC_create (t->destination,
+                      path,
+                      &connection_ready_cb,
+                      t);
+  /* FIXME: schedule job to kill connection (and path?)  if it takes
+     too long to get ready! (And track performance data on how long
+     other connections took with the tunnel!) */
+  GNUNET_CONTAINER_DLL_insert (t->connection_head,
+                               t->connection_tail,
+                               ct);
+  t->num_connections++;
+  return GNUNET_YES;
+}
+
+
+/**
+ * Consider using the path @a p for the tunnel @a t.
+ * The tunnel destination is at offset @a off in path @a p.
+ *
+ * @param cls our tunnel
+ * @param path a path to our destination
+ * @param off offset of the destination on path @a path
+ */
+void
+GCT_consider_path (struct CadetTunnel *t,
+                   struct CadetPeerPath *p,
+                   unsigned int off)
+{
+  (void) consider_path_cb (t,
+                           p,
+                           off);
+}
+
+
+/**
  * Create a tunnel to @a destionation.  Must only be called
  * from within #GCP_get_tunnel().
  *
@@ -526,9 +739,14 @@ GCT_create_tunnel (struct CadetPeer *destination)
   struct CadetTunnel *t;
 
   t = GNUNET_new (struct CadetTunnel);
-  t->peer = destination;
+  t->destination = destination;
   t->channels = GNUNET_CONTAINER_multihashmap32_create (8);
-
+  (void) GCP_iterate_paths (destination,
+                            &consider_path_cb,
+                            t);
+  t->maintain_connections_task
+    = GNUNET_SCHEDULER_add_now (&maintain_connections_cb,
+                                t);
   return t;
 }
 
@@ -589,7 +807,8 @@ GCT_send (struct CadetTunnel *t,
   GNUNET_CONTAINER_DLL_insert_tail (t->tq_head,
                                     t->tq_tail,
                                     q);
-  /* FIXME: initiate transmission process! */
+  /* FIXME: what about KX being ready? */
+  trigger_transmissions (t);
   return q;
 }
 
@@ -631,7 +850,7 @@ GCT_iterate_connections (struct CadetTunnel *t,
        NULL != ct;
        ct = ct->next)
     iter (iter_cls,
-          ct->c);
+          ct->cc);
 }
 
 
@@ -820,7 +1039,8 @@ GCT_debug (const struct CadetTunnel *t,
   LOG2 (level,
         "TTT connections:\n");
   for (iter_c = t->connection_head; NULL != iter_c; iter_c = iter_c->next)
-    GCC_debug (iter_c->c, level);
+    GCC_debug (iter_c->cc,
+               level);
 
   LOG2 (level,
         "TTT TUNNEL END\n");
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.h 
b/src/cadet/gnunet-service-cadet-new_tunnels.h
index 5e06559d5..0abe99f70 100644
--- a/src/cadet/gnunet-service-cadet-new_tunnels.h
+++ b/src/cadet/gnunet-service-cadet-new_tunnels.h
@@ -28,6 +28,7 @@
 #ifndef GNUNET_SERVICE_CADET_TUNNELS_H
 #define GNUNET_SERVICE_CADET_TUNNELS_H
 
+#include "gnunet-service-cadet-new.h"
 
 /**
  * How many connections would we like to have per tunnel?
@@ -156,6 +157,20 @@ GCT_get_destination (struct CadetTunnel *t);
 
 
 /**
+ * Consider using the path @a p for the tunnel @a t.
+ * The tunnel destination is at offset @a off in path @a p.
+ *
+ * @param cls our tunnel
+ * @param path a path to our destination
+ * @param off offset of the destination on path @a path
+ */
+void
+GCT_consider_path (struct CadetTunnel *t,
+                   struct CadetPeerPath *p,
+                   unsigned int off);
+
+
+/**
  * Add a channel to a tunnel.
  *
  * @param t Tunnel.

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]