make copy of transport_api_core.c
[oweals/gnunet.git] / src / transport / transport-testing.c
index ae878a79e5daca2501e9c5a5cde91b882883f30a..e3d4b7a9bdc9d34a07f3be7a94ac5157f8c74c4b 100644 (file)
@@ -2,20 +2,18 @@
      This file is part of GNUnet.
      Copyright (C) 2006, 2009, 2015, 2016 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
+     GNUnet is free software: you can redistribute it and/or modify it
+     under the terms of the GNU Affero General Public License as published
+     by the Free Software Foundation, either version 3 of the License,
+     or (at your option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
+     Affero General Public License for more details.
+    
+     You should have received a copy of the GNU Affero General Public License
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 /**
  * @file transport-testing.c
@@ -44,11 +42,21 @@ find_peer_context (struct GNUNET_TRANSPORT_TESTING_Handle *tth,
 }
 
 
-static void
-notify_connecting_context (struct GNUNET_TRANSPORT_TESTING_Handle *tth,
-                           struct GNUNET_TRANSPORT_TESTING_PeerContext *p1,
-                           struct GNUNET_TRANSPORT_TESTING_PeerContext *p2)
+/**
+ * Find any connecting context matching the given pair of peers.
+ *
+ * @param p1 first peer
+ * @param p2 second peer
+ * @param cb function to call
+ * @param cb_cls closure for @a cb
+ */
+void
+GNUNET_TRANSPORT_TESTING_find_connecting_context (struct GNUNET_TRANSPORT_TESTING_PeerContext *p1,
+                                                 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2,
+                                                 GNUNET_TRANSPORT_TESTING_ConnectContextCallback cb,
+                                                 void *cb_cls)
 {
+  struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
 
@@ -56,36 +64,95 @@ notify_connecting_context (struct GNUNET_TRANSPORT_TESTING_Handle *tth,
   {
     ccn = cc->next;
     if ( (cc->p1 == p1) &&
-         (cc->p2 == p2) )
-      cc->p1_c = GNUNET_YES;
-    if ( (cc->p1 == p2) &&
-         (cc->p2 == p1) )
-      cc->p2_c = GNUNET_YES;
-    if ( (cc->p1_c == GNUNET_YES) &&
-         (cc->p2_c == GNUNET_YES) )
-    {
-      cc->cb (cc->cb_cls);
-      GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
-    }
+        (cc->p2 == p2) )
+      cb (cb_cls,
+         cc);
   }
 }
 
 
 static void
+set_p1c (void *cls,
+        struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
+{
+  int *found = cls;
+
+  if (NULL != found)
+    *found = GNUNET_YES;
+  cx->p1_c = GNUNET_YES;
+}
+
+
+static void
+set_mq (void *cls,
+       struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
+{
+  struct GNUNET_MQ_Handle *mq = cls;
+
+  cx->mq = mq;
+}
+
+
+static void
+set_p2c (void *cls,
+        struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
+{
+  int *found = cls;
+
+  if (NULL != found)
+    *found = GNUNET_YES;
+  cx->p2_c = GNUNET_YES;
+}
+
+
+static void
+clear_p1c (void *cls,
+          struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
+{
+  int *found = cls;
+
+  if (NULL != found)
+    *found = GNUNET_YES;
+  cx->p1_c = GNUNET_NO;
+}
+
+
+static void
+clear_p2c (void *cls,
+        struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
+{
+  int *found = cls;
+
+  if (NULL != found)
+    *found = GNUNET_YES;
+  cx->p2_c = GNUNET_NO;
+}
+
+
+static void *
 notify_connect (void *cls,
-                const struct GNUNET_PeerIdentity *peer)
+                const struct GNUNET_PeerIdentity *peer,
+               struct GNUNET_MQ_Handle *mq)
 {
   struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
+  struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
   char *p2_s;
   struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
+  struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
+  struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
+  int found;
+  void *ret;
 
   p2 = find_peer_context (p->tth,
                           peer);
   if (NULL != p->nc)
-    p->nc (p->cb_cls,
-           peer);
+    ret = p->nc (p->cb_cls,
+                peer,
+                mq);
+  else
+    ret = NULL;
 
-  if (p2 != NULL)
+  if (NULL != p2)
     GNUNET_asprintf (&p2_s,
                      "%u (`%s')",
                      p2->no,
@@ -100,30 +167,109 @@ notify_connect (void *cls,
        p->no,
        GNUNET_i2s (&p->id));
   GNUNET_free (p2_s);
-  notify_connecting_context (p->tth,
-                             p,
-                             p2);
+  /* update flags in connecting contexts */
+  found = GNUNET_NO;
+  GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
+                                                   p2,
+                                                   &set_p1c,
+                                                   &found);
+  if (GNUNET_NO == found)
+  {
+    cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
+    cc->p1 = p;
+    cc->p2 = p2;
+    cc->p1_c = GNUNET_YES;
+    GNUNET_CONTAINER_DLL_insert (tth->cc_head,
+                                tth->cc_tail,
+                                cc);
+  }
+  found = GNUNET_NO;
+  GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
+                                                   p,
+                                                   &set_p2c,
+                                                   &found);
+  if (GNUNET_NO == found)
+  {
+    cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
+    cc->p1 = p2;
+    cc->p2 = p;
+    cc->p1_c = GNUNET_YES;
+    GNUNET_CONTAINER_DLL_insert (tth->cc_head,
+                                tth->cc_tail,
+                                cc);
+  }
+  GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
+                                                   p2,
+                                                   &set_mq,
+                                                   mq);
+  /* update set connected flag for all requests */
+  for (cc = tth->cc_head; NULL != cc; cc = cc->next)
+  {
+    if (GNUNET_YES == cc->connected)
+      continue;
+    if ( (GNUNET_YES == cc->p1_c) &&
+         (GNUNET_YES == cc->p2_c) )
+    {
+      cc->connected = GNUNET_YES;
+      /* stop trying to connect */
+      if (NULL != cc->tct)
+      {
+       GNUNET_SCHEDULER_cancel (cc->tct);
+       cc->tct = NULL;
+      }
+      if (NULL != cc->oh)
+      {
+       GNUNET_TRANSPORT_offer_hello_cancel (cc->oh);
+       cc->oh = NULL;
+      }
+      if (NULL != cc->ats_sh)
+      {
+       GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh);
+       cc->ats_sh = NULL;
+      }
+    }
+  }
+  /* then notify application */
+  for (cc = tth->cc_head; NULL != cc; cc = ccn)
+  {
+    ccn = cc->next;
+    if ( (GNUNET_YES == cc->connected) &&
+         (NULL != cc->cb) )
+    {
+      cc->cb (cc->cb_cls);
+      cc->cb = NULL; /* only notify once! */
+    }
+  }
+  return ret;
 }
 
 
+/**
+ * Offer the current HELLO of P2 to P1.
+ *
+ * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest`
+ */
+static void
+offer_hello (void *cls);
+
+
 static void
 notify_disconnect (void *cls,
-                   const struct GNUNET_PeerIdentity *peer)
+                   const struct GNUNET_PeerIdentity *peer,
+                  void *handler_cls)
 {
   struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
+  struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
   char *p2_s;
   /* Find PeerContext */
   int no = 0;
   struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = NULL;
+  struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
 
-  if (NULL != p)
-  {
-    p2 = find_peer_context (p->tth,
-                            peer);
-    no = p->no;
-  }
-
-  if (p2 != NULL)
+  p2 = find_peer_context (p->tth,
+                         peer);
+  no = p->no;
+  if (NULL != p2)
     GNUNET_asprintf (&p2_s,
                      "%u (`%s')",
                      p2->no,
@@ -138,28 +284,47 @@ notify_disconnect (void *cls,
        no,
        GNUNET_i2s (&p->id));
   GNUNET_free (p2_s);
-
-  if (NULL == p)
-    return;
+  /* notify about disconnect */
   if (NULL != p->nd)
     p->nd (p->cb_cls,
-           peer);
-}
-
-
-static void
-notify_receive (void *cls,
-                const struct GNUNET_PeerIdentity *peer,
-                const struct GNUNET_MessageHeader *message)
-{
-  struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
-
-  if (NULL == p)
+           peer,
+          handler_cls);
+  if (NULL == p2)
     return;
-  if (NULL != p->rec)
-    p->rec (p->cb_cls,
-            peer,
-            message);
+  /* clear MQ, it is now invalid */
+  GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
+                                                   p2,
+                                                   &set_mq,
+                                                   NULL);
+  /* update set connected flags for all requests */
+  GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
+                                                   p2,
+                                                   &clear_p1c,
+                                                   NULL);
+  GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
+                                                   p,
+                                                   &clear_p2c,
+                                                   NULL);
+  /* resume connectivity requests as necessary */
+  for (cc = tth->cc_head; NULL != cc; cc = cc->next)
+  {
+    if (GNUNET_NO == cc->connected)
+      continue;
+    if ( (GNUNET_YES != cc->p1_c) ||
+         (GNUNET_YES != cc->p2_c) )
+    {
+      cc->connected = GNUNET_NO;
+      /* start trying to connect */
+      if ( (NULL == cc->tct) &&
+          (NULL == cc->oh) )
+       cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
+                                           cc);
+      if (NULL == cc->ats_sh)
+       cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats,
+                                                     &p2->id,
+                                                     1);
+    }
+  }
 }
 
 
