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