- fix error messages
[oweals/gnunet.git] / src / transport / test_transport_api_monitoring.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @file transport/test_transport_api.c
22  * @brief base test case for transport implementations
23  *
24  * This test case serves as a base for tcp, udp, and udp-nat
25  * transport test cases.  Based on the executable being run
26  * the correct test case will be performed.  Conservation of
27  * C code apparently.
28  */
29 #include "platform.h"
30 #include "gnunet_transport_service.h"
31 #include "transport-testing.h"
32
33 /**
34  * How long until we give up on transmitting the message?
35  */
36 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
37
38 /**
39  * How long until we give up on transmitting the message?
40  */
41 #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
42
43 #define TEST_MESSAGE_SIZE 2600
44
45 #define TEST_MESSAGE_TYPE 12345
46
47 static char *test_source;
48
49 static char *test_plugin;
50
51 static char *test_name;
52
53 static int ok;
54
55 static int s_started;
56
57 static int s_connected;
58
59 static int s_sending;
60
61 static GNUNET_SCHEDULER_TaskIdentifier die_task;
62
63 static GNUNET_SCHEDULER_TaskIdentifier send_task;
64
65 static struct PeerContext *p1;
66
67 static struct PeerContext *p2;
68
69 static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
70
71 static struct GNUNET_TRANSPORT_TransmitHandle *th;
72
73 static struct GNUNET_TRANSPORT_TESTING_handle *tth;
74
75 static char *cfg_file_p1;
76
77 static char *cfg_file_p2;
78
79 static struct GNUNET_TRANSPORT_PeerMonitoringContext *pmc_p1;
80
81 static struct GNUNET_TRANSPORT_PeerMonitoringContext *pmc_p2;
82
83 static int p1_c = GNUNET_NO;
84
85 static int p2_c = GNUNET_NO;
86
87
88 static void
89 end ()
90 {
91   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping peers\n");
92
93
94   if (send_task != GNUNET_SCHEDULER_NO_TASK)
95     GNUNET_SCHEDULER_cancel (send_task);
96
97   if (die_task != GNUNET_SCHEDULER_NO_TASK)
98     GNUNET_SCHEDULER_cancel (die_task);
99
100   if (th != NULL)
101     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
102   th = NULL;
103
104   if (NULL != pmc_p1)
105   {
106     GNUNET_TRANSPORT_monitor_peers_cancel (pmc_p1);
107     pmc_p1 = NULL;
108   }
109   if (NULL != pmc_p2)
110   {
111     GNUNET_TRANSPORT_monitor_peers_cancel (pmc_p2);
112     pmc_p2 = NULL;
113   }
114
115   GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
116   p1 = NULL;
117   GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
118   p2 = NULL;
119
120   ok = 0;
121 }
122
123 static void
124 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
125 {
126   die_task = GNUNET_SCHEDULER_NO_TASK;
127
128   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Fail! Stopping peers\n");
129
130
131   if (send_task != GNUNET_SCHEDULER_NO_TASK)
132     GNUNET_SCHEDULER_cancel (send_task);
133
134   if (cc != NULL)
135   {
136     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n"));
137     GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
138     cc = NULL;
139   }
140
141   if (th != NULL)
142     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
143   else
144     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were not ready to send data\n"));
145
146   if (s_started == GNUNET_NO)
147     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peers were not started \n"));
148   else
149     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peers were started \n"));
150
151   if (s_connected == GNUNET_NO)
152     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were not connected\n"));
153   else
154     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were connected\n"));
155
156   if (s_sending == GNUNET_NO)
157     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were not ready to send data\n"));
158   else
159     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were ready to send data\n"));
160
161   th = NULL;
162
163   if (NULL != pmc_p1)
164   {
165     GNUNET_TRANSPORT_monitor_peers_cancel (pmc_p1);
166     pmc_p1 = NULL;
167   }
168   if (NULL != pmc_p2)
169   {
170     GNUNET_TRANSPORT_monitor_peers_cancel (pmc_p2);
171     pmc_p2 = NULL;
172   }
173
174   if (p1 != NULL)
175     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
176   else
177     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer 1 was not started\n"));
178   if (p2 != NULL)
179     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
180   else
181     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer 2 was not started\n"));
182
183   ok = GNUNET_SYSERR;
184 }
185
186
187 static void
188 notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
189                 const struct GNUNET_MessageHeader *message)
190 {
191   struct PeerContext *p = cls;
192   struct PeerContext *t = NULL;
193
194   if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
195     t = p1;
196   if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
197     t = p2;
198   GNUNET_assert (t != NULL);
199
200   char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
201
202   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
203               "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n",
204               p->no, ps, ntohs (message->type), ntohs (message->size), t->no,
205               GNUNET_i2s (&t->id));
206   GNUNET_free (ps);
207 }
208
209
210 static size_t
211 notify_ready (void *cls, size_t size, void *buf)
212 {
213   struct PeerContext *p = cls;
214   struct GNUNET_MessageHeader *hdr;
215
216   th = NULL;
217
218   if (buf == NULL)
219   {
220     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
221                 "Timeout occurred while waiting for transmit_ready\n");
222     if (GNUNET_SCHEDULER_NO_TASK != die_task)
223       GNUNET_SCHEDULER_cancel (die_task);
224     die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
225     ok = 42;
226     return 0;
227   }
228
229   GNUNET_assert (size >= TEST_MESSAGE_SIZE);
230   if (buf != NULL)
231   {
232     memset (buf, '\0', TEST_MESSAGE_SIZE);
233     hdr = buf;
234     hdr->size = htons (TEST_MESSAGE_SIZE);
235     hdr->type = htons (TEST_MESSAGE_TYPE);
236   }
237
238   char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id));
239   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
240               "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n",
241               p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no,
242               GNUNET_i2s (&p->id));
243   GNUNET_free (ps);
244
245   return TEST_MESSAGE_SIZE;
246 }
247
248
249 static void
250 sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
251 {
252   send_task = GNUNET_SCHEDULER_NO_TASK;
253
254   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
255     return;
256   char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id));
257
258   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
259               "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n",
260               p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s);
261   GNUNET_free (receiver_s);
262   s_sending = GNUNET_YES;
263   th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, TEST_MESSAGE_SIZE, 0,
264                                                TIMEOUT_TRANSMIT, &notify_ready,
265                                                p1);
266 }
267
268
269 static void
270 notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
271 {
272   static int c;
273
274   c++;
275   struct PeerContext *p = cls;
276   struct PeerContext *t = NULL;
277
278   if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
279     t = p1;
280   if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
281     t = p2;
282   GNUNET_assert (t != NULL);
283
284   char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
285
286   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
287               "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps,
288               t->no, GNUNET_i2s (peer));
289   GNUNET_free (ps);
290 }
291
292
293 static void
294 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
295 {
296   struct PeerContext *p = cls;
297   char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
298
299   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
300               "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps,
301               GNUNET_i2s (peer));
302
303   GNUNET_free (ps);
304
305   if (th != NULL)
306     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
307   th = NULL;
308 }
309
310
311 static void
312 testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
313 {
314   cc = NULL;
315   char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
316
317   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peers connected: %u (%s) <-> %u (%s)\n",
318               p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
319   GNUNET_free (p1_c);
320
321   s_connected = GNUNET_YES;
322   send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL);
323 }
324
325
326 static void
327 start_cb (struct PeerContext *p, void *cls)
328 {
329   static int started;
330
331   started++;
332
333   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer %u (`%s') started\n", p->no,
334               GNUNET_i2s (&p->id));
335
336   if (started != 2)
337     return;
338   else
339     s_started = GNUNET_YES;
340   char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
341
342   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
343               "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
344               p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id));
345   GNUNET_free (sender_c);
346
347   cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
348                                                NULL);
349
350 }
351
352 static void done ()
353 {
354   if ((GNUNET_YES == p1_c) && (GNUNET_YES == p2_c))
355   {
356     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Both peers state to be connected\n");
357     ok = 0;
358     end();
359   }
360 }
361
362 static void monitor1_cb (void *cls,
363                         const struct GNUNET_PeerIdentity *peer,
364                         const struct GNUNET_HELLO_Address *address,
365                         enum GNUNET_TRANSPORT_PeerState state,
366                         struct GNUNET_TIME_Absolute state_timeout)
367 {
368   if ((NULL == peer) || (NULL == p1))
369     return;
370
371   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Monitor 1: %s %s %s\n",
372       GNUNET_i2s (peer), GNUNET_TRANSPORT_p2s(state), GNUNET_STRINGS_absolute_time_to_string(state_timeout));
373   if ((0 == memcmp (peer, &p2->id, sizeof (p2->id)) &&
374       (GNUNET_YES == GNUNET_TRANSPORT_is_connected(state)) &&
375       GNUNET_NO == p1_c) )
376   {
377     p1_c = GNUNET_YES;
378     GNUNET_SCHEDULER_add_now (&done, NULL);
379   }
380
381 }
382
383
384 static void monitor2_cb (void *cls,
385                         const struct GNUNET_PeerIdentity *peer,
386                         const struct GNUNET_HELLO_Address *address,
387                         enum GNUNET_TRANSPORT_PeerState state,
388                         struct GNUNET_TIME_Absolute state_timeout)
389 {
390   if ((NULL == peer) || (NULL == p2))
391     return;
392
393   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Monitor 2: %s %s %s\n",
394       GNUNET_i2s (peer), GNUNET_TRANSPORT_p2s (state), GNUNET_STRINGS_absolute_time_to_string(state_timeout));
395   if ((0 == memcmp (peer, &p1->id, sizeof (p1->id)) &&
396       (GNUNET_YES == GNUNET_TRANSPORT_is_connected(state)) &&
397       GNUNET_NO == p2_c) )
398   {
399     p2_c = GNUNET_YES;
400     GNUNET_SCHEDULER_add_now (&done, NULL);
401   }
402 }
403
404
405
406 static void
407 run (void *cls, char *const *args, const char *cfgfile,
408      const struct GNUNET_CONFIGURATION_Handle *cfg)
409 {
410   die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
411
412   s_started = GNUNET_NO;
413   s_connected = GNUNET_NO;
414   s_sending = GNUNET_NO;
415
416   p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
417                                             &notify_receive, &notify_connect,
418                                             &notify_disconnect, &start_cb,
419                                             NULL);
420   pmc_p1 = GNUNET_TRANSPORT_monitor_peers (p1->cfg, NULL, GNUNET_NO, GNUNET_TIME_UNIT_FOREVER_REL, &monitor1_cb, NULL);
421
422   p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
423                                             &notify_receive, &notify_connect,
424                                             &notify_disconnect, &start_cb,
425                                             NULL);
426   pmc_p2 = GNUNET_TRANSPORT_monitor_peers (p2->cfg, NULL, GNUNET_NO, GNUNET_TIME_UNIT_FOREVER_REL, &monitor2_cb, NULL);
427
428   if ((p1 == NULL) || (p2 == NULL))
429   {
430     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
431     if (die_task != GNUNET_SCHEDULER_NO_TASK)
432       GNUNET_SCHEDULER_cancel (die_task);
433     die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
434     return;
435   }
436 }
437
438
439 static int
440 check ()
441 {
442   static char *const argv[] = { "test-transport-api",
443     "-c",
444     "test_transport_api_data.conf",
445     NULL
446   };
447   static struct GNUNET_GETOPT_CommandLineOption options[] = {
448     GNUNET_GETOPT_OPTION_END
449   };
450
451   send_task = GNUNET_SCHEDULER_NO_TASK;
452
453   ok = 1;
454   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name,
455                       "nohelp", options, &run, &ok);
456
457   return ok;
458 }
459
460 int
461 main (int argc, char *argv[])
462 {
463   int ret;
464
465   ok = 1;
466
467   GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
468   GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
469   GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
470                                                  &test_plugin);
471
472   GNUNET_log_setup (test_name,
473                     "WARNING",
474                     NULL);
475   tth = GNUNET_TRANSPORT_TESTING_init ();
476
477   GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
478   GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
479
480   ret = check ();
481
482   GNUNET_free (cfg_file_p1);
483   GNUNET_free (cfg_file_p2);
484
485   GNUNET_free (test_source);
486   GNUNET_free (test_plugin);
487   GNUNET_free (test_name);
488
489   GNUNET_TRANSPORT_TESTING_done (tth);
490
491   if (0 != ret)
492     return ret;
493   else
494     return ok;
495 }
496
497 /* end of test_transport_api.c */