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