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