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