test_transport_api_bidirectional_connect.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2009, 2010 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file transport/test_transport_api_bidirectional_connect.c
  19. * @brief base test case for transport implementations
  20. *
  21. * Perform a 3-way handshake connection set up in both directions at
  22. * (almost) the same time
  23. */
  24. #include "platform.h"
  25. #include "gnunet_transport_service.h"
  26. #include "transport-testing.h"
  27. /**
  28. * How long until we give up on transmitting the message?
  29. */
  30. #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
  31. /**
  32. * How long until we give up on transmitting the message?
  33. */
  34. #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
  35. #define MTYPE 12345
  36. static char *test_source;
  37. static char *test_plugin;
  38. static char *test_name;
  39. static int ok;
  40. static GNUNET_SCHEDULER_TaskIdentifier die_task;
  41. static GNUNET_SCHEDULER_TaskIdentifier send_task;
  42. static struct PeerContext *p1;
  43. static struct PeerContext *p2;
  44. static GNUNET_TRANSPORT_TESTING_ConnectRequest cc1;
  45. static GNUNET_TRANSPORT_TESTING_ConnectRequest cc2;
  46. static struct GNUNET_TRANSPORT_TransmitHandle *th;
  47. static struct GNUNET_TRANSPORT_TESTING_handle *tth;
  48. static char *cfg_file_p1;
  49. static char *cfg_file_p2;
  50. static void
  51. end ()
  52. {
  53. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
  54. if (send_task != GNUNET_SCHEDULER_NO_TASK)
  55. {
  56. GNUNET_SCHEDULER_cancel (send_task);
  57. send_task = GNUNET_SCHEDULER_NO_TASK;
  58. }
  59. if (die_task != GNUNET_SCHEDULER_NO_TASK)
  60. GNUNET_SCHEDULER_cancel (die_task);
  61. if (NULL != th)
  62. {
  63. GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
  64. th = NULL;
  65. }
  66. GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
  67. GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
  68. }
  69. static void
  70. end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  71. {
  72. die_task = GNUNET_SCHEDULER_NO_TASK;
  73. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
  74. if (send_task != GNUNET_SCHEDULER_NO_TASK)
  75. {
  76. GNUNET_SCHEDULER_cancel (send_task);
  77. send_task = GNUNET_SCHEDULER_NO_TASK;
  78. }
  79. if (NULL != cc2)
  80. {
  81. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n"));
  82. GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc2);
  83. cc2 = NULL;
  84. }
  85. if (NULL != cc1)
  86. {
  87. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n"));
  88. GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc1);
  89. cc1 = NULL;
  90. }
  91. if (NULL != th)
  92. {
  93. GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
  94. th = NULL;
  95. }
  96. if (p1 != NULL)
  97. GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
  98. if (p2 != NULL)
  99. GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
  100. ok = GNUNET_SYSERR;
  101. }
  102. static void
  103. notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
  104. const struct GNUNET_MessageHeader *message)
  105. {
  106. struct PeerContext *p = cls;
  107. struct PeerContext *t = NULL;
  108. if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
  109. t = p1;
  110. if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
  111. t = p2;
  112. GNUNET_assert (t != NULL);
  113. char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
  114. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  115. "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n",
  116. p->no, ps, ntohs (message->type), ntohs (message->size), t->no,
  117. GNUNET_i2s (&t->id));
  118. GNUNET_free (ps);
  119. if ((MTYPE == ntohs (message->type)) &&
  120. (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)))
  121. {
  122. ok = 0;
  123. end ();
  124. }
  125. else
  126. {
  127. GNUNET_break (0);
  128. ok = 1;
  129. end ();
  130. }
  131. }
  132. static size_t
  133. notify_ready (void *cls, size_t size, void *buf)
  134. {
  135. struct PeerContext *p = cls;
  136. struct GNUNET_MessageHeader *hdr;
  137. th = NULL;
  138. if (buf == NULL)
  139. {
  140. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  141. "Timeout occurred while waiting for transmit_ready\n");
  142. if (GNUNET_SCHEDULER_NO_TASK != die_task)
  143. GNUNET_SCHEDULER_cancel (die_task);
  144. die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
  145. ok = 42;
  146. return 0;
  147. }
  148. GNUNET_assert (size >= 256);
  149. if (buf != NULL)
  150. {
  151. hdr = buf;
  152. hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
  153. hdr->type = htons (MTYPE);
  154. }
  155. char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id));
  156. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  157. "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n",
  158. p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no,
  159. GNUNET_i2s (&p->id));
  160. GNUNET_free (ps);
  161. return sizeof (struct GNUNET_MessageHeader);
  162. }
  163. static void
  164. sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  165. {
  166. send_task = GNUNET_SCHEDULER_NO_TASK;
  167. if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
  168. return;
  169. char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id));
  170. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  171. "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n",
  172. p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s);
  173. GNUNET_free (receiver_s);
  174. th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256,
  175. TIMEOUT_TRANSMIT, &notify_ready,
  176. p1);
  177. }
  178. static void
  179. notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
  180. {
  181. static int c;
  182. c++;
  183. GNUNET_assert (NULL != cls);
  184. struct PeerContext *p = cls;
  185. struct PeerContext *t = NULL;
  186. if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
  187. t = p1;
  188. if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
  189. t = p2;
  190. GNUNET_assert (t != NULL);
  191. char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
  192. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  193. "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps,
  194. t->no, GNUNET_i2s (peer));
  195. GNUNET_free (ps);
  196. }
  197. static void
  198. notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
  199. {
  200. struct PeerContext *p = cls;
  201. char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
  202. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  203. "Peer %u (`%4s'): peer (`%s') disconnected from me!\n",
  204. p->no, ps,
  205. GNUNET_i2s (peer));
  206. GNUNET_free (ps);
  207. if (GNUNET_SCHEDULER_NO_TASK != send_task)
  208. {
  209. GNUNET_SCHEDULER_cancel(send_task);
  210. GNUNET_break (0);
  211. send_task = GNUNET_SCHEDULER_NO_TASK;
  212. }
  213. if (NULL != th)
  214. {
  215. GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
  216. th = NULL;
  217. }
  218. }
  219. static void
  220. testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
  221. {
  222. static int connected = GNUNET_NO;
  223. if ((cls == cc1) && (NULL != cc2))
  224. {
  225. GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc2);
  226. }
  227. if ((cls == cc2) && (NULL != cc1))
  228. {
  229. GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc1);
  230. }
  231. cc1 = NULL;
  232. cc2 = NULL;
  233. if (connected > 0)
  234. return;
  235. connected ++;
  236. char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
  237. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n",
  238. p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
  239. GNUNET_free (p1_c);
  240. send_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &sendtask, NULL);
  241. }
  242. static void
  243. start_cb (struct PeerContext *p, void *cls)
  244. {
  245. static int started;
  246. started++;
  247. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  248. "Peer %u (`%s') started\n",
  249. p->no,
  250. GNUNET_i2s (&p->id));
  251. if (started != 2)
  252. return;
  253. char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
  254. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  255. "Test tries to connect peer %u (`%s') <-> peer %u (`%s')\n",
  256. p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id));
  257. GNUNET_free (sender_c);
  258. cc1 =
  259. GNUNET_TRANSPORT_TESTING_connect_peers (tth, p2, p1, &testing_connect_cb,
  260. cc1);
  261. cc2 =
  262. GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
  263. cc2);
  264. }
  265. static void
  266. run (void *cls, char *const *args, const char *cfgfile,
  267. const struct GNUNET_CONFIGURATION_Handle *cfg)
  268. {
  269. die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
  270. p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
  271. &notify_receive, &notify_connect,
  272. &notify_disconnect, &start_cb,
  273. NULL);
  274. p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
  275. &notify_receive, &notify_connect,
  276. &notify_disconnect, &start_cb,
  277. NULL);
  278. if ((p1 == NULL) || (p2 == NULL))
  279. {
  280. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
  281. if (die_task != GNUNET_SCHEDULER_NO_TASK)
  282. GNUNET_SCHEDULER_cancel (die_task);
  283. die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
  284. return;
  285. }
  286. }
  287. static int
  288. check ()
  289. {
  290. static char *const argv[] = { "test-transport-api",
  291. "-c",
  292. "test_transport_api_data.conf",
  293. NULL
  294. };
  295. static struct GNUNET_GETOPT_CommandLineOption options[] = {
  296. GNUNET_GETOPT_OPTION_END
  297. };
  298. #if WRITECONFIG
  299. setTransportOptions ("test_transport_api_data.conf");
  300. #endif
  301. send_task = GNUNET_SCHEDULER_NO_TASK;
  302. ok = 1;
  303. GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name,
  304. "nohelp", options, &run, &ok);
  305. return ok;
  306. }
  307. int
  308. main (int argc, char *argv[])
  309. {
  310. int ret;
  311. GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
  312. GNUNET_log_setup (test_name,
  313. "WARNING",
  314. NULL);
  315. GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
  316. GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
  317. &test_plugin);
  318. tth = GNUNET_TRANSPORT_TESTING_init ();
  319. GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
  320. GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
  321. ret = check ();
  322. GNUNET_free (cfg_file_p1);
  323. GNUNET_free (cfg_file_p2);
  324. GNUNET_free (test_source);
  325. GNUNET_free (test_plugin);
  326. GNUNET_free (test_name);
  327. GNUNET_TRANSPORT_TESTING_done (tth);
  328. return ret;
  329. }
  330. /* end of test_transport_api_bidirectional_connect.c */