binding to specific address
[oweals/gnunet.git] / src / transport / test_transport_api.c
index 3a902a677df1eba6d3a9f963c0023c0b81ef0fb6..eb64b0f398130a8846a6b17d644ba607843ef6c2 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2009 Christian Grothoff (and other contributing authors)
+     (C) 2009, 2010 Christian Grothoff (and other contributing authors)
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      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 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
 */
 /**
  * @file transport/test_transport_api.c
 */
 /**
  * @file transport/test_transport_api.c
- * @brief testcase for transport_api.c
+ * @brief base test case for transport implementations
+ *
+ * This test case serves as a base for tcp, udp, and udp-nat
+ * transport test cases.  Based on the executable being run
+ * the correct test case will be performed.  Conservation of
+ * C code apparently.
  */
 #include "platform.h"
 #include "gnunet_common.h"
  */
 #include "platform.h"
 #include "gnunet_common.h"
@@ -30,6 +35,7 @@
 #include "gnunet_scheduler_lib.h"
 #include "gnunet_transport_service.h"
 #include "transport.h"
 #include "gnunet_scheduler_lib.h"
 #include "gnunet_transport_service.h"
 #include "transport.h"
+#include "transport-testing.h"
 
 #define VERBOSE GNUNET_NO
 
 
 #define VERBOSE GNUNET_NO
 
 
 #define START_ARM GNUNET_YES
 
 
 #define START_ARM GNUNET_YES
 
-#define VERBOSE_TRANSPORT GNUNET_NO
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
 
 /**
  * How long until we give up on transmitting the message?
  */
 
 /**
  * How long until we give up on transmitting the message?
  */
-#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 50)
+#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
 
 #define MTYPE 12345
 
 
 #define MTYPE 12345
 
-struct PeerContext
-{
-  struct GNUNET_CONFIGURATION_Handle *cfg;
-  struct GNUNET_TRANSPORT_Handle *th;
-  struct GNUNET_PeerIdentity id;
-#if START_ARM
-  pid_t arm_pid;
-#endif
-};
-
-static struct PeerContext p1;
+static char *test_source;
 
 
-static struct PeerContext p2;
+static char *test_plugin;
 
 
-static struct GNUNET_SCHEDULER_Handle *sched;
+static char *test_name;
 
 static int ok;
 
 
 static int ok;
 
-static int is_tcp;
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier send_task;
 
 
-static int is_udp;
+struct PeerContext *p1;
 
 
-GNUNET_SCHEDULER_TaskIdentifier die_task;
+struct PeerContext *p2;
+
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
+
+struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+char *cfg_file_p1;
+
+char *cfg_file_p2;
 
 #if VERBOSE
 #define OKPP do { ok++; fprintf (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
 
 #if VERBOSE
 #define OKPP do { ok++; fprintf (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
@@ -80,244 +89,186 @@ GNUNET_SCHEDULER_TaskIdentifier die_task;
 static void
 end ()
 {
 static void
 end ()
 {
-  /* do work here */
-  GNUNET_assert (ok == 8);
-  GNUNET_SCHEDULER_cancel (sched, die_task);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from transports!\n");
-  GNUNET_TRANSPORT_disconnect (p1.th);
-  GNUNET_TRANSPORT_disconnect (p2.th);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
 
 
-  die_task = GNUNET_SCHEDULER_NO_TASK;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transports disconnected, returning success!\n");
-  ok = 0;
-}
+  if (send_task != GNUNET_SCHEDULER_NO_TASK)
+    GNUNET_SCHEDULER_cancel (send_task);
 
 
-static void
-stop_arm (struct PeerContext *p)
-{
-#if START_ARM
-  if (0 != PLIBC_KILL (p->arm_pid, SIGTERM))
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
-  GNUNET_OS_process_wait (p->arm_pid);
-#endif
-  GNUNET_CONFIGURATION_destroy (p->cfg);
-}
-
-static void
-end_badly ()
-{
-  /* do work here */
-  fprintf(stderr, "Ending on an unhappy note.\n");
+  if (die_task != GNUNET_SCHEDULER_NO_TASK)
+    GNUNET_SCHEDULER_cancel (die_task);
 
 
-  GNUNET_TRANSPORT_disconnect (p1.th);
-  GNUNET_TRANSPORT_disconnect (p2.th);
+  if (th != NULL)
+    GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+  th = NULL;
 
 
-  ok = 1;
-  return;
+  GNUNET_TRANSPORT_TESTING_stop_peer (p1);
+  GNUNET_TRANSPORT_TESTING_stop_peer (p2);
 }
 
 static void
 }
 
 static void