@@ -185,8 +350,7 @@ get_hello (void *cb_cls,
          "Peer %u (`%s') successfully started\n",
          p->no,
          GNUNET_i2s (&p->id));
-    p->start_cb (p,
-                 p->cb_cls);
+    p->start_cb (p->start_cb_cls);
     p->start_cb = NULL;
   }
 }
@@ -197,26 +361,29 @@ get_hello (void *cb_cls,
  * @param tth the testing handle
  * @param cfgname configuration file
  * @param peer_id a unique number to identify the peer
- * @param rec receive callback
+ * @param handlers functions for receiving messages
  * @param nc connect callback
  * @param nd disconnect callback
- * @param start_cb start callback
  * @param cb_cls closure for callback
+ * @param start_cb start callback
+ * @param start_cb_cls closure for callback
  * @return the peer context
  */
 struct GNUNET_TRANSPORT_TESTING_PeerContext *
 GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_Handle *tth,
                                      const char *cfgname,
                                      int peer_id,
-                                     GNUNET_TRANSPORT_ReceiveCallback rec,
-                                     GNUNET_TRANSPORT_NotifyConnect nc,
-                                     GNUNET_TRANSPORT_NotifyDisconnect nd,
-                                     GNUNET_TRANSPORT_TESTING_StartCallback start_cb,
-                                     void *cb_cls)
+                                     const struct GNUNET_MQ_MessageHandler *handlers,
+                                     GNUNET_TRANSPORT_NotifyConnecT nc,
+                                     GNUNET_TRANSPORT_NotifyDisconnecT nd,
+                                    void *cb_cls,
+                                     GNUNET_SCHEDULER_TaskCallback start_cb,
+                                     void *start_cb_cls)
 {
   char *emsg = NULL;
   struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
-  struct GNUNET_PeerIdentity *dummy;
+  struct GNUNET_PeerIdentity dummy;
+  unsigned int i;
 
   if (GNUNET_NO == GNUNET_DISK_file_test (cfgname))
   {
@@ -230,12 +397,24 @@ GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_Handle *tth
   p->tth = tth;
   p->nc = nc;
   p->nd = nd;
-  p->rec = rec;
-  p->start_cb = start_cb;
-  if (cb_cls != NULL)
+  if (NULL != handlers)
+  {
+    for (i=0;NULL != handlers[i].cb;i++) ;
+    p->handlers = GNUNET_new_array (i + 1,
+                                   struct GNUNET_MQ_MessageHandler);
+    GNUNET_memcpy (p->handlers,
+                  handlers,
+                  i * sizeof (struct GNUNET_MQ_MessageHandler));
+  }
+  if (NULL != cb_cls)
     p->cb_cls = cb_cls;
   else
     p->cb_cls = p;
+  p->start_cb = start_cb;
+  if (NULL != start_cb_cls)
+    p->start_cb_cls = start_cb_cls;
+  else
+    p->start_cb_cls = p;
   GNUNET_CONTAINER_DLL_insert (tth->p_head,
                                tth->p_tail,
                                p);
@@ -302,14 +481,16 @@ GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_Handle *tth
        "Peer %u configured with identity `%s'\n",
        p->no,
        GNUNET_i2s_full (&p->id));
-
-  p->th = GNUNET_TRANSPORT_connect (p->cfg,
-                                    NULL,
-                                    p,
-                                    &notify_receive,
-                                    &notify_connect,
-                                    &notify_disconnect);
-  if (NULL == p->th)
+  p->tmh = GNUNET_TRANSPORT_manipulation_connect (p->cfg);
+  p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
+                                        NULL,
+                                        handlers,
+                                        p,
+                                        &notify_connect,
+                                        &notify_disconnect,
+                                        NULL);
+  if ( (NULL == p->th) ||
+       (NULL == p->tmh) )
   {
     LOG (GNUNET_ERROR_TYPE_ERROR,
          "Failed to connect to transport service for peer `%s': `%s'\n",
@@ -328,10 +509,11 @@ GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_Handle *tth
     GNUNET_TRANSPORT_TESTING_stop_peer (p);
     return NULL;
   }
-  p->ghh = GNUNET_TRANSPORT_get_hello (p->cfg,
-                                       &get_hello,
+  p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg,
+                                      GNUNET_TRANSPORT_AC_ANY,
+                                      &get_hello,
                                        p);
-  GNUNET_assert (p->ghh != NULL);
+  GNUNET_assert (NULL != p->ghh);
   return p;
 }
 
