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