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