(no commit message)
[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_common.h"
29 #include "gnunet_constants.h"
30 #include "gnunet_util_lib.h"
31 #include "gnunet_hello_lib.h"
32 #include "gnunet_peerinfo_service.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_protocols.h"
35 #include "gnunet_signatures.h"
36 #include "gnunet_transport_plugin.h"
37
38 #include "transport.h"
39
40 /**
41  * How long until we give up on transmitting the message?
42  */
43 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
44
45 /**
46  * Our public key.
47  */
48 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
49
50 /**
51  * Our identity.
52  */
53 static struct GNUNET_PeerIdentity my_identity;
54
55 /**
56  * Our private key.
57  */
58 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
59
60 /**
61  * Our configuration.
62  */
63 const struct GNUNET_CONFIGURATION_Handle *cfg;
64
65 /**
66  * Our configuration.
67  */
68 struct GNUNET_STATISTICS_Handle *stats;
69
70 /**
71  * Number of neighbours we'd like to have.
72  */
73 static uint32_t max_connect_per_transport;
74
75 /**
76  * Environment for this plugin.
77  */
78 struct GNUNET_TRANSPORT_PluginEnvironment env;
79
80 /**
81  *handle for the api provided by this plugin
82  */
83 struct GNUNET_TRANSPORT_PluginFunctions *api;
84
85 /**
86  * Timeout task
87  */
88 static GNUNET_SCHEDULER_TaskIdentifier timeout_task;
89
90 /**
91  * Library name
92  */
93 static char *libname;
94
95 struct AddressWrapper *head;
96 struct AddressWrapper *tail;
97
98 /**
99  * Did the test pass or fail?
100  */
101 static int ok;
102
103
104 struct AddressWrapper
105 {
106   struct AddressWrapper *next;
107
108   struct AddressWrapper *prev;
109
110   void *addr;
111
112   size_t addrlen;
113 };
114
115 static void
116 end ()
117 {
118   if (NULL != head)
119   {
120
121   }
122
123   if (GNUNET_SCHEDULER_NO_TASK != timeout_task)
124   {
125       GNUNET_SCHEDULER_cancel (timeout_task);
126       timeout_task = GNUNET_SCHEDULER_NO_TASK;
127   }
128
129   if (NULL != api)
130   {
131       GNUNET_PLUGIN_unload (libname, api);
132   }
133   GNUNET_free (libname);
134   libname = NULL;
135   GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
136   stats = NULL;
137
138   ok = 0;
139 }
140
141 static void
142
143 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
144 {
145   struct AddressWrapper *w;
146   int c = 0;
147
148   timeout_task = GNUNET_SCHEDULER_NO_TASK;
149   if (NULL != libname)
150   {
151     if (NULL != api)
152       GNUNET_PLUGIN_unload (libname, api);
153     GNUNET_free (libname);
154     libname = NULL;
155   }
156
157   w = head;
158   while (NULL != head)
159   {
160       GNUNET_CONTAINER_DLL_remove (head, tail, w);
161       c ++;
162       GNUNET_free (w->addr);
163       GNUNET_free (w);
164   }
165   if (c > 0)
166   {
167     GNUNET_break (0);
168     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
169               _("Plugin did not remove %u addresses \n"), c);
170   }
171
172   if (NULL != stats)
173   {
174     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
175     stats = NULL;
176   }
177
178   ok = 1;
179 }
180
181
182 static void
183 end_badly_now ()
184 {
185   if (GNUNET_SCHEDULER_NO_TASK != timeout_task)
186   {
187       GNUNET_SCHEDULER_cancel (timeout_task);
188       timeout_task = GNUNET_SCHEDULER_NO_TASK;
189   }
190   timeout_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
191 }
192
193
194 static struct GNUNET_TIME_Relative
195 env_receive (void *cls,
196             const struct GNUNET_PeerIdentity *peer,
197             const struct GNUNET_MessageHeader *message,
198             const struct GNUNET_ATS_Information *ats,
199             uint32_t ats_count,
200             struct Session * session,
201             const char *sender_address,
202             uint16_t sender_address_len)
203 {
204   /* do nothing */
205   GNUNET_break (0);
206   return GNUNET_TIME_relative_get_zero_();
207 }
208
209
210 static void
211 env_notify_address (void *cls,
212                     int add_remove,
213                     const void *addr,
214                     size_t addrlen)
215 {
216   struct AddressWrapper *w;
217   char *a2s;
218   void *s2a;
219   size_t s2a_len;
220
221   if (GNUNET_YES == add_remove)
222   {
223       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
224                   _("Adding address of length %u\n"), addrlen);
225
226       w = GNUNET_malloc (sizeof (struct AddressWrapper));
227       w->addr = GNUNET_malloc (addrlen);
228       w->addrlen = addrlen;
229       memcpy (w->addr, addr, addrlen);
230       GNUNET_CONTAINER_DLL_insert(head, tail, w);
231
232       a2s = strdup (api->address_to_string (api, w->addr, w->addrlen));
233       if (NULL == a2s)
234       {
235           GNUNET_break (0);
236           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
237                       _("Plugin cannot convert address to string!\n"));
238           end_badly_now();
239           return;
240       }
241
242       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
243                   _("Plugin added address `%s'\n"), a2s);
244
245       if (GNUNET_OK != api->string_to_address (api, a2s, strlen (a2s)+1, &s2a, &s2a_len))
246       {
247           GNUNET_break (0);
248           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
249                       _("Plugin cannot convert string to address!\n"));
250           end_badly_now();
251           return;
252       }
253
254       if (s2a_len != w->addrlen)
255       {
256           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
257                       _("Plugin creates different address length when converting address->string->address: %u != %u\n"), w->addrlen, s2a_len);
258       }
259       else
260       {
261           if (0 != memcmp (s2a, w->addr, s2a_len))
262             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
263                         _("Plugin creates different address length when connecting back and forth!\n"));
264       }
265
266       if (GNUNET_OK != api->check_address (api->cls, w->addr, w->addrlen))
267       {
268           GNUNET_break (0);
269           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
270                       _("Plugin refuses added address!\n"));
271           end_badly_now();
272           return;
273       }
274   }
275   else if (GNUNET_NO == add_remove)
276   {
277       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
278                   _("Removing address of length %u\n"), addrlen);
279
280       w = head;
281       while (NULL != w)
282       {
283           if ((addrlen == w->addrlen) && (0 == memcmp (w->addr, addr, addrlen)))
284           {
285             break;
286           }
287           w = w->next;
288       }
289
290       if (w == NULL)
291       {
292           GNUNET_break (0);
293           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
294                       _("Plugin removes address never added!\n"));
295           end_badly_now();
296           return;
297       }
298
299       GNUNET_CONTAINER_DLL_remove (head, tail, w);
300       GNUNET_free (w->addr);
301       GNUNET_free (w);
302   }
303   else
304   {
305       GNUNET_break (0);
306       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
307                   _("Invalid operation\n"));
308       end_badly_now ();
309   }
310 }
311
312 struct GNUNET_ATS_Information
313 env_get_address_type (void *cls,
314                      const struct sockaddr *addr,
315                      size_t addrlen)
316 {
317   struct GNUNET_ATS_Information ats;
318   ats.type = htonl (0);
319   ats.value = htonl (0);
320   return ats;
321 }
322
323
324 const struct GNUNET_MessageHeader *
325 env_get_our_hello (void)
326 {
327   GNUNET_break (0);
328   return NULL;
329 }
330
331 void env_session_end (void *cls,
332                       const struct GNUNET_PeerIdentity *peer,
333                       struct Session * session)
334 {
335
336 }
337
338 static void
339 setup_plugin_environment ()
340 {
341   env.cfg = cfg;
342   env.cls = &env;
343   env.my_identity = &my_identity;
344   env.max_connections = max_connect_per_transport;
345   env.stats = stats;
346
347   env.receive = &env_receive;
348   env.notify_address = &env_notify_address;
349   env.get_address_type = &env_get_address_type;
350   env.get_our_hello = &env_get_our_hello;
351   env.session_end = &env_session_end;
352 }
353
354
355 /**
356  * Runs the test.
357  *
358  * @param cls closure
359  * @param c configuration to use
360  */
361 static void
362 run (void *cls, char *const *args, const char *cfgfile,
363      const struct GNUNET_CONFIGURATION_Handle *c)
364 {
365   char *const *argv = cls;
366   unsigned long long tneigh;
367   char *keyfile;
368   char *plugin;
369   char *sep;
370
371   timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, end_badly, NULL);
372
373   cfg = c;
374   /* parse configuration */
375   if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (c,
376                           "TRANSPORT",
377                           "NEIGHBOUR_LIMIT",
378                           &tneigh)) ||
379       (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c,
380                           "GNUNETD", "HOSTKEY",
381                           &keyfile)))
382   {
383     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
384                 _("Transport service is lacking key configuration settings.  Exiting.\n"));
385
386     return;
387   }
388
389   stats = GNUNET_STATISTICS_create ("transport", cfg);
390   if (NULL == stats)
391   {
392       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
393                   _("Could not create statistics.  Exiting.\n"));
394       end_badly_now ();
395       return;
396   }
397
398   max_connect_per_transport = (uint32_t) tneigh;
399   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
400   GNUNET_free (keyfile);
401   if (my_private_key == NULL)
402   {
403     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
404                 _("Transport service could not access hostkey.  Exiting.\n"));
405     end_badly_now ();
406     return;
407   }
408   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
409   GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
410                       &my_identity.hashPubKey);
411
412   /* load plugins... */
413   setup_plugin_environment ();
414
415   plugin = strrchr(argv[0],'_');
416   sep = strrchr(argv[0],'.');
417   if (NULL == plugin)
418   {
419       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Not a valid test name\n"));
420       end_badly_now ();
421       return;
422   }
423   plugin++;
424   if (NULL != sep)
425       sep[0] = '\0';
426
427   /* Loading plugin */
428   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading transport plugin %s\n"), plugin);
429   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", plugin);
430   api = GNUNET_PLUGIN_load (libname, &env);
431   if (api == NULL)
432   {
433     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
434                 _("Failed to load transport plugin for tcp\n"));
435     end_badly_now ();
436     return;
437   }
438
439   /* Check if all functions are implemented */
440   if (NULL == api->address_pretty_printer)
441   {
442       GNUNET_break (0);
443       end_badly_now ();
444       return;
445   }
446   if (NULL == api->address_to_string)
447   {
448       GNUNET_break (0);
449       end_badly_now ();
450       return;
451   }
452   GNUNET_assert (NULL != api->check_address);
453   if (NULL == api->check_address)
454   {
455       GNUNET_break (0);
456       end_badly_now ();
457       return;
458   }
459   GNUNET_assert (NULL != api->disconnect);
460   if (NULL == api->disconnect)
461   {
462       GNUNET_break (0);
463       end_badly_now ();
464       return;
465   }
466   GNUNET_assert (NULL != api->get_session);
467   if (NULL == api->get_session)
468   {
469       GNUNET_break (0);
470       end_badly_now ();
471       return;
472   }
473   if (NULL == api->address_pretty_printer)
474   {
475       GNUNET_break (0);
476       end_badly_now ();
477       return;
478   }
479   if (NULL == api->string_to_address)
480   {
481       GNUNET_break (0);
482       end_badly_now ();
483       return;
484   }
485 }
486
487
488 /**
489  * The main function for the transport service.
490  *
491  * @param argc number of arguments from the command line
492  * @param argv command line arguments
493  * @return 0 ok, 1 on error
494  */
495 int
496 main (int argc, char *const *argv)
497 {
498   static struct GNUNET_GETOPT_CommandLineOption options[] = {
499     GNUNET_GETOPT_OPTION_END
500   };
501   int ret;
502
503   char *const argv_prog[] = {
504     "test_plugin_transport",
505     "-c",
506     "test_plugin_transport_data.conf",
507     "-L", "WARNING",
508     NULL
509   };
510   GNUNET_log_setup ("test-plugin-transport",
511                     "WARNING",
512                     NULL);
513   ok = 1;                       /* set to fail */
514   ret = (GNUNET_OK == GNUNET_PROGRAM_run (5,
515                            argv_prog,
516                            "test-plugin-transport",
517                            "testcase",
518                            options,
519                            &run,
520                            (void *) argv)) ? ok : 1;
521   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-plugin-transport");
522   return ret;
523 }
524
525 /* end of test_plugin_transport.c */