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