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