@@ -341,14 +523,17 @@ GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_Handle *tth
  *
  * @param p the peer
  * @param restart_cb callback to call when restarted
- * @param cb_cls callback closure
+ * @param restart_cb_cls callback closure
  * @return #GNUNET_OK in success otherwise #GNUNET_SYSERR
  */
 int
 GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_PeerContext *p,
-                                       GNUNET_TRANSPORT_TESTING_StartCallback restart_cb,
-                                       void *cb_cls)
+                                       GNUNET_SCHEDULER_TaskCallback restart_cb,
+                                       void *restart_cb_cls)
 {
+  struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
+  struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
+
   /* shutdown */
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Stopping peer %u (`%s')\n",
@@ -356,14 +541,26 @@ GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_PeerConte
        GNUNET_i2s (&p->id));
   if (NULL != p->ghh)
   {
-    GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
+    GNUNET_TRANSPORT_hello_get_cancel (p->ghh);
     p->ghh = NULL;
   }
   if (NULL != p->th)
   {
-    GNUNET_TRANSPORT_disconnect (p->th);
+    GNUNET_TRANSPORT_core_disconnect (p->th);
     p->th = NULL;
   }
+  if (NULL != p->tmh)
+  {
+    GNUNET_TRANSPORT_manipulation_disconnect (p->tmh);
+    p->tmh = NULL;
+  }
+  for (cc = p->tth->cc_head; NULL != cc; cc = ccn)
+  {
+    ccn = cc->next;
+    if ( (cc->p1 == p) ||
+         (cc->p2 == p) )
+      GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
+  }
   if (NULL != p->ats)
   {
     GNUNET_ATS_connectivity_done (p->ats);
@@ -397,17 +594,19 @@ GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_PeerConte
 
   GNUNET_assert (NULL == p->start_cb);
   p->start_cb = restart_cb;
-  p->cb_cls = cb_cls;
-
-  p->th = GNUNET_TRANSPORT_connect (p->cfg,
-                                    NULL,
-                                    p,
-                                    &notify_receive,
-                                    &notify_connect,
-                                    &notify_disconnect);
+  p->start_cb_cls = restart_cb_cls;
+
+  p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
+                                        NULL,
+                                        p->handlers,
+                                        p,
+                                        &notify_connect,
+                                        &notify_disconnect,
+                                        NULL);
   GNUNET_assert (NULL != p->th);
   p->ats = GNUNET_ATS_connectivity_init (p->cfg);
-  p->ghh = GNUNET_TRANSPORT_get_hello (p->cfg,
+  p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg,
+                                      GNUNET_TRANSPORT_AC_ANY,
                                        &get_hello,
                                        p);
   GNUNET_assert (NULL != p->ghh);
@@ -424,15 +623,29 @@ void
 GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_PeerContext *p)
 {
   struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
+  struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
+  struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
 
+  for (cc = tth->cc_head; NULL != cc; cc = ccn)
+  {
+    ccn = cc->next;
+    if ( (cc->p1 == p) ||
+         (cc->p2 == p) )
+      GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
+  }
   if (NULL != p->ghh)
   {
-    GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
+    GNUNET_TRANSPORT_hello_get_cancel (p->ghh);
     p->ghh = NULL;
   }
+  if (NULL != p->tmh)
+  {
+    GNUNET_TRANSPORT_manipulation_disconnect (p->tmh);
+    p->tmh = NULL;
+  }
   if (NULL != p->th)
   {
-    GNUNET_TRANSPORT_disconnect (p->th);
+    GNUNET_TRANSPORT_core_disconnect (p->th);
     p->th = NULL;
   }
   if (NULL != p->peer)
@@ -463,6 +676,11 @@ GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_PeerContext
     GNUNET_CONFIGURATION_destroy (p->cfg);
     p->cfg = NULL;
   }
+  if (NULL != p->handlers)
+  {
+    GNUNET_free (p->handlers);
+    p->handlers = NULL;
+  }
   GNUNET_CONTAINER_DLL_remove (tth->p_head,
                                tth->p_tail,
                                p);
@@ -474,15 +692,6 @@ GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_PeerContext
 }
 
 
-/**
- * Offer the current HELLO of P2 to P1.
- *
- * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest`
- */
-static void
-offer_hello (void *cls);
-
-
 /**
  * Function called after the HELLO was passed to the
  * transport service.
@@ -555,6 +764,18 @@ GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_PeerCont
 {
   struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
+  struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
+
+  ccn = NULL;
+  for (cc = tth->cc_head; NULL != cc; cc = cc->next)
+  {
+    if ( (cc->p1 == p1) &&
+        (cc->p2 == p2) )
+    {
+      ccn = cc;
+      break;
+    }
+  }
 
   cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
   cc->p1 = p1;
@@ -564,6 +785,12 @@ GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_PeerCont
     cc->cb_cls = cls;
   else
     cc->cb_cls = cc;
+  if (NULL != ccn)
+  {
+    cc->p1_c = ccn->p1_c;
+    cc->p2_c = ccn->p2_c;
+    cc->connected = ccn->connected;
+  }
   GNUNET_CONTAINER_DLL_insert (tth->cc_head,
                                tth->cc_tail,
                                cc);