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