-notify_receive (void *cls,
-                const struct GNUNET_PeerIdentity *peer,
-                const struct GNUNET_MessageHeader *message,
-                struct GNUNET_TIME_Relative latency,
-               uint32_t distance)
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ok is (%d)!\n",
-              ok);
-  GNUNET_assert (ok == 7);
-  OKPP;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %d from peer (%p)!\n",
-                ntohs(message->type), cls);
-
-  GNUNET_assert (MTYPE == ntohs (message->type));
-  GNUNET_assert (sizeof (struct GNUNET_MessageHeader) ==
-                 ntohs (message->size));
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message from peer (%p)!\n",
-              cls);
-  end ();
-}
+  die_task = GNUNET_SCHEDULER_NO_TASK;
 
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
 
 
-static void
-notify_connect (void *cls,
-                const struct GNUNET_PeerIdentity *peer,
-                struct GNUNET_TIME_Relative latency,
-               uint32_t distance)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Peer `%4s' connected to us (%p)!\n", GNUNET_i2s (peer), cls);
-  GNUNET_assert ((ok >= 1) && (ok <= 6));
-  OKPP;
-}
+  if (send_task != GNUNET_SCHEDULER_NO_TASK)
+    GNUNET_SCHEDULER_cancel (send_task);
 
 
+  if (cc != NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n"));
+    GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
+  }
 
 
-static void
-notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
-{
-  ok--;
+  if (th != NULL)
+    GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+  th = NULL;
+
+  if (p1 != NULL)
+    GNUNET_TRANSPORT_TESTING_stop_peer (p1);
+  if (p2 != NULL)
+    GNUNET_TRANSPORT_TESTING_stop_peer (p2);
+
+  ok = GNUNET_SYSERR;
 }
 
 
 static void
 }
 
 
 static void
-setup_peer (struct PeerContext *p, const char *cfgname)
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+                const struct GNUNET_MessageHeader *message,
+                const struct GNUNET_TRANSPORT_ATS_Information *ats,
+                uint32_t ats_count)
 {
 {
-  p->cfg = GNUNET_CONFIGURATION_create ();
-#if START_ARM
-  p->arm_pid = GNUNET_OS_start_process ("gnunet-service-arm",
-                                        "gnunet-service-arm",
-#if VERBOSE_ARM
-                                        "-L", "DEBUG",
-#endif
-                                        "-c", cfgname, NULL);
-#endif
-  GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received message of type %d from peer %s!\n",
+              ntohs (message->type), GNUNET_i2s (peer));
 
 
-  p->th = GNUNET_TRANSPORT_connect (sched, p->cfg,
-                                    p,
-                                    &notify_receive,
-                                    &notify_connect, &notify_disconnect);
-  GNUNET_assert (p->th != NULL);
+  if ((MTYPE == ntohs (message->type)) &&
+      (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)))
+  {
+    ok = 0;
+    end ();
+  }
+  else
+  {
+    GNUNET_break (0);
+    ok = 1;
+    end ();
+  }
 }
 
 
 static size_t
 notify_ready (void *cls, size_t size, void *buf)
 {
 }
 
 
 static size_t
 notify_ready (void *cls, size_t size, void *buf)
 {
+  struct PeerContext *p = cls;
   struct GNUNET_MessageHeader *hdr;
 
   struct GNUNET_MessageHeader *hdr;
 
+  th = NULL;
+
+  if (buf == NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Timeout occurred while waiting for transmit_ready\n");
+    if (GNUNET_SCHEDULER_NO_TASK != die_task)
+      GNUNET_SCHEDULER_cancel (die_task);
+    die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+    ok = 42;
+    return 0;
+  }
+
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Transmitting message to peer (%p) - %u!\n", cls, size);
+              "Transmitting message with %u bytes to peer %s\n",
+              sizeof (struct GNUNET_MessageHeader), GNUNET_i2s (&p->id));
   GNUNET_assert (size >= 256);
   GNUNET_assert (size >= 256);
-  GNUNET_assert ((ok >= 5) && (ok <= 6));
-  OKPP;
+
   if (buf != NULL)
   {
     hdr = buf;
     hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
     hdr->type = htons (MTYPE);
   }
   if (buf != NULL)
   {
     hdr = buf;
     hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
     hdr->type = htons (MTYPE);
   }
-
   return sizeof (struct GNUNET_MessageHeader);
 }
 
 
 static void
   return sizeof (struct GNUNET_MessageHeader);
 }
 
 
 static void
-exchange_hello_last (void *cls,
-                     const struct GNUNET_MessageHeader *message)
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+                const struct GNUNET_TRANSPORT_ATS_Information *ats,
+                uint32_t ats_count)
 {
 {
-  struct PeerContext *me = cls;
-
-  GNUNET_TRANSPORT_get_hello_cancel (p2.th, &exchange_hello_last, me);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Exchanging HELLO with peer (%p)!\n", cls);
-  GNUNET_assert (ok >= 3);
-  OKPP;
-  GNUNET_assert (message != NULL);
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
-                                      message, &me->id));
-
-  GNUNET_TRANSPORT_offer_hello (p1.th, message);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Finished exchanging HELLOs, now waiting for transmission!\n");
-
-  /* both HELLOs exchanged, get ready to test transmission! */
-  GNUNET_TRANSPORT_notify_transmit_ready (p1.th,
-                                          &p2.id,
-                                          256, 0, TIMEOUT, &notify_ready,
-                                          &p1);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n",
+              GNUNET_i2s (peer), cls);
 }
 
 
 static void
 }
 
 
 static void
-exchange_hello (void *cls,
-                const struct GNUNET_MessageHeader *message)
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
 {
 {
-  struct PeerContext *me = cls;
-
-  GNUNET_TRANSPORT_get_hello_cancel (p1.th, &exchange_hello, me);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Exchanging HELLO with peer (%p)!\n", cls);
-  GNUNET_assert (ok >= 2);
-  OKPP;
-  GNUNET_assert (message != NULL);
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
-                                      message, &me->id));
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received HELLO size %d\n", GNUNET_HELLO_size((const struct GNUNET_HELLO_Message *)message));
-
-  GNUNET_TRANSPORT_offer_hello (p2.th, message);
-
-  GNUNET_TRANSPORT_get_hello (p2.th, &exchange_hello_last, &p2);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' disconnected (%p)!\n",
+              GNUNET_i2s (peer), cls);
 }
 
 static void
 }
 
 static void
-setTransportOptions(char * filename)
+sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 {
-  struct GNUNET_CONFIGURATION_Handle * tempcfg;
-
-  tempcfg = GNUNET_CONFIGURATION_create();
-  GNUNET_CONFIGURATION_load (tempcfg, filename);
+  send_task = GNUNET_SCHEDULER_NO_TASK;
 
 
-  unsigned long long curr_port;
-  GNUNET_CONFIGURATION_get_value_number(tempcfg, "transport", "port", &curr_port);
+  if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+    return;
 
 
-  if (is_udp)
-    {
-      GNUNET_CONFIGURATION_set_value_string(tempcfg, "transport", "plugins", "udp");
-      GNUNET_CONFIGURATION_set_value_number(tempcfg, "transport-udp", "PORT", curr_port + 3);
-    }
-  else if (is_tcp)
-    {
-      GNUNET_CONFIGURATION_set_value_string(tempcfg, "transport", "plugins", "tcp");
-      GNUNET_CONFIGURATION_set_value_number(tempcfg, "transport-tcp", "port", curr_port + 3);
-    }
+  th = GNUNET_TRANSPORT_notify_transmit_ready (p1->th, &p2->id, 256, 0,
+                                               TIMEOUT_TRANSMIT, &notify_ready,
+                                               &p1);
+}
 
 
-#if VERBOSE_TRANSPORT
-      GNUNET_CONFIGURATION_set_value_string(tempcfg, "transport", "DEBUG", "YES");
-      GNUNET_CONFIGURATION_set_value_string(tempcfg, "transport", "PREFIX", "xterm -e xterm -T transport -e gdb --args");
-#else
-      GNUNET_CONFIGURATION_set_value_string(tempcfg, "transport", "DEBUG", "NO");
-      GNUNET_CONFIGURATION_set_value_string(tempcfg, "transport", "PREFIX", "");
-#endif
+static void
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
+{
+  cc = NULL;
+  char *p1_c = strdup (GNUNET_i2s (&p1->id));
 
 
-  GNUNET_CONFIGURATION_write(tempcfg, filename);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %s <-> %s\n", p1_c,
+              GNUNET_i2s (&p2->id));
+  GNUNET_free (p1_c);
 
 
-  GNUNET_CONFIGURATION_destroy(tempcfg);
-  return;
+  // FIXME: THIS IS REQUIRED! SEEMS TO BE A BUG!
+  send_task =
+      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &sendtask, NULL);
 }
 
 static void
 }
 
 static void
-run (void *cls,
-     struct GNUNET_SCHEDULER_Handle *s,
-     char *const *args,
-     const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
+run (void *cls, char *const *args, const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
 {
-  GNUNET_assert (ok == 1);
-  OKPP;
-  sched = s;
-
-  setTransportOptions("test_transport_api_peer1.conf");
-  setTransportOptions("test_transport_api_peer2.conf");
+  die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
 
 
-  die_task = GNUNET_SCHEDULER_add_delayed (sched,
-      GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 1), &end_badly, NULL);
+  p1 = GNUNET_TRANSPORT_TESTING_start_peer (cfg_file_p1, &notify_receive,
+                                            &notify_connect, &notify_disconnect,
+                                            NULL);
+  p2 = GNUNET_TRANSPORT_TESTING_start_peer (cfg_file_p2, &notify_receive,
+                                            &notify_connect, &notify_disconnect,
+                                            NULL);
 
 
-  setup_peer (&p1, "test_transport_api_peer1.conf");
-  setup_peer (&p2, "test_transport_api_peer2.conf");
+  if ((p1 == NULL) || (p2 == NULL))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
+    if (die_task != GNUNET_SCHEDULER_NO_TASK)
+      GNUNET_SCHEDULER_cancel (die_task);
+    die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+    return;
+  }
 
 
-  GNUNET_TRANSPORT_get_hello (p1.th, &exchange_hello, &p1);
+  cc = GNUNET_TRANSPORT_TESTING_connect_peers (p1, p2, &testing_connect_cb,
+                                               NULL);
 }
 
 }
 
+
 static int
 check ()
 {
 static int
 check ()
 {
-
-  char *const argv[] = { "test-transport-api",
+  static char *const argv[] = { "test-transport-api",
     "-c",
     "test_transport_api_data.conf",
 #if VERBOSE
     "-c",
     "test_transport_api_data.conf",
 #if VERBOSE
@@ -325,19 +276,19 @@ check ()
 #endif
     NULL
   };
 #endif
     NULL
   };
-
-  setTransportOptions("test_transport_api_data.conf");
-
-  struct GNUNET_GETOPT_CommandLineOption options[] = {
+  static struct GNUNET_GETOPT_CommandLineOption options[] = {
     GNUNET_GETOPT_OPTION_END
   };
 
     GNUNET_GETOPT_OPTION_END
   };
 
+#if WRITECONFIG
+  setTransportOptions ("test_transport_api_data.conf");
+#endif
+  send_task = GNUNET_SCHEDULER_NO_TASK;
+
   ok = 1;
   ok = 1;
-  GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
-                      argv, "test-transport-api", "nohelp",
-                      options, &run, &ok);
-  stop_arm (&p1);
-  stop_arm (&p2);
+  GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name,
+                      "nohelp", options, &run, &ok);
+
   return ok;
 }
 
   return ok;
 }
 
@@ -345,27 +296,52 @@ int
 main (int argc, char *argv[])
 {
   int ret;
 main (int argc, char *argv[])
 {
   int ret;
+  int nat_res;
 
 
-  if (strstr(argv[0], "tcp") != NULL)
-    {
-      is_tcp = GNUNET_YES;
-    }
-  else if (strstr(argv[0], "udp") != NULL)
-    {
-      is_udp = GNUNET_YES;
-    }
-
+  GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
+  GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
+                                                 &test_plugin);
+  GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
 
 
-  GNUNET_log_setup ("test-transport-api",
+  GNUNET_log_setup (test_name,
 #if VERBOSE
                     "DEBUG",
 #else
                     "WARNING",
 #endif
                     NULL);
 #if VERBOSE
                     "DEBUG",
 #else
                     "WARNING",
 #endif
                     NULL);
+
+  if ((strcmp (test_plugin, "tcp_nat") == 0) ||
+      (strcmp (test_plugin, "udp_nat") == 0))
+  {
+    nat_res = GNUNET_OS_check_helper_binary ("gnunet-nat-server");
+    if (GNUNET_NO == nat_res)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Cannot run NAT test: `%s' %s \n",
+                  "gnunet-nat-server", "SUID not set");
+      return 0;
+    }
+    if (GNUNET_SYSERR == nat_res)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Cannot run NAT test: `%s' %s \n",
+                  "gnunet-nat-server", "file not found");
+      return 0;
+    }
+  }
+
+  GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
+  GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
+
   ret = check ();
   ret = check ();
-  GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-1");
-  GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-transport-peer-2");
+
+  GNUNET_free (cfg_file_p1);
+  GNUNET_free (cfg_file_p2);
+
+  GNUNET_free (test_source);
+  GNUNET_free (test_plugin);
+  GNUNET_free (test_name);
+
+
   return ret;
 }
 
   return ret;
 }