cd22226f141dc8ca2bc775dfdca1886868150b66
[oweals/gnunet.git] / src / hostlist / test_gnunet_daemon_hostlist_learning.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 2, 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 hostlist/test_gnunet_daemon_hostlist.c
22  * @brief test for gnunet_daemon_hostslist.c
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_arm_service.h"
28 #include "gnunet_core_service.h"
29 #include "gnunet_transport_service.h"
30 #include "gnunet_resolver_service.h"
31 #include "gnunet_statistics_service.h"
32
33 #define VERBOSE GNUNET_YES
34
35 #define START_ARM GNUNET_YES
36 #define MAX_URL_LEN 1000
37
38 /**
39  * How long until wait until testcases fails
40  */
41 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
42 #define CHECK_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
43
44 static int timeout;
45 static int adv_sent;
46
47 static int adv_arrived_p1;
48 static int learned_hostlist_saved_p1;
49 static int learned_hostlist_downloaded_p1;
50
51 static int adv_arrived_p2;
52 static int learned_hostlist_saved_p2;
53 static int learned_hostlist_downloaded_p2;
54
55 static char * current_adv_uri;
56
57 static struct GNUNET_SCHEDULER_Handle *sched;
58
59 static GNUNET_SCHEDULER_TaskIdentifier timeout_task;
60 static GNUNET_SCHEDULER_TaskIdentifier check_task;
61     
62 struct PeerContext
63 {
64   struct GNUNET_CONFIGURATION_Handle *cfg;
65   struct GNUNET_TRANSPORT_Handle *th;
66   struct GNUNET_MessageHeader *hello;
67   struct GNUNET_ARM_Handle *arm;
68   struct GNUNET_CORE_Handle *core;
69   struct GNUNET_STATISTICS_Handle *stats;
70 #if START_ARM
71   pid_t arm_pid;
72 #endif
73 };
74
75 static struct PeerContext adv_peer;
76
77 static struct PeerContext learn_peer;
78
79 static struct PeerContext learn_peer2;
80
81
82 static void
83 waitpid_task (void *cls,
84               const struct GNUNET_SCHEDULER_TaskContext *tc)
85 {
86   struct PeerContext *p = cls;
87
88 #if START_ARM
89   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
90               "Killing ARM process.\n");
91   if (0 != PLIBC_KILL (p->arm_pid, SIGTERM))
92     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
93   if (GNUNET_OS_process_wait(p->arm_pid) != GNUNET_OK)
94     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
95   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
96               "ARM process %u stopped\n", p->arm_pid);
97 #endif
98   GNUNET_CONFIGURATION_destroy (p->cfg);
99 }
100
101
102 static void
103 stop_cb (void *cls,
104          int success)
105 {
106   struct PeerContext *p = cls;
107
108   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
109               success
110               ? "ARM stopped core service\n"
111               : "ARM failed to stop core service\n");
112   GNUNET_ARM_disconnect (p->arm);
113   p->arm = NULL;
114   /* make sure this runs after all other tasks are done */
115   GNUNET_SCHEDULER_add_delayed (sched,
116                                 GNUNET_TIME_UNIT_SECONDS,
117                                 &waitpid_task, p);
118 }
119
120
121 static void shutdown_testcase()
122 {
123   if (timeout_task != GNUNET_SCHEDULER_NO_TASK)
124   {
125     GNUNET_SCHEDULER_cancel (sched,
126                              timeout_task);
127     timeout_task = GNUNET_SCHEDULER_NO_TASK;
128   }
129   if (check_task != GNUNET_SCHEDULER_NO_TASK)
130   {
131     GNUNET_SCHEDULER_cancel (sched,
132         check_task);
133     check_task = GNUNET_SCHEDULER_NO_TASK;
134   }
135   if ( NULL != current_adv_uri ) GNUNET_free (current_adv_uri);
136
137   if (adv_peer.th != NULL)
138   {
139     GNUNET_TRANSPORT_disconnect (adv_peer.th);
140     adv_peer.th = NULL;
141   }
142   if (learn_peer.th != NULL)
143   {
144     GNUNET_TRANSPORT_disconnect (learn_peer.th);
145     learn_peer.th = NULL;
146   }
147   /*
148   if (learn_peer2.th != NULL)
149   {
150     GNUNET_TRANSPORT_disconnect (learn_peer2.th);
151     learn_peer2.th = NULL;
152   }*/
153   if (adv_peer.core != NULL)
154   {
155     GNUNET_CORE_disconnect (adv_peer.core);
156     adv_peer.core = NULL;
157   }
158   if (learn_peer.core != NULL)
159   {
160     GNUNET_CORE_disconnect (learn_peer.core);
161     learn_peer.core = NULL;
162   }
163   /*
164   if (learn_peer2.core != NULL)
165   {
166     GNUNET_CORE_disconnect (learn_peer2.core);
167     learn_peer2.core = NULL;
168   }*/
169   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
170               "Asking ARM to stop core services\n");
171   learn_peer.arm = GNUNET_ARM_connect (learn_peer.cfg, sched, NULL);
172   GNUNET_ARM_stop_service (learn_peer.arm, "core", GNUNET_TIME_UNIT_SECONDS,
173                            &stop_cb, &learn_peer);
174   /* learn_peer2.arm = GNUNET_ARM_connect (learn_peer2.cfg, sched, NULL);
175   GNUNET_ARM_stop_service (learn_peer2.arm, "core", GNUNET_TIME_UNIT_SECONDS,
176                            &stop_cb, &learn_peer2);*/
177   adv_peer.arm = GNUNET_ARM_connect (adv_peer.cfg, sched, NULL);
178   GNUNET_ARM_stop_service (adv_peer.arm, "core", GNUNET_TIME_UNIT_SECONDS,
179                            &stop_cb, &adv_peer);
180
181   GNUNET_SCHEDULER_shutdown (sched);
182 }
183
184 /**
185  * Timeout, give up.
186  */
187 static void
188 timeout_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
189 {
190   timeout_task = GNUNET_SCHEDULER_NO_TASK;
191   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
192               "Timeout while executing testcase, test failed.\n");
193   timeout = GNUNET_YES;
194   shutdown_testcase();
195 }
196
197 static int
198 process_downloads (void *cls,
199               const char *subsystem,
200               const char *name,
201               uint64_t value,
202               int is_persistent)
203 {
204
205
206   if ( ((struct PeerContext *) cls == &learn_peer) && (value == 2) && (learned_hostlist_downloaded_p1 == GNUNET_NO) )
207   {
208     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
209                 _("Peer1 has successfully downloaded advertised URI \n"));
210     learned_hostlist_downloaded_p1 = GNUNET_YES;
211   }
212   /*
213   if ( ((struct PeerContext *) cls == &learn_peer2) && (value == 2) && (learned_hostlist_downloaded_p2 == GNUNET_NO) )
214   {
215     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
216                 _("Peer2 has successfully downloaded advertised URI \n"));
217     learned_hostlist_downloaded_p2 = GNUNET_YES;
218   }*/
219   if ( (GNUNET_NO != learned_hostlist_downloaded_p1) /*&& (GNUNET_NO != learned_hostlist_downloaded_p2)*/ )
220     shutdown_testcase();
221   return GNUNET_OK;
222 }
223
224 static int
225 process_uris_recv (void *cls,
226               const char *subsystem,
227               const char *name,
228               uint64_t value,
229               int is_persistent)
230 {
231   if ( ((struct PeerContext *) cls == &learn_peer) && (value == 1) && (learned_hostlist_saved_p1 == GNUNET_NO))
232   {
233     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
234                 _("Peer1 has successfully saved advertised URI \n"));
235     learned_hostlist_saved_p1 = GNUNET_YES;
236   }
237   /*
238   if ( ((struct PeerContext *) cls == &learn_peer2) && (value == 1) && (learned_hostlist_saved_p2 == GNUNET_NO))
239   {
240     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
241                 _("Peer2 has successfully saved advertised URI \n"));
242     learned_hostlist_saved_p2 = GNUNET_YES;
243   }*/
244   return GNUNET_OK;
245 }
246
247 static int
248 process_adv_sent (void *cls,
249               const char *subsystem,
250               const char *name,
251               uint64_t value,
252               int is_persistent)
253 {
254   if ( (value >= 1) && (adv_sent == GNUNET_NO))
255   {
256     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
257                 _("Server has successfully sent advertisement\n"));
258     adv_sent = GNUNET_YES;
259   }
260   return GNUNET_OK;
261 }
262
263
264 /**
265  * Check the server statistics regularly
266  */
267 static void
268 check_statistics (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
269 {
270   char *stat;
271   GNUNET_asprintf (&stat,
272                    gettext_noop("# advertised URI `%s' downloaded"),
273                    current_adv_uri);
274   GNUNET_STATISTICS_get (learn_peer.stats,
275                          "hostlist",
276                          stat,
277                          GNUNET_TIME_UNIT_MINUTES,
278                          NULL,
279                          &process_downloads,
280                          &learn_peer);
281   /*GNUNET_STATISTICS_get (learn_peer2.stats,
282                          "hostlist",
283                          stat,
284                          GNUNET_TIME_UNIT_MINUTES,
285                          NULL,
286                          &process_downloads,
287                          &learn_peer2);*/
288   GNUNET_free (stat);
289
290   GNUNET_STATISTICS_get (learn_peer.stats,
291                          "hostlist",
292                          gettext_noop("# advertised hostlist URIs"),
293                          GNUNET_TIME_UNIT_MINUTES,
294                          NULL,
295                          &process_uris_recv,
296                          &learn_peer);
297   /*GNUNET_STATISTICS_get (learn_peer2.stats,
298                          "hostlist",
299                          gettext_noop("# advertised hostlist URIs"),
300                          GNUNET_TIME_UNIT_MINUTES,
301                          NULL,
302                          &process_uris_recv,
303                          &learn_peer2);*/
304   GNUNET_STATISTICS_get (adv_peer.stats,
305                          "hostlist",
306                          gettext_noop("# hostlist advertisements send"),
307                          GNUNET_TIME_UNIT_MINUTES,
308                          NULL,
309                          &process_adv_sent,
310                          NULL);
311   check_task = GNUNET_SCHEDULER_add_delayed (sched,
312                                 CHECK_INTERVALL,
313                                 &check_statistics,
314                                 NULL);
315 }
316
317 /**
318  * Core handler for p2p hostlist advertisements
319  */
320 static int ad_arrive_handler (void *cls,
321                              const struct GNUNET_PeerIdentity * peer,
322                              const struct GNUNET_MessageHeader * message,
323                              struct GNUNET_TIME_Relative latency,
324                              uint32_t distance)
325 {
326   char *hostname;
327   char *expected_uri = GNUNET_malloc (MAX_URL_LEN);
328
329   unsigned long long port;
330   size_t size;
331   const struct GNUNET_MessageHeader * incoming;
332
333   if (-1 == GNUNET_CONFIGURATION_get_value_number (adv_peer.cfg,
334                                                    "HOSTLIST",
335                                                    "HTTPPORT",
336                                                    &port))
337     {
338     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
339                 "Could not read advertising server's configuration\n" );
340     if ( NULL != expected_uri ) GNUNET_free ( expected_uri );
341     return GNUNET_SYSERR;
342     }
343   hostname = GNUNET_RESOLVER_local_fqdn_get ();
344   if (NULL != hostname)
345     {
346       size = strlen (hostname);
347       if (size + 15 > MAX_URL_LEN)
348         {
349           GNUNET_break (0);
350         }
351       else
352         {
353           GNUNET_asprintf (&expected_uri,
354                            "http://%s:%u/",
355                            hostname,
356                            (unsigned int) port);
357         }
358     }
359
360   incoming = (const struct GNUNET_MessageHeader *) message;
361   current_adv_uri = strdup ((char*) &incoming[1]);
362   if ( 0 == strcmp( expected_uri, current_adv_uri ) )
363   {
364     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
365                 "Recieved hostlist advertisement with URI `%s' as expected\n", current_adv_uri);
366     adv_arrived_p1 = GNUNET_YES;
367     adv_arrived_p2 = GNUNET_YES;
368   }
369   else
370     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
371                 "Expected URI `%s' and recieved URI `%s' differ\n", expected_uri, current_adv_uri);
372   if ( NULL != expected_uri ) GNUNET_free ( expected_uri );
373   if ( NULL != expected_uri )  GNUNET_free ( hostname );
374   return GNUNET_OK;
375 }
376
377 /**
378  * List of handlers if we are learning.
379  */
380 static struct GNUNET_CORE_MessageHandler learn_handlers[] = {
381   { &ad_arrive_handler, GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT, 0},
382   { NULL, 0, 0 }
383 };
384
385 static void
386 setup_learn_peer (struct PeerContext *p, const char *cfgname)
387 {
388   char * filename;
389   unsigned int result;
390   p->cfg = GNUNET_CONFIGURATION_create ();
391 #if START_ARM
392   p->arm_pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
393                                         "gnunet-service-arm",
394 #if VERBOSE
395                                         "-L", "DEBUG",
396 #endif
397                                         "-c", cfgname, NULL);
398 #endif
399   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
400   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (p->cfg,
401                                                           "HOSTLIST",
402                                                           "HOSTLISTFILE",
403                                                           &filename))
404   {
405   if ( GNUNET_YES == GNUNET_DISK_file_test (filename) )
406     {
407       result = remove (filename);
408       if (result == 0)
409       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
410             _("Hostlist file `%s' was removed\n"),filename);
411     }
412   }
413   if ( NULL != filename)  GNUNET_free ( filename );
414
415   GNUNET_ARM_start_services (p->cfg, sched, "core", NULL);
416
417   p->core = GNUNET_CORE_connect (sched, p->cfg,
418                               GNUNET_TIME_UNIT_FOREVER_REL,
419                               NULL,
420                               NULL,
421                               NULL, NULL,
422                               NULL, GNUNET_NO,
423                               NULL, GNUNET_NO,
424                               learn_handlers );
425   GNUNET_assert ( NULL != p->core );
426   p->stats = GNUNET_STATISTICS_create (sched, "hostlist", p->cfg);
427   GNUNET_assert ( NULL != p->stats );
428 }
429
430
431 static void
432 setup_adv_peer (struct PeerContext *p, const char *cfgname)
433 {
434   p->cfg = GNUNET_CONFIGURATION_create ();
435 #if START_ARM
436   p->arm_pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
437                                         "gnunet-service-arm",
438 #if VERBOSE
439                                         "-L", "DEBUG",
440 #endif
441                                         "-c", cfgname, NULL);
442 #endif
443   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
444   GNUNET_ARM_start_services (p->cfg, sched, "core", NULL);
445   p->stats = GNUNET_STATISTICS_create (sched, "hostlist", p->cfg);
446   GNUNET_assert ( NULL != p->stats );
447 }
448
449 static void
450 run (void *cls,
451      struct GNUNET_SCHEDULER_Handle *s,
452      char *const *args,
453      const char *cfgfile, 
454      const struct GNUNET_CONFIGURATION_Handle *cfg)
455 {
456   timeout = GNUNET_NO;
457   adv_sent =GNUNET_NO;
458
459   adv_arrived_p1 = GNUNET_NO;
460   learned_hostlist_downloaded_p1 = GNUNET_NO;
461   learned_hostlist_saved_p1 = GNUNET_NO;
462
463   /*adv_arrived_p2 = GNUNET_NO;
464   learned_hostlist_downloaded_p2 = GNUNET_NO;
465   learned_hostlist_saved_p2 = GNUNET_NO;*/
466
467   sched = s;
468   timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
469                                                TIMEOUT,
470                                                &timeout_error,
471                                                NULL);
472   check_task = GNUNET_SCHEDULER_add_delayed (sched,
473                                 CHECK_INTERVALL,
474                                 &check_statistics,
475                                 NULL);
476
477   setup_adv_peer (&adv_peer, "test_learning_adv_peer.conf");
478   setup_learn_peer (&learn_peer, "test_learning_learn_peer.conf");
479   // setup_learn_peer (&learn_peer2, "test_learning_learn_peer2.conf");
480
481 }
482
483
484 static int
485 check ()
486 {
487   unsigned int failed;
488   char *const argv[] = { "test-gnunet-daemon-hostlist",
489     "-c", "learning_data.conf",
490 #if VERBOSE
491     "-L", "DEBUG",
492 #endif
493     NULL
494   };
495   struct GNUNET_GETOPT_CommandLineOption options[] = {
496     GNUNET_GETOPT_OPTION_END
497   };
498
499   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
500                       argv, "test-gnunet-daemon-hostlist",
501                       "nohelp", options, &run, NULL);
502
503   failed = GNUNET_NO;
504
505   if (timeout == GNUNET_YES)
506   {
507     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
508                 "Testcase could not set up two communicating peers, timeout\n");
509     failed = GNUNET_YES;
510   }
511   if (adv_arrived_p1 == GNUNET_NO)
512   {
513     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
514                 "Peer1: Learning peer did not recieve advertisement from server\n");
515     failed = GNUNET_YES;
516   }
517   if ( learned_hostlist_saved_p1 == GNUNET_NO )
518     {
519       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
520                   "Peer1: Advertised hostlist was not saved in datastore\n");
521       failed = GNUNET_YES;
522     }
523   if (learned_hostlist_downloaded_p1 == GNUNET_NO)
524   {
525     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
526                 "Peer1: Advertised hostlist could not be downloaded from server\n");
527     failed = GNUNET_YES;
528   }
529   /*
530   if (adv_arrived_p2 == GNUNET_NO)
531   {
532     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
533                 "Peer2: Learning peer did not recieve advertisement from server\n");
534     failed = GNUNET_YES;
535   }
536   if ( learned_hostlist_saved_p2 == GNUNET_NO )
537     {
538       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
539                   "Peer2: Advertised hostlist was not saved in datastore\n");
540       failed = GNUNET_YES;
541     }
542   if (learned_hostlist_downloaded_p2 == GNUNET_NO)
543   {
544     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
545                 "Peer2: Advertised hostlist could not be downloaded from server\n");
546     failed = GNUNET_YES;
547   }*/
548
549   if (adv_sent == GNUNET_NO)
550   {
551     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
552                 "Advertised was not sent from server to client\n");
553     failed = GNUNET_YES;
554   }
555   if ( GNUNET_YES == failed )
556     return GNUNET_YES;
557   else
558     return GNUNET_NO;
559 }
560
561 int
562 main (int argc, char *argv[])
563 {
564   
565   int ret;
566
567   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-1");
568   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-2");
569   GNUNET_log_setup ("test-gnunet-daemon-hostlist",
570 #if VERBOSE
571                     "DEBUG",
572 #else
573                     "WARNING",
574 #endif
575                     NULL);
576   ret = check ();
577   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-1");
578   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-2");
579   return ret; 
580 }
581
582 /* end of test_gnunet_daemon_hostlist.c */