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