binding to specific address
[oweals/gnunet.git] / src / transport / test_transport_api.c
index 7ce02c757749ab7596de288a87ec6e6bfef1bc41..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
 
 /**
  * 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, 30)
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
 
 
-#define MTYPE 12345
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
 
 
-struct PeerContext
-{
-  struct GNUNET_CONFIGURATION_Handle *cfg;
-  struct GNUNET_TRANSPORT_Handle *th;
-  struct GNUNET_PeerIdentity id;
-#if START_ARM
-  pid_t arm_pid;
-#endif
-};
+#define MTYPE 12345
 
 
-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;
+
+struct PeerContext *p1;
+
+struct PeerContext *p2;
 
 
-static int is_udp;
+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)
@@ -76,222 +89,186 @@ static int is_udp;
 static void
 end ()
 {
 static void
 end ()
 {
-  /* do work here */
-  GNUNET_assert (ok == 8);
-  GNUNET_TRANSPORT_disconnect (p1.th);
-  GNUNET_TRANSPORT_disconnect (p2.th);
-  ok = 0;
-}
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
 
 
+  if (send_task != GNUNET_SCHEDULER_NO_TASK)
+    GNUNET_SCHEDULER_cancel (send_task);
 
 
-/**
- * Function called by the transport for each received message.
- *
- * @param cls closure
- * @param latency estimated latency for communicating with the
- *             given peer
- * @param peer (claimed) identity of the other peer
- * @param message the message
- */
-static void
-notify_receive (void *cls,
-                struct GNUNET_TIME_Relative latency,
-                const struct GNUNET_PeerIdentity *peer,
-                const struct GNUNET_MessageHeader *message)
-{
-  GNUNET_assert (ok == 7);
-  OKPP;
-  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 ();
-}
+  if (die_task != GNUNET_SCHEDULER_NO_TASK)
+    GNUNET_SCHEDULER_cancel (die_task);
 
 
+  if (th != NULL)
+    GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+  th = NULL;
 
 
-/**
- * Function called to notify transport users that another
- * peer connected to us.
- *
- * @param cls closure
- * @param transport the transport service handle
- * @param peer the peer that disconnected
- * @param latency current latency of the connection
- */
-static void
-notify_connect (void *cls,
-                const struct GNUNET_PeerIdentity *peer,
-                struct GNUNET_TIME_Relative latency)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Peer `%4s' connected to us (%p)!\n", GNUNET_i2s (peer), cls);
-  GNUNET_assert ((ok >= 1) && (ok <= 6));
-  OKPP;
+  GNUNET_TRANSPORT_TESTING_stop_peer (p1);
+  GNUNET_TRANSPORT_TESTING_stop_peer (p2);
 }
 
 }
 
-
-/**
- * Function called to notify transport users that another
- * peer disconnected from us.
- *
- * @param cls closure
- * @param transport the transport service handle
- * @param peer the peer that disconnected
- */
 static void
 static void
-notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 {
-  ok--;
+  die_task = GNUNET_SCHEDULER_NO_TASK;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
+
+  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);
+  }
+
+  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));
-
-  p->th = GNUNET_TRANSPORT_connect (sched, p->cfg,
-                                    p,
-                                    &notify_receive,
-                                    &notify_connect, &notify_disconnect);
-  GNUNET_assert (p->th != NULL);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received message of type %d from peer %s!\n",
+              ntohs (message->type), GNUNET_i2s (peer));
+
+  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;
-  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,
-                     struct GNUNET_TIME_Relative latency,
-                     const struct GNUNET_PeerIdentity *peer,
-                     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_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,
-                struct GNUNET_TIME_Relative latency,
-                const struct GNUNET_PeerIdentity *peer,
-                const struct GNUNET_MessageHeader *message)
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
 {
 {
-  struct PeerContext *me = cls;
-
-  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_TRANSPORT_get_hello (p2.th, TIMEOUT, &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;
+  send_task = GNUNET_SCHEDULER_NO_TASK;
 
 
-  tempcfg = GNUNET_CONFIGURATION_create();
-  GNUNET_CONFIGURATION_load (tempcfg, filename);
+  if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+    return;
 
 
-  unsigned long long curr_port;
-  GNUNET_CONFIGURATION_get_value_number(tempcfg, "transport", "port", &curr_port);
-
-  if (is_udp)
-    {
-      fprintf(stderr, "setting transport udp plugins\n");
-      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);
-    }
-  GNUNET_CONFIGURATION_write(tempcfg, filename);
-  return;
+  th = GNUNET_TRANSPORT_notify_transmit_ready (p1->th, &p2->id, 256, 0,
+                                               TIMEOUT_TRANSMIT, &notify_ready,
+                                               &p1);
 }
 
 static void
 }
 
 static void
-run (void *cls,
-     struct GNUNET_SCHEDULER_Handle *s,
-     char *const *args,
-     const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
 {
 {
-  GNUNET_assert (ok == 1);
-  OKPP;
-  sched = s;
+  cc = NULL;
+  char *p1_c = strdup (GNUNET_i2s (&p1->id));
 
 
-  setTransportOptions("test_transport_api_peer1.conf");
-  setTransportOptions("test_transport_api_peer2.conf");
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %s <-> %s\n", p1_c,
+              GNUNET_i2s (&p2->id));
+  GNUNET_free (p1_c);
 
 
-  setup_peer (&p1, "test_transport_api_peer1.conf");
-  setup_peer (&p2, "test_transport_api_peer2.conf");
-  GNUNET_TRANSPORT_get_hello (p1.th, TIMEOUT, &exchange_hello, &p1);
+  // 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
-stop_arm (struct PeerContext *p)
+run (void *cls, char *const *args, const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
 {
-#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);
+  die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &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);
+
+  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;
+  }
+
+  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
@@ -299,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;
 }
 
@@ -319,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;
 }