fix 1683
[oweals/gnunet.git] / src / hostlist / test_gnunet_daemon_hostlist_learning.c
1 /*
2      This file is part of GNUnet
3      (C) 2009, 2010, 2011 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 3, 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_NO
34
35 #define START_ARM GNUNET_YES
36
37 #define MAX_URL_LEN 1000
38
39 /**
40  * How long until wait until testcases fails
41  */
42 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 180)
43
44 #define CHECK_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
45
46     
47 struct PeerContext
48 {
49   struct GNUNET_CONFIGURATION_Handle *cfg;
50   struct GNUNET_TRANSPORT_Handle *th;
51   struct GNUNET_MessageHeader *hello;
52   struct GNUNET_CORE_Handle *core;
53   struct GNUNET_STATISTICS_Handle *stats;
54 #if START_ARM
55   struct GNUNET_OS_Process *arm_proc;
56 #endif
57 };
58
59 static int timeout;
60
61 static int adv_sent;
62
63 static int adv_arrived;
64
65 static int learned_hostlist_saved;
66
67 static int learned_hostlist_downloaded;
68
69 static char * current_adv_uri;
70
71 static const struct GNUNET_CONFIGURATION_Handle *cfg;
72
73 static GNUNET_SCHEDULER_TaskIdentifier timeout_task;
74
75 static GNUNET_SCHEDULER_TaskIdentifier check_task;
76
77 static struct PeerContext adv_peer;
78
79 static struct PeerContext learn_peer;
80
81 static struct GNUNET_STATISTICS_GetHandle * download_stats;
82
83 static struct GNUNET_STATISTICS_GetHandle * urisrecv_stat;
84
85 static struct GNUNET_STATISTICS_GetHandle * advsent_stat;
86
87
88 static void 
89 shutdown_testcase()
90 {
91   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
92               "Shutdown testcase....\n");
93   if (timeout_task != GNUNET_SCHEDULER_NO_TASK)
94     {
95       GNUNET_SCHEDULER_cancel (timeout_task);
96       timeout_task = GNUNET_SCHEDULER_NO_TASK;
97     }
98   if (NULL != download_stats)
99     {
100       GNUNET_STATISTICS_get_cancel (download_stats);
101       download_stats = NULL;
102     }
103   if (NULL != urisrecv_stat)
104     {
105       GNUNET_STATISTICS_get_cancel (urisrecv_stat);
106       urisrecv_stat = NULL;
107     }
108   if (NULL != advsent_stat)
109     {
110       GNUNET_STATISTICS_get_cancel (advsent_stat);
111       advsent_stat = NULL;
112     }
113   if (check_task != GNUNET_SCHEDULER_NO_TASK)
114     {
115       GNUNET_SCHEDULER_cancel (check_task);
116       check_task = GNUNET_SCHEDULER_NO_TASK;
117     }
118   if (NULL != current_adv_uri)
119     {
120       GNUNET_free (current_adv_uri);
121       current_adv_uri = NULL;
122     }
123   if (adv_peer.th != NULL)
124     {
125       GNUNET_TRANSPORT_disconnect (adv_peer.th);
126       adv_peer.th = NULL;
127     }
128   if (learn_peer.th != NULL)
129     {
130       GNUNET_TRANSPORT_disconnect (learn_peer.th);
131       learn_peer.th = NULL;
132     }
133   if (adv_peer.core != NULL)
134     {
135       GNUNET_CORE_disconnect (adv_peer.core);
136       adv_peer.core = NULL;
137     }
138   if (learn_peer.core != NULL)
139     {
140       GNUNET_CORE_disconnect (learn_peer.core);
141       learn_peer.core = NULL;
142     }
143 #if START_ARM
144   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
145               "Killing hostlist server ARM process.\n");
146   if (0 != GNUNET_OS_process_kill (adv_peer.arm_proc, SIGTERM))
147     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
148                          "kill");
149   if (GNUNET_OS_process_wait(adv_peer.arm_proc) != GNUNET_OK)
150     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
151                          "waitpid");
152   GNUNET_OS_process_close (adv_peer.arm_proc);
153   adv_peer.arm_proc = NULL;
154   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
155               "Killing hostlist client ARM process.\n");
156   if (0 != GNUNET_OS_process_kill (learn_peer.arm_proc, SIGTERM))
157     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 
158                          "kill");
159   if (GNUNET_OS_process_wait(learn_peer.arm_proc) != GNUNET_OK)
160     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
161                          "waitpid");
162   GNUNET_OS_process_close (learn_peer.arm_proc);
163   learn_peer.arm_proc = NULL;
164 #endif
165   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
166               "Shutdown complete....\n");
167 }
168
169 /**
170  * Timeout, give up.
171  */
172 static void
173 timeout_error (void *cls, 
174                const struct GNUNET_SCHEDULER_TaskContext *tc)
175 {
176   timeout_task = GNUNET_SCHEDULER_NO_TASK;
177   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
178     return;
179   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
180               "Timeout while executing testcase, test failed.\n");
181   timeout = GNUNET_YES;
182   shutdown_testcase();
183 }
184
185
186 static void
187 process_downloads_done (void *cls, int success)
188 {
189   download_stats = NULL;
190 }
191
192
193 static int
194 process_downloads (void *cls,
195                    const char *subsystem,
196                    const char *name,
197                    uint64_t value,
198                    int is_persistent)
199 {
200   if ( (value >= 2) && 
201        (learned_hostlist_downloaded == GNUNET_NO) )
202     {
203       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
204                   "Peer has successfully downloaded advertised URI\n");
205       learned_hostlist_downloaded = GNUNET_YES;
206       if ( (learned_hostlist_saved == GNUNET_YES) &&
207            (adv_sent == GNUNET_YES) )
208         shutdown_testcase();
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   if ( ((struct PeerContext *) cls == &learn_peer) && 
229        (value == 1) && 
230        (learned_hostlist_saved == GNUNET_NO) )
231     {
232       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
233                   "Peer has successfully saved advertised URI\n");
234       learned_hostlist_saved = GNUNET_YES;
235       if ( (learned_hostlist_downloaded == GNUNET_YES) &&
236            (adv_sent == GNUNET_YES) )
237         shutdown_testcase();
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         shutdown_testcase();
265     }
266   return GNUNET_OK;
267 }
268
269
270 /**
271  * Check the server statistics regularly
272  */
273 static void
274 check_statistics (void *cls, 
275                   const struct GNUNET_SCHEDULER_TaskContext *tc)
276 {
277   char *stat;
278
279   check_task = GNUNET_SCHEDULER_NO_TASK;
280   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
281     return;
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 = GNUNET_STATISTICS_get (learn_peer.stats,
290                                               "hostlist",
291                                               stat,
292                                               GNUNET_TIME_UNIT_MINUTES,
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 = GNUNET_STATISTICS_get (learn_peer.stats,
299                                              "hostlist",
300                                              gettext_noop("# advertised hostlist URIs"),
301                                              GNUNET_TIME_UNIT_MINUTES,
302                                              &process_uris_recv_done,
303                                              &process_uris_recv,
304                                              &learn_peer);
305     }
306   GNUNET_free (stat);
307   if ( NULL != adv_peer.stats)
308     {
309       if (NULL != advsent_stat)
310         GNUNET_STATISTICS_get_cancel (advsent_stat);
311       advsent_stat = GNUNET_STATISTICS_get (adv_peer.stats,
312                                             "hostlist",
313                                             gettext_noop("# hostlist advertisements send"),
314                                             GNUNET_TIME_UNIT_MINUTES,
315                                             &process_adv_sent_done,
316                                             &process_adv_sent,
317                                             NULL);
318     }
319   check_task = GNUNET_SCHEDULER_add_delayed (CHECK_INTERVALL,
320                                              &check_statistics,
321                                              NULL);
322 }
323
324
325 /**
326  * Core handler for p2p hostlist advertisements
327  */
328 static int 
329 ad_arrive_handler (void *cls,
330                    const struct GNUNET_PeerIdentity * peer,
331                    const struct GNUNET_MessageHeader * message,
332                    const struct GNUNET_TRANSPORT_ATS_Information *atsi)
333 {
334   char *hostname;
335   char *expected_uri;
336   unsigned long long port;
337   const struct GNUNET_MessageHeader * incoming;
338
339   if (-1 == GNUNET_CONFIGURATION_get_value_number (adv_peer.cfg,
340                                                    "HOSTLIST",
341                                                    "HTTPPORT",
342                                                    &port))
343     {
344       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
345                   "Could not read advertising server's configuration\n" );
346       return GNUNET_SYSERR;
347     }
348
349   if ( GNUNET_SYSERR  == GNUNET_CONFIGURATION_get_value_string (adv_peer.cfg,
350                                                                 "HOSTLIST",
351                                                                 "EXTERNAL_DNS_NAME",
352                                                                 &hostname))
353     hostname = GNUNET_RESOLVER_local_fqdn_get ();
354   GNUNET_asprintf (&expected_uri,
355                    "http://%s:%u/",
356                    hostname != NULL ? hostname : "localhost",
357                    (unsigned int) port);   
358   incoming = (const struct GNUNET_MessageHeader *) message;
359   current_adv_uri = strdup ((char*) &incoming[1]);
360   if ( 0 == strcmp( expected_uri, current_adv_uri ) )
361     {
362       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
363                   "Received hostlist advertisement with URI `%s' as expected\n",
364                   current_adv_uri);
365       adv_arrived = GNUNET_YES;
366       adv_sent = GNUNET_YES;
367     }
368   else
369     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
370                 "Expected URI `%s' and recieved URI `%s' differ\n",
371                 expected_uri,
372                 current_adv_uri);
373   GNUNET_free (expected_uri);
374   GNUNET_free_non_null (hostname);
375   return GNUNET_OK;
376 }
377
378
379 /**
380  * List of handlers if we are learning.
381  */
382 static struct GNUNET_CORE_MessageHandler learn_handlers[] = {
383   { &ad_arrive_handler, GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT, 0},
384   { NULL, 0, 0 }
385 };
386
387
388 static void
389 setup_learn_peer (struct PeerContext *p, 
390                   const char *cfgname)
391 {
392   char * filename;
393   unsigned int result;
394
395   p->cfg = GNUNET_CONFIGURATION_create ();
396 #if START_ARM
397   p->arm_proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
398                                         "gnunet-service-arm",
399 #if VERBOSE
400                                         "-L", "DEBUG",
401 #endif
402                                         "-c", cfgname, NULL);
403 #endif
404   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
405   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (p->cfg,
406                                                           "HOSTLIST",
407                                                           "HOSTLISTFILE",
408                                                           &filename))
409     {
410       if (GNUNET_YES == GNUNET_DISK_file_test (filename))
411         {
412           result = UNLINK (filename);
413           if (result == 0)
414             GNUNET_log (GNUNET_ERROR_TYPE_INFO,
415                         _("Hostlist file `%s' was removed\n"),filename);
416         }
417       GNUNET_free (filename);
418     }
419   p->core = GNUNET_CORE_connect (p->cfg,
420                                  1,
421                                  NULL,
422                                  NULL,
423                                  NULL, NULL, NULL,
424                                  NULL, GNUNET_NO,
425                                  NULL, GNUNET_NO,
426                                  learn_handlers );
427   GNUNET_assert ( NULL != p->core );
428   p->stats = GNUNET_STATISTICS_create ("hostlist", p->cfg);
429   GNUNET_assert ( NULL != p->stats );
430 }
431
432
433 static void
434 setup_adv_peer (struct PeerContext *p, 
435                 const char *cfgname)
436 {
437   p->cfg = GNUNET_CONFIGURATION_create ();
438 #if START_ARM
439   p->arm_proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
440                                         "gnunet-service-arm",
441 #if VERBOSE
442                                         "-L", "DEBUG",
443 #endif
444                                         "-c", cfgname, NULL);
445 #endif
446   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
447   p->stats = GNUNET_STATISTICS_create ("hostlist", p->cfg);
448   GNUNET_assert ( NULL != p->stats );
449 }
450
451
452 static void
453 run (void *cls,
454      char *const *args,
455      const char *cfgfile, 
456      const struct GNUNET_CONFIGURATION_Handle *c)
457 {
458   timeout = GNUNET_NO;
459   adv_sent =GNUNET_NO;
460
461   adv_arrived = 0;
462   learned_hostlist_saved = GNUNET_NO;
463   learned_hostlist_downloaded = GNUNET_NO;
464
465   cfg = c;
466
467   setup_adv_peer (&adv_peer, "test_learning_adv_peer.conf");
468   setup_learn_peer (&learn_peer, "test_learning_learn_peer.conf");
469   timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
470                                                &timeout_error,
471                                                NULL);
472
473   check_task = GNUNET_SCHEDULER_add_delayed (CHECK_INTERVALL,
474                                 &check_statistics,
475                                 NULL);
476 }
477
478
479 static int
480 check ()
481 {
482   unsigned int failed;
483   char *const argv[] = { 
484     "test-gnunet-daemon-hostlist-learning",
485     "-c", "learning_data.conf",
486 #if VERBOSE
487     "-L", "DEBUG",
488 #endif
489     NULL
490   };
491   struct GNUNET_GETOPT_CommandLineOption options[] = {
492     GNUNET_GETOPT_OPTION_END
493   };
494
495   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
496                       argv, "test-gnunet-daemon-hostlist-learning",
497                       "nohelp", options,
498                       &run, NULL);
499   failed = GNUNET_NO;
500   if (timeout == GNUNET_YES)
501     {
502       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
503                   "Testcase timeout\n");
504       failed = GNUNET_YES;
505     }
506   if (adv_arrived != GNUNET_YES)
507     {
508       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
509                   "Learning peer did not receive advertisement from server\n");
510       failed = GNUNET_YES;
511     }
512   if ( learned_hostlist_saved == GNUNET_NO )
513     {
514       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
515                   "Advertised hostlist was not saved in datastore\n");
516       failed = GNUNET_YES;
517     }
518   if (learned_hostlist_downloaded == GNUNET_NO)
519     {
520       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
521                   "Advertised hostlist could not be downloaded from server\n");
522       failed = GNUNET_YES;
523     }
524   if (adv_sent == GNUNET_NO)
525     {
526       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
527                   "Advertised was not sent from server to client\n");
528       failed = GNUNET_YES;
529     }
530   if (GNUNET_YES == failed)
531     return GNUNET_YES;
532   return GNUNET_NO;
533 }
534
535
536 int
537 main (int argc, char *argv[])
538
539   int ret;
540
541   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1");
542   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2");
543   GNUNET_log_setup ("test-gnunet-daemon-hostlist",
544 #if VERBOSE
545                     "DEBUG",
546 #else
547                     "WARNING",
548 #endif
549                     NULL);
550   ret = check ();
551   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-1");
552   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-hostlist-peer-2");
553   if (GNUNET_YES == GNUNET_DISK_file_test ("hostlists_learn_peer.file"))
554     {
555       if (0 == UNLINK("hostlists_learn_peer.file"))
556         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
557                     "Hostlist file hostlists_learn_peer.file was removed\n");
558     }
559   return ret; 
560 }
561
562 /* end of test_gnunet_daemon_hostlist.c */