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