fixing unchecked return values
[oweals/gnunet.git] / src / transport / test_plugin_transport.c
1 /*
2  This file is part of GNUnet.
3  (C) 2009 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_plugin_transport.c
22  * @brief testcase for transport_api.c
23  * @author Sailor Siraj
24  * @author Christian Grothoff
25  */
26
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_hello_lib.h"
30 #include "gnunet_peerinfo_service.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_transport_plugin.h"
34 #include "transport.h"
35
36 /**
37  * How long until we give up on transmitting the message?
38  */
39 #define WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
40 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
41
42 #define HOSTKEY_FILE "test_plugin_hostkey.ecc"
43
44 /**
45  * Our public key.
46  */
47 static struct GNUNET_PeerIdentity my_identity;
48
49 /**
50  * Our private key.
51  */
52 static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
53
54 /**
55  * Our configuration.
56  */
57 const struct GNUNET_CONFIGURATION_Handle *cfg;
58
59 /**
60  * Our configuration.
61  */
62 struct GNUNET_STATISTICS_Handle *stats;
63
64 /**
65  * Our HELLO
66  */
67 struct GNUNET_HELLO_Message *hello;
68
69 /**
70  * Number of neighbours we'd like to have.
71  */
72 static uint32_t max_connect_per_transport;
73
74 /**
75  * Environment for this plugin.
76  */
77 struct GNUNET_TRANSPORT_PluginEnvironment env;
78
79 /**
80  *handle for the api provided by this plugin
81  */
82 struct GNUNET_TRANSPORT_PluginFunctions *api;
83
84 /**
85  * Helper handler
86  */
87 struct GNUNET_HELPER_Handle *suid_helper;
88
89 /**
90  * Timeout task
91  */
92 static GNUNET_SCHEDULER_TaskIdentifier timeout_endbadly;
93
94 /**
95  * Timeout task
96  */
97 static GNUNET_SCHEDULER_TaskIdentifier timeout_wait;
98
99 /**
100  * Library name
101  */
102 static char *libname;
103
104 /**
105  * Plugin addresses head
106  */
107 struct AddressWrapper *head;
108
109 /**
110  * Plugin addresses tail
111  */
112 struct AddressWrapper *tail;
113
114 unsigned int addresses_reported;
115
116 unsigned int pretty_printers_running;
117
118 /**
119  * Did the test pass or fail?
120  */
121 static int ok;
122
123 struct AddressWrapper
124 {
125   struct AddressWrapper *next;
126
127   struct AddressWrapper *prev;
128
129   struct GNUNET_HELLO_Address *address;
130
131   char *addrstring;
132 };
133
134 static void
135 end ()
136 {
137   struct AddressWrapper *w;
138   int c = 0;
139   ok = 0;
140
141   if (GNUNET_SCHEDULER_NO_TASK != timeout_endbadly)
142   {
143     GNUNET_SCHEDULER_cancel (timeout_endbadly);
144     timeout_endbadly = GNUNET_SCHEDULER_NO_TASK;
145   }
146   if (NULL != api)
147     GNUNET_PLUGIN_unload (libname, api);
148
149   while (NULL != head)
150   {
151     w = head;
152     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Plugin did not remove address `%s'\n",
153         w->addrstring);
154     GNUNET_CONTAINER_DLL_remove(head, tail, w);
155     c++;
156     GNUNET_HELLO_address_free(w->address);
157     GNUNET_free(w->addrstring);
158     GNUNET_free(w);
159   }
160   if (c > 0)
161   {
162     GNUNET_break(0);
163     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Plugin did not remove %u addresses \n",
164         c);
165     ok = 1;
166   }
167
168   GNUNET_free(libname);
169   libname = NULL;
170   GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
171   stats = NULL;
172
173   if (NULL != suid_helper)
174   {
175     GNUNET_HELPER_stop (suid_helper, GNUNET_NO);
176     suid_helper = NULL;
177   }
178 }
179
180 static void
181 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
182 {
183   struct AddressWrapper *w;
184   int c = 0;
185
186   timeout_endbadly = GNUNET_SCHEDULER_NO_TASK;
187   if (GNUNET_SCHEDULER_NO_TASK != timeout_wait)
188   {
189     GNUNET_SCHEDULER_cancel (timeout_wait);
190     timeout_wait = GNUNET_SCHEDULER_NO_TASK;
191   }
192
193   if (pretty_printers_running > 0)
194   {
195     timeout_endbadly = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
196         &end_badly, &ok);
197     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
198         "Have pending calls to pretty_printer ... deferring shutdown\n");
199     return;
200   }
201
202   if (NULL != cls)
203   {
204     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
205         "Test took too long to execute, timeout .... \n");
206   }
207
208   if (NULL != libname)
209   {
210     if (NULL != api)
211       GNUNET_PLUGIN_unload (libname, api);
212     GNUNET_free(libname);
213     libname = NULL;
214   }
215
216   while (NULL != head)
217   {
218     w = head;
219     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Plugin did not remove address `%s'\n",
220         w->addrstring);
221     GNUNET_CONTAINER_DLL_remove(head, tail, w);
222     c++;
223     GNUNET_HELLO_address_free(w->address);
224     GNUNET_free(w->addrstring);
225     GNUNET_free(w);
226   }
227   if (c > 0)
228   {
229     GNUNET_break(0);
230     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Plugin did not remove %u addresses\n",
231         c);
232   }
233
234   if (NULL != stats)
235   {
236     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
237     stats = NULL;
238   }
239
240   if (NULL != suid_helper)
241   {
242     GNUNET_HELPER_stop (suid_helper, GNUNET_NO);
243     suid_helper = NULL;
244   }
245
246   ok = 1;
247 }
248
249 static void
250 wait_end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
251 {
252   timeout_wait = GNUNET_SCHEDULER_NO_TASK;
253   if (0 == addresses_reported)
254     GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
255         "Plugin did not report any addresses, could not check address conversion functions\n");
256   end ();
257 }
258
259 static void
260 end_badly_now ()
261 {
262   if (GNUNET_SCHEDULER_NO_TASK != timeout_wait)
263   {
264     GNUNET_SCHEDULER_cancel (timeout_wait);
265     timeout_wait = GNUNET_SCHEDULER_NO_TASK;
266   }
267   if (GNUNET_SCHEDULER_NO_TASK != timeout_endbadly)
268   {
269     GNUNET_SCHEDULER_cancel (timeout_endbadly);
270     timeout_endbadly = GNUNET_SCHEDULER_NO_TASK;
271   }
272   timeout_endbadly = GNUNET_SCHEDULER_add_now (&end_badly, NULL );
273 }
274
275 static struct GNUNET_TIME_Relative
276 env_receive (void *cls,
277     const struct GNUNET_HELLO_Address *address,
278     struct Session *session,
279     const struct GNUNET_MessageHeader *message)
280 {
281   /* do nothing */
282   return GNUNET_TIME_relative_get_zero_ ();
283 }
284
285 static int got_reply;
286
287 /**
288  * Take the given address and append it to the set of results sent back to
289  * the client.
290  *
291  * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
292  * @param buf text to transmit
293  */
294 static void
295 address_pretty_printer_cb (void *cls, const char *buf)
296 {
297   if (NULL != buf)
298   {
299     got_reply = GNUNET_YES;
300     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Pretty address : `%s'\n", buf);
301     pretty_printers_running--;
302   }
303   else
304   {
305     if (GNUNET_NO == got_reply)
306     {
307       pretty_printers_running--;
308       GNUNET_break(0);
309       end_badly_now ();
310     }
311   }
312 }
313
314 static void
315 env_notify_address (void *cls, int add_remove,
316     const struct GNUNET_HELLO_Address *address)
317 {
318   struct AddressWrapper *w;
319   struct AddressWrapper *wtmp;
320   void *s2a;
321   size_t s2a_len;
322
323   if (GNUNET_YES == add_remove)
324   {
325     addresses_reported++;
326     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Adding address of length %u\n",
327         address->address_length);
328
329     for (wtmp = head; NULL != wtmp; wtmp = wtmp->next)
330     {
331       if ((address->address_length == wtmp->address->address_length) &&
332           (0 == memcmp (address->address, wtmp->address->address, address->address_length)))
333       {
334         GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
335             "Duplicate address notification .... \n");
336         return;
337       }
338     }
339
340     w = GNUNET_new (struct AddressWrapper);
341     w->address = GNUNET_HELLO_address_copy (address);
342     GNUNET_CONTAINER_DLL_insert(head, tail, w);
343     got_reply = GNUNET_NO;
344     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Testing: address_to_string \n");
345     w->addrstring = strdup (
346         api->address_to_string (api, w->address->address,
347             w->address->address_length));
348     if (NULL == w->addrstring)
349     {
350       GNUNET_break(0);
351       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
352           "Plugin cannot convert address to string!\n");
353       end_badly_now ();
354       return;
355     }
356     else
357     {
358       GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Plugin added address `%s'\n",
359           w->addrstring);
360       GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Testing address_to_string: OK\n");
361     }
362
363     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Testing: string_to_address \n");
364     s2a = NULL;
365     s2a_len = 0;
366     if ((GNUNET_OK
367         != api->string_to_address (api, w->addrstring,
368             strlen (w->addrstring) + 1, &s2a, &s2a_len)) || (NULL == s2a))
369     {
370       GNUNET_break(0);
371       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
372           "Plugin cannot convert string to address!\n");
373       end_badly_now ();
374       return;
375     }
376
377     /*
378      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
379      "Plugin creates `%s' %u\n",api->address_to_string (api, s2a, s2a_len), s2a_len);
380
381      int c1;
382      for (c1 = 0; c1 < s2a_len; c1++ )
383      fprintf (stderr, "%u == %u\n", ((char *) s2a)[c1], ((char *) w->addr)[c1]);
384      */
385     if (s2a_len != w->address->address_length)
386     {
387       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
388           "Plugin creates different address length when converting address->string->address: %u != %u\n",
389           w->address->address_length, s2a_len);
390     }
391     else if (0 != memcmp (s2a, w->address->address, s2a_len))
392     {
393       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
394           "Plugin creates different address length when converting back and forth %i!\n",
395           memcmp (s2a, w->address->address, s2a_len));
396     }
397     else
398     {
399       GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Testing string_to_address: OK\n");
400     }
401     GNUNET_free(s2a);
402
403     pretty_printers_running++;
404     api->address_pretty_printer (api->cls, address->transport_name, address->address, address->address_length, GNUNET_YES,
405         GNUNET_TIME_UNIT_MINUTES, &address_pretty_printer_cb, w);
406
407     if (GNUNET_OK != api->check_address (api->cls, w->address->address, w->address->address_length))
408     {
409       GNUNET_break(0);
410       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Plugin refuses added address!\n");
411       end_badly_now ();
412       return;
413     }
414     if (GNUNET_SCHEDULER_NO_TASK != timeout_wait)
415     {
416       GNUNET_SCHEDULER_cancel (timeout_wait);
417       timeout_wait = GNUNET_SCHEDULER_NO_TASK;
418     }
419
420     timeout_wait = GNUNET_SCHEDULER_add_delayed (WAIT, &wait_end, NULL );
421
422   }
423   else if (GNUNET_NO == add_remove)
424   {
425     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Removing address of length %u\n",
426         address->address_length);
427
428     w = head;
429     while (NULL != w)
430     {
431       if ((address->address_length == w->address->address_length) &&
432           (0 == memcmp (w->address->address, address->address, address->address_length)))
433       {
434         break;
435       }
436       w = w->next;
437     }
438
439     if (w == NULL )
440     {
441       GNUNET_break(0);
442       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
443           "Plugin removes address never added!\n");
444       end_badly_now ();
445       return;
446     }
447
448     GNUNET_CONTAINER_DLL_remove(head, tail, w);
449     GNUNET_HELLO_address_free (w->address);
450     GNUNET_free(w->addrstring);
451     GNUNET_free(w);
452   }
453   else
454   {
455     GNUNET_break(0);
456     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Invalid operation: %u\n", add_remove);
457     end_badly_now ();
458     return;
459   }
460 }
461
462 static struct GNUNET_ATS_Information
463 env_get_address_type (void *cls, const struct sockaddr *addr, size_t addrlen)
464 {
465   struct GNUNET_ATS_Information ats;
466   ats.type = htonl (GNUNET_ATS_NETWORK_TYPE);
467   ats.value = htonl (GNUNET_ATS_NET_LOOPBACK);
468   return ats;
469 }
470
471 static const struct GNUNET_MessageHeader *
472 env_get_our_hello ()
473 {
474   return (const struct GNUNET_MessageHeader *) hello;
475 }
476
477 static void
478 env_session_end (void *cls,
479                  const struct GNUNET_HELLO_Address *address,
480                  struct Session *session)
481 {
482
483 }
484
485 static void
486 env_update_metrics (void *cls,
487     const struct GNUNET_HELLO_Address *address,
488     struct Session *session,
489     const struct GNUNET_ATS_Information *ats,
490     uint32_t ats_count)
491 {
492 }
493
494 static void
495 setup_plugin_environment ()
496 {
497   env.cfg = cfg;
498   env.cls = &env;
499   env.my_identity = &my_identity;
500   env.max_connections = max_connect_per_transport;
501   env.stats = stats;
502   env.receive = &env_receive;
503   env.notify_address = &env_notify_address;
504   env.get_address_type = &env_get_address_type;
505   env.update_address_metrics = &env_update_metrics;
506   env.get_our_hello = &env_get_our_hello;
507   env.session_end = &env_session_end;
508 }
509
510 static int
511 handle_helper_message (void *cls, void *client,
512     const struct GNUNET_MessageHeader *hdr)
513 {
514   return GNUNET_OK;
515 }
516
517 /**
518  * Runs the test.
519  *
520  * @param cls closure
521  * @param c configuration to use
522  */
523 static void
524 run (void *cls, char * const *args, const char *cfgfile,
525     const struct GNUNET_CONFIGURATION_Handle *c)
526 {
527   char * const *argv = cls;
528   unsigned long long tneigh;
529   char *keyfile;
530   char *plugin;
531   char *sep;
532
533   timeout_endbadly = GNUNET_SCHEDULER_add_delayed (TIMEOUT, end_badly, &ok);
534
535   cfg = c;
536   /* parse configuration */
537   if ((GNUNET_OK
538       != GNUNET_CONFIGURATION_get_value_number (c, "TRANSPORT",
539           "NEIGHBOUR_LIMIT", &tneigh))
540       || (GNUNET_OK
541           != GNUNET_CONFIGURATION_get_value_filename (c, "PEER", "PRIVATE_KEY",
542               &keyfile)))
543   {
544     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
545         "Transport service is lacking key configuration settings.  Exiting.\n");
546     return;
547   }
548
549   if (NULL == (stats = GNUNET_STATISTICS_create ("transport", cfg)))
550   {
551     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
552         "Could not create statistics.  Exiting.\n");
553     GNUNET_free(keyfile);
554     end_badly_now ();
555     return;
556   }
557
558   if (GNUNET_OK != GNUNET_DISK_file_test (HOSTKEY_FILE))
559   {
560     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Hostkey `%s' missing.  Exiting.\n",
561         HOSTKEY_FILE);
562     GNUNET_free(keyfile);
563     end_badly_now ();
564     return;
565   }
566
567   if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (keyfile))
568   {
569     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
570         "Could not create a directory for hostkey `%s'.  Exiting.\n", keyfile);
571     GNUNET_free(keyfile);
572     end_badly_now ();
573     return;
574   }
575
576   if (GNUNET_OK != GNUNET_DISK_file_copy (HOSTKEY_FILE, keyfile))
577   {
578     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
579         "Could not copy hostkey `%s' to destination `%s'.  Exiting.\n",
580         HOSTKEY_FILE, keyfile);
581     GNUNET_free(keyfile);
582     end_badly_now ();
583     return;
584   }
585
586   max_connect_per_transport = (uint32_t) tneigh;
587   my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile);
588   GNUNET_free(keyfile);
589   if (NULL == my_private_key)
590   {
591     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
592         "Could not access hostkey.  Exiting.\n");
593     end_badly_now ();
594     return;
595   }
596   GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
597
598   hello = GNUNET_HELLO_create (&my_identity.public_key, NULL, NULL, GNUNET_NO);
599
600   /* load plugins... */
601   setup_plugin_environment ();
602
603   GNUNET_assert(strlen (argv[0]) > strlen ("test_plugin_"));
604   plugin = strstr (argv[0], "test_plugin_");
605   sep = strrchr (argv[0], '.');
606   if (NULL == plugin)
607   {
608     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Not a valid test name\n");
609     end_badly_now ();
610     return;
611   }
612   plugin += strlen ("test_plugin_");
613   if (NULL != sep)
614     sep[0] = '\0';
615
616   /* Hack for WLAN: start a second helper */
617   if (0 == strcmp (plugin, "wlan"))
618   {
619     char * helper_argv[3];
620     helper_argv[0] = (char *) "gnunet-helper-transport-wlan-dummy";
621     helper_argv[1] = (char *) "2";
622     helper_argv[2] = NULL;
623     suid_helper = GNUNET_HELPER_start (GNUNET_NO,
624         "gnunet-helper-transport-wlan-dummy", helper_argv,
625         &handle_helper_message, NULL, NULL );
626   }
627
628   /* Loading plugin */
629   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Loading transport plugin %s\n", plugin);
630   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", plugin);
631   api = GNUNET_PLUGIN_load (libname, &env);
632   if (api == NULL )
633   {
634     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
635         "Failed to load transport plugin for %s\n", plugin);
636     end_badly_now ();
637     return;
638   }
639
640   timeout_wait = GNUNET_SCHEDULER_add_delayed (WAIT, &wait_end, NULL );
641
642   /* Check if all functions are implemented */
643   if (NULL == api->address_pretty_printer)
644   {
645     GNUNET_break(0);
646     end_badly_now ();
647     return;
648   }
649   if (NULL == api->address_to_string)
650   {
651     GNUNET_break(0);
652     end_badly_now ();
653     return;
654   }
655   GNUNET_assert(NULL != api->check_address);
656   if (NULL == api->check_address)
657   {
658     GNUNET_break(0);
659     end_badly_now ();
660     return;
661   }
662   GNUNET_assert(NULL != api->disconnect_peer);
663   if (NULL == api->disconnect_peer)
664   {
665     GNUNET_break(0);
666     end_badly_now ();
667     return;
668   }
669   GNUNET_assert(NULL != api->get_session);
670   if (NULL == api->get_session)
671   {
672     GNUNET_break(0);
673     end_badly_now ();
674     return;
675   }
676   if (NULL == api->address_pretty_printer)
677   {
678     GNUNET_break(0);
679     end_badly_now ();
680     return;
681   }
682   if (NULL == api->string_to_address)
683   {
684     GNUNET_break(0);
685     end_badly_now ();
686     return;
687   }
688
689 }
690
691 /**
692  * The main function for the test
693  *
694  * @param argc number of arguments from the command line
695  * @param argv command line arguments
696  * @return 0 ok, 1 on error
697  */
698 int
699 main (int argc, char * const *argv)
700 {
701   static struct GNUNET_GETOPT_CommandLineOption options[] = {
702       GNUNET_GETOPT_OPTION_END };
703   int ret;
704
705   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-plugin-transport");
706
707   char * const argv_prog[] = { "test_plugin_transport", "-c",
708       "test_plugin_transport_data.conf", NULL };
709   GNUNET_log_setup ("test-plugin-transport", "WARNING", NULL );
710   ok = 1; /* set to fail */
711   ret =
712       (GNUNET_OK
713           == GNUNET_PROGRAM_run (3, argv_prog, "test-plugin-transport",
714               "testcase", options, &run, (void *) argv)) ? ok : 1;
715   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-plugin-transport");
716   return ret;
717 }
718
719 /* end of test_plugin_transport.c */