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