transport testing:
[oweals/gnunet.git] / src / transport / test_transport_api_restart_2peers.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_restart_2peers.c
22  * @brief base test case for transport implementations
23  *
24  * This test case starts 2 peers, connects and exchanges a message
25  * boths peer are restarted and tested if peers reconnect
26  * C code apparently.
27  */
28 #include "platform.h"
29 #include "gnunet_common.h"
30 #include "gnunet_hello_lib.h"
31 #include "gnunet_getopt_lib.h"
32 #include "gnunet_os_lib.h"
33 #include "gnunet_program_lib.h"
34 #include "gnunet_scheduler_lib.h"
35 #include "gnunet_transport_service.h"
36 #include "transport.h"
37 #include "transport-testing.h"
38
39 #define VERBOSE GNUNET_EXTRA_LOGGING
40 #define VERBOSE_ARM GNUNET_EXTRA_LOGGING
41
42 #define START_ARM GNUNET_YES
43
44 /**
45  * How long until we give up on transmitting the message?
46  */
47 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
48
49 /**
50  * How long until we give up on transmitting the message?
51  */
52 #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
53
54 #define MTYPE 12345
55
56 static char *test_source;
57
58 static char *test_plugin;
59
60 static char *test_name;
61
62 static int ok;
63
64 static GNUNET_SCHEDULER_TaskIdentifier die_task;
65
66 static GNUNET_SCHEDULER_TaskIdentifier send_task;
67
68 struct PeerContext *p1;
69
70 struct PeerContext *p2;
71
72 static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
73
74 struct GNUNET_TRANSPORT_TransmitHandle *th;
75
76 struct GNUNET_TRANSPORT_TESTING_handle *tth;
77
78 char *cfg_file_p1;
79
80 char *cfg_file_p2;
81
82 static int restarted;
83
84 #if VERBOSE
85 #define OKPP do { ok++; fprintf (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
86 #else
87 #define OKPP do { ok++; } while (0)
88 #endif
89
90
91 static void
92 end ()
93 {
94   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
95
96   if (send_task != GNUNET_SCHEDULER_NO_TASK)
97     GNUNET_SCHEDULER_cancel (send_task);
98
99   if (die_task != GNUNET_SCHEDULER_NO_TASK)
100     GNUNET_SCHEDULER_cancel (die_task);
101
102   if (th != NULL)
103     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
104   th = NULL;
105
106   GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
107   GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
108 }
109
110 static void
111 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
112 {
113   die_task = GNUNET_SCHEDULER_NO_TASK;
114
115   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
116
117   if (restarted == GNUNET_YES)
118     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers were restarted\n");
119
120   if (restarted == GNUNET_NO)
121     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers were NOT restarted\n");
122
123   if (send_task != GNUNET_SCHEDULER_NO_TASK)
124     GNUNET_SCHEDULER_cancel (send_task);
125
126   if (cc != NULL)
127   {
128     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n"));
129     GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
130     cc = NULL;
131   }
132
133   if (th != NULL)
134     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
135   th = NULL;
136
137   if (p1 != NULL)
138     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
139   if (p2 != NULL)
140     GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
141
142   ok = GNUNET_SYSERR;
143 }
144
145 static
146 void restart (struct PeerContext *p , char * cfg_file)
147 {
148   GNUNET_assert (p != NULL);
149   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
150               "Restarting peer %u (`%4s')\n",
151               p->no,
152               GNUNET_i2s (&p->id));
153   GNUNET_TRANSPORT_TESTING_restart_peer (tth, p, cfg_file);
154   return;
155 }
156
157 static void
158 notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
159                 const struct GNUNET_MessageHeader *message,
160                 const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
161 {
162   struct PeerContext *p = cls;
163   struct PeerContext *t = NULL;
164
165   if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
166     t = p1;
167   if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
168     t = p2;
169   GNUNET_assert (t != NULL);
170
171   char *ps = strdup (GNUNET_i2s (&p->id));
172
173   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
174               "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n",
175               p->no, ps, ntohs (message->type), ntohs (message->size), t->no,
176               GNUNET_i2s (&t->id));
177
178   if ((MTYPE == ntohs (message->type)) &&
179       (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)))
180   {
181     restarted = GNUNET_YES;
182     restart (p1, cfg_file_p1);
183     restart (p2, cfg_file_p2);
184   }
185   else
186   {
187     GNUNET_break (0);
188     ok = 1;
189     if (die_task != GNUNET_SCHEDULER_NO_TASK)
190       GNUNET_SCHEDULER_cancel (die_task);
191     die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
192   }
193 }
194
195
196 static size_t
197 notify_ready (void *cls, size_t size, void *buf)
198 {
199   struct PeerContext *p = cls;
200   struct GNUNET_MessageHeader *hdr;
201
202   th = NULL;
203
204   if (buf == NULL)
205   {
206     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
207                 "Timeout occurred while waiting for transmit_ready\n");
208     if (GNUNET_SCHEDULER_NO_TASK != die_task)
209       GNUNET_SCHEDULER_cancel (die_task);
210     die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
211     ok = 42;
212     return 0;
213   }
214
215   GNUNET_assert (size >= 256);
216
217   if (buf != NULL)
218   {
219     hdr = buf;
220     hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
221     hdr->type = htons (MTYPE);
222   }
223   char *ps = strdup (GNUNET_i2s (&p2->id));
224
225   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
226               "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n",
227               p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no,
228               GNUNET_i2s (&p->id));
229   GNUNET_free (ps);
230   return sizeof (struct GNUNET_MessageHeader);
231 }
232
233
234 static void
235 sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
236 {
237   send_task = GNUNET_SCHEDULER_NO_TASK;
238
239   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
240     return;
241   char *receiver_s = strdup (GNUNET_i2s (&p1->id));
242
243   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
244               "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n",
245               p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s);
246   GNUNET_free (receiver_s);
247
248   th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256, 0,
249                                                TIMEOUT_TRANSMIT, &notify_ready,
250                                                p1);
251 }
252
253
254 static void
255 notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
256                 const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
257 {
258   static int c;
259
260   c++;
261   struct PeerContext *p = cls;
262   struct PeerContext *t = NULL;
263
264   if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
265     t = p1;
266   if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
267     t = p2;
268   GNUNET_assert (t != NULL);
269
270   char *ps = strdup (GNUNET_i2s (&p->id));
271
272   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
273               "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps,
274               t->no, GNUNET_i2s (peer));
275   GNUNET_free (ps);
276
277   if ((restarted == GNUNET_YES) && (c == 4))
278     end ();
279 }
280
281
282 static void
283 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
284 {
285   struct PeerContext *p = cls;
286   char *ps = strdup (GNUNET_i2s (&p->id));
287
288   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
289               "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps,
290               GNUNET_i2s (peer));
291
292   if (th != NULL)
293     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
294   th = NULL;
295 }
296
297 static void
298 testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
299 {
300   cc = NULL;
301   char *p1_c = strdup (GNUNET_i2s (&p1->id));
302
303   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n",
304               p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
305   GNUNET_free (p1_c);
306
307   send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL);
308 }
309
310
311
312 void
313 start_cb (struct PeerContext *p, void *cls)
314 {
315   static int started;
316
317   started++;
318
319   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
320               GNUNET_i2s (&p->id));
321
322   if (started != 2)
323     return;
324
325   char *sender_c = strdup (GNUNET_i2s (&p1->id));
326
327   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
328               "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
329               p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id));
330
331   cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
332                                                NULL);
333
334 }
335
336 static void
337 run (void *cls, char *const *args, const char *cfgfile,
338      const struct GNUNET_CONFIGURATION_Handle *cfg)
339 {
340   die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
341
342   p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
343                                             &notify_receive, &notify_connect,
344                                             &notify_disconnect, &start_cb,
345                                             NULL);
346
347   p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
348                                             &notify_receive, &notify_connect,
349                                             &notify_disconnect, &start_cb,
350                                             NULL);
351
352   if ((p1 == NULL) || (p2 == NULL))
353   {
354     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
355     if (die_task != GNUNET_SCHEDULER_NO_TASK)
356       GNUNET_SCHEDULER_cancel (die_task);
357     die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
358     return;
359   }
360 }
361
362
363 static int
364 check ()
365 {
366   static char *const argv[] = { "test-transport-api",
367     "-c",
368     "test_transport_api_data.conf",
369 #if VERBOSE
370     "-L", "DEBUG",
371 #endif
372     NULL
373   };
374   static struct GNUNET_GETOPT_CommandLineOption options[] = {
375     GNUNET_GETOPT_OPTION_END
376   };
377
378 #if WRITECONFIG
379   setTransportOptions ("test_transport_api_data.conf");
380 #endif
381   send_task = GNUNET_SCHEDULER_NO_TASK;
382
383   ok = 1;
384   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name,
385                       "nohelp", options, &run, &ok);
386
387   return ok;
388 }
389
390 int
391 main (int argc, char *argv[])
392 {
393   int ret;
394   int nat_res;
395
396   GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
397   GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
398   GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
399                                                  &test_plugin);
400
401   GNUNET_log_setup (test_name,
402 #if VERBOSE
403                     "DEBUG",
404 #else
405                     "WARNING",
406 #endif
407                     NULL);
408
409   tth = GNUNET_TRANSPORT_TESTING_init ();
410
411   if ((strcmp (test_plugin, "tcp_nat") == 0) ||
412       (strcmp (test_plugin, "udp_nat") == 0))
413   {
414     nat_res = GNUNET_OS_check_helper_binary ("gnunet-nat-server");
415     if (GNUNET_NO == nat_res)
416     {
417       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Cannot run NAT test: `%s' %s \n",
418                   "gnunet-nat-server", "SUID not set");
419       return 0;
420     }
421     if (GNUNET_SYSERR == nat_res)
422     {
423       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Cannot run NAT test: `%s' %s \n",
424                   "gnunet-nat-server", "file not found");
425       return 0;
426     }
427   }
428
429   GNUNET_asprintf(&cfg_file_p1,"test_transport_api_tcp_peer1.conf");
430   GNUNET_asprintf(&cfg_file_p2,"test_transport_api_tcp_peer2.conf");
431
432
433   ret = check ();
434
435   GNUNET_free (cfg_file_p1);
436   GNUNET_free (cfg_file_p2);
437
438   GNUNET_free (test_source);
439   GNUNET_free (test_plugin);
440   GNUNET_free (test_name);
441
442   GNUNET_TRANSPORT_TESTING_done (tth);
443
444   return ret;
445 }
446
447 /* end of test_transport_api_restart_2peers.c */