4c466d5c7bab5b768a72382a9c5b1c98b2c8ba67
[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_YES
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   fprintf (stderr,
201            "New stat: %s has value %llu\n",
202            name,
203            (unsigned long long) value);
204   if ( (value == 2) && 
205        (learned_hostlist_downloaded == GNUNET_NO) )
206     {
207       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
208                   "Peer has successfully downloaded advertised URI\n");
209       learned_hostlist_downloaded = GNUNET_YES;
210       if ( (learned_hostlist_saved == GNUNET_YES) &&
211            (adv_sent == GNUNET_YES) )
212         shutdown_testcase();
213     }
214   return GNUNET_OK;
215 }
216
217
218 static void
219 process_uris_recv_done (void *cls, int success)
220 {
221   urisrecv_stat = NULL;
222 }
223
224
225 static int
226 process_uris_recv (void *cls,
227                    const char *subsystem,
228                    const char *name,
229                    uint64_t value,
230                    int is_persistent)
231 {
232   if ( ((struct PeerContext *) cls == &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         shutdown_testcase();
242     }
243   return GNUNET_OK;
244 }
245
246
247 static void
248 process_adv_sent_done (void *cls, int success)
249 {
250   advsent_stat = NULL;
251 }
252
253
254 static int
255 process_adv_sent (void *cls,
256                   const char *subsystem,
257                   const char *name,
258                   uint64_t value,
259                   int is_persistent)
260 {
261   if ( (value >= 1) && (adv_sent == GNUNET_NO))
262     {
263       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
264                   "Server has successfully sent advertisement\n");
265       adv_sent = GNUNET_YES;
266       if ( (learned_hostlist_downloaded == GNUNET_YES) &&
267            (learned_hostlist_saved == GNUNET_YES) )
268         shutdown_testcase();
269     }
270   return GNUNET_OK;
271 }
272
273
274 /**
275  * Check the server statistics regularly
276  */
277 static void
278 check_statistics (void *cls, 
279                   const struct GNUNET_SCHEDULER_TaskContext *tc)
280 {
281   char *stat;
282
283   check_task = GNUNET_SCHEDULER_NO_TASK;
284   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
285     return;
286   GNUNET_asprintf (&stat,
287                    gettext_noop("# advertised URI `%s' downloaded"),
288                    current_adv_uri);
289   if (NULL != learn_peer.stats)
290     {
291       if (NULL != download_stats)
292         GNUNET_STATISTICS_get_cancel (download_stats);
293       download_stats = GNUNET_STATISTICS_get (learn_peer.stats,
294                                               "hostlist",
295                                               stat,
296                                               GNUNET_TIME_UNIT_MINUTES,
297                                               &process_downloads_done,
298                                               &process_downloads,
299                                               &learn_peer);      
300       if (NULL != urisrecv_stat)
301         GNUNET_STATISTICS_get_cancel (urisrecv_stat);
302       urisrecv_stat = GNUNET_STATISTICS_get (learn_peer.stats,
303                                              "hostlist",
304                                              gettext_noop("# advertised hostlist URIs"),
305                                              GNUNET_TIME_UNIT_MINUTES,
306                                              &process_uris_recv_done,
307                                              &process_uris_recv,
308                                              &learn_peer);
309     }
310   GNUNET_free (stat);
311   if ( NULL != adv_peer.stats)
312     {
313       if (NULL != advsent_stat)
314         GNUNET_STATISTICS_get_cancel (advsent_stat);
315       advsent_stat = GNUNET_STATISTICS_get (adv_peer.stats,
316                                             "hostlist",
317                                             gettext_noop("# hostlist advertisements send"),
318                                             GNUNET_TIME_UNIT_MINUTES,
319                                             &process_adv_sent_done,
320                                             &process_adv_sent,
321                                             NULL);
322     }
323   check_task = GNUNET_SCHEDULER_add_delayed (CHECK_INTERVALL,
324                                              &check_statistics,
325                                              NULL);
326 }
327
328
329 /**
330  * Core handler for p2p hostlist advertisements
331  */
332 static int 
333 ad_arrive_handler (void *cls,
334                    const struct GNUNET_PeerIdentity * peer,
335                    const struct GNUNET_MessageHeader * message,
336                    const struct GNUNET_TRANSPORT_ATS_Information *atsi)
337 {
338   char *hostname;
339   char *expected_uri;
340   unsigned long long port;
341   const struct GNUNET_MessageHeader * incoming;
342
343   if (-1 == GNUNET_CONFIGURATION_get_value_number (adv_peer.cfg,
344                                                    "HOSTLIST",
345                                                    "HTTPPORT",
346                                                    &port))
347     {
348       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
349                   "Could not read advertising server's configuration\n" );
350       return GNUNET_SYSERR;
351     }
352
353   if ( GNUNET_SYSERR  == GNUNET_CONFIGURATION_get_value_string (adv_peer.cfg,
354                                                                 "HOSTLIST",
355                                                                 "EXTERNAL_DNS_NAME",
356                                                                 &hostname))
357     hostname = GNUNET_RESOLVER_local_fqdn_get ();
358   GNUNET_asprintf (&expected_uri,
359                    "http://%s:%u/",
360                    hostname != NULL ? hostname : "localhost",
361                    (unsigned int) port);   
362   incoming = (const struct GNUNET_MessageHeader *) message;
363   current_adv_uri = strdup ((char*) &incoming[1]);
364   if ( 0 == strcmp( expected_uri, current_adv_uri ) )
365     {
366       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
367                   "Received hostlist advertisement with URI `%s' as expected\n",
368                   current_adv_uri);
369       adv_arrived = GNUNET_YES;
370       adv_sent = GNUNET_YES;
371     }
372   else
373     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
374                 "Expected URI `%s' and recieved URI `%s' differ\n",
375                 expected_uri,
376                 current_adv_uri);
377   GNUNET_free (expected_uri);
378   GNUNET_free_non_null (hostname);
379   return GNUNET_OK;
380 }
381
382
383 /**
384  * List of handlers if we are learning.
385  */
386 static struct GNUNET_CORE_MessageHandler learn_handlers[] = {
387   { &ad_arrive_handler, GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT, 0},
388   { NULL, 0, 0 }
389 };
390
391
392 static void
393 setup_learn_peer (struct PeerContext *p, 
394                   const char *cfgname)
395 {
396   char * filename;
397   unsigned int result;
398
399   p->cfg = GNUNET_CONFIGURATION_create ();
400 #if START_ARM
401   p->arm_proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
402                                         "gnunet-service-arm",
403 #if VERBOSE
404                                         "-L", "DEBUG",
405 #endif
406                                         "-c", cfgname, NULL);
407 #endif
408   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
409   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (p->cfg,
410                                                           "HOSTLIST",
411                                                           "HOSTLISTFILE",
412                                                           &filename))
413     {
414       if (GNUNET_YES == GNUNET_DISK_file_test (filename))
415         {
416           result = UNLINK (filename);
417           if (result == 0)
418             GNUNET_log (GNUNET_ERROR_TYPE_INFO,
419                         _("Hostlist file `%s' was removed\n"),filename);
420         }
421       GNUNET_free (filename);
422     }
423   p->core = GNUNET_CORE_connect (p->cfg,
424                                  1,
425                                  NULL,
426                                  NULL,
427                                  NULL, NULL, NULL,
428                                  NULL, GNUNET_NO,
429                                  NULL, GNUNET_NO,
430                                  learn_handlers );
431   GNUNET_assert ( NULL != p->core );
432   p->stats = GNUNET_STATISTICS_create ("hostlist", p->cfg);
433   GNUNET_assert ( NULL != p->stats );
434 }
435
436
437 static void
438 setup_adv_peer (struct PeerContext *p, 
439                 const char *cfgname)
440 {
441   p->cfg = GNUNET_CONFIGURATION_create ();
442 #if START_ARM
443   p->arm_proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
444                                         "gnunet-service-arm",
445 #if VERBOSE
446                                         "-L", "DEBUG",
447 #endif
448                                         "-c", cfgname, NULL);
449 #endif
450   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
451   p->stats = GNUNET_STATISTICS_create ("hostlist", p->cfg);
452   GNUNET_assert ( NULL != p->stats );
453 }
454
455
456 static void
457 run (void *cls,
458      char *const *args,
459      const char *cfgfile, 
460      const struct GNUNET_CONFIGURATION_Handle *c)
461 {
462   timeout = GNUNET_NO;
463   adv_sent =GNUNET_NO;
464
465   adv_arrived = 0;
466   learned_hostlist_saved = GNUNET_NO;
467   learned_hostlist_downloaded = GNUNET_NO;
468
469   cfg = c;
470
471   setup_adv_peer (&adv_peer, "test_learning_adv_peer.conf");
472   setup_learn_peer (&learn_peer, "test_learning_learn_peer.conf");
473   timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
474                                                &timeout_error,
475                                                NULL);
476
477   check_task = GNUNET_SCHEDULER_add_delayed (CHECK_INTERVALL,
478                                 &check_statistics,
479                                 NULL);
480 }
481
482
483 static int
484 check ()
485 {
486   unsigned int failed;
487   char *const argv[] = { 
488     "test-gnunet-daemon-hostlist-learning",
489     "-c", "learning_data.conf",
490 #if VERBOSE
491     "-L", "DEBUG",
492 #endif
493     NULL
494   };
495   struct GNUNET_GETOPT_CommandLineOption options[] = {
496     GNUNET_GETOPT_OPTION_END
497   };
498
499   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
500                       argv, "test-gnunet-daemon-hostlist-learning",
501                       "nohelp", options,
502                       &run, NULL);
503   failed = GNUNET_NO;
504   if (timeout == GNUNET_YES)
505     {
506       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
507                   "Testcase timeout\n");
508       failed = GNUNET_YES;
509     }
510   if (adv_arrived != GNUNET_YES)
511     {
512       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
513                   "Learning peer did not receive advertisement from server\n");
514       failed = GNUNET_YES;
515     }
516   if ( learned_hostlist_saved == GNUNET_NO )
517     {
518       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
519                   "Advertised hostlist was not saved in datastore\n");
520       failed = GNUNET_YES;
521     }
522   if (learned_hostlist_downloaded == GNUNET_NO)
523     {
524       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
525                   "Advertised hostlist could not be downloaded from server\n");
526       failed = GNUNET_YES;
527     }
528   if (adv_sent == GNUNET_NO)
529     {
530       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
531                   "Advertised was not sent from server to client\n");
532       failed = GNUNET_YES;
533     }
534   if (GNUNET_YES == failed)
535     return GNUNET_YES;
536   return GNUNET_NO;
537 }
538
539
540 int
541 main (int argc, char *argv[])
542
543   int ret;
544
545   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-1");
546   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-2");
547   GNUNET_log_setup ("test-gnunet-daemon-hostlist",
548 #if VERBOSE
549                     "DEBUG",
550 #else
551                     "WARNING",
552 #endif
553                     NULL);
554   ret = check ();
555   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-1");
556   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-2");
557   if (GNUNET_YES == GNUNET_DISK_file_test ("hostlists_learn_peer.file"))
558     {
559       if (0 == UNLINK("hostlists_learn_peer.file"))
560         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
561                     "Hostlist file hostlists_learn_peer.file was removed\n");
562     }
563   return ret; 
564 }
565
566 /* end of test_gnunet_daemon_hostlist.c */