fb9446bc4665a8b5cbd317f1dacbfeeb84f28729
[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
32 #define VERBOSE GNUNET_YES
33
34 #define START_ARM GNUNET_YES
35 #define MAX_URL_LEN 1000
36
37 /**
38  * How long until wait until testcases fails
39  */
40 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
41 #define CHECK_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
42
43 static int timeout;
44 static int adv_arrived;
45
46 static struct GNUNET_SCHEDULER_Handle *sched;
47
48 static GNUNET_SCHEDULER_TaskIdentifier timeout_task;
49 static GNUNET_SCHEDULER_TaskIdentifier check_task;
50     
51 struct PeerContext
52 {
53   struct GNUNET_CONFIGURATION_Handle *cfg;
54   struct GNUNET_TRANSPORT_Handle *th;
55   struct GNUNET_MessageHeader *hello;
56   struct GNUNET_ARM_Handle *arm;
57   struct GNUNET_CORE_Handle *core;
58 #if START_ARM
59   pid_t arm_pid;
60 #endif
61 };
62
63 static struct PeerContext adv_peer;
64
65 static struct PeerContext learn_peer;
66
67 static void
68 clean_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
69 {
70   if (adv_peer.th != NULL)
71   {
72     GNUNET_TRANSPORT_disconnect (adv_peer.th);
73     adv_peer.th = NULL;
74   }
75   if (learn_peer.th != NULL)
76   {
77     GNUNET_TRANSPORT_disconnect (learn_peer.th);
78     learn_peer.th = NULL;
79   }
80   if (adv_peer.core != NULL)
81   {
82     GNUNET_CORE_disconnect (adv_peer.core);
83     adv_peer.core = NULL;
84   }
85   if (learn_peer.core != NULL)
86   {
87     GNUNET_CORE_disconnect (learn_peer.core);
88     learn_peer.core = NULL;
89   }
90   GNUNET_SCHEDULER_shutdown (sched);
91 }
92
93 static void shutdown_testcase()
94 {
95   if (timeout_task != GNUNET_SCHEDULER_NO_TASK)
96   {
97     GNUNET_SCHEDULER_cancel (sched,
98                              timeout_task);
99     timeout_task = GNUNET_SCHEDULER_NO_TASK;
100   }
101   if (check_task != GNUNET_SCHEDULER_NO_TASK)
102   {
103     GNUNET_SCHEDULER_cancel (sched,
104         check_task);
105     check_task = GNUNET_SCHEDULER_NO_TASK;
106   }
107   GNUNET_SCHEDULER_add_now (sched,
108                             &clean_up, NULL);
109 }
110
111 /**
112  * Timeout, give up.
113  */
114 static void
115 timeout_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
116 {
117   timeout_task = GNUNET_SCHEDULER_NO_TASK;
118   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
119               "Timeout while executing testcase, test failed.\n");
120   timeout = GNUNET_YES;
121   clean_up (NULL, tc);
122 }
123
124 /**
125  * Check the server statistics regularly
126  */
127 static void
128 check_statistics (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
129 {
130   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
131               "Checking server stats...\n");
132   check_task = GNUNET_SCHEDULER_add_delayed (sched,
133                                 CHECK_INTERVALL,
134                                 &check_statistics,
135                                 NULL);
136 }
137
138 /**
139  * Core handler for p2p hostlist advertisements
140  */
141 static int ad_arrive_handler (void *cls,
142                              const struct GNUNET_PeerIdentity * peer,
143                              const struct GNUNET_MessageHeader * message,
144                              struct GNUNET_TIME_Relative latency,
145                              uint32_t distance)
146 {
147   char *hostname;
148   char *expected_uri = GNUNET_malloc (MAX_URL_LEN);
149   char *recv_uri;
150
151   unsigned long long port;
152   size_t size;
153   const struct GNUNET_MessageHeader * incoming;
154
155   if (-1 == GNUNET_CONFIGURATION_get_value_number (adv_peer.cfg,
156                                                    "HOSTLIST",
157                                                    "HTTPPORT",
158                                                    &port))
159     {
160     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
161                 "Could not read advertising server's configuration\n" );
162     return GNUNET_SYSERR;
163     }
164   hostname = GNUNET_RESOLVER_local_hostname_get ();
165   if (NULL != hostname)
166     {
167       size = strlen (hostname);
168       if (size + 15 > MAX_URL_LEN)
169         {
170           GNUNET_break (0);
171         }
172       else
173         {
174           GNUNET_asprintf (&expected_uri,
175                            "http://%s:%u/",
176                            hostname,
177                            (unsigned int) port);
178         }
179     }
180
181   incoming = (const struct GNUNET_MessageHeader *) message;
182   recv_uri = (char*) &incoming[1];
183   if ( 0 == strcmp( expected_uri, recv_uri ) )
184   {
185     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
186                 "Recieved hostlist advertisement with URI `%s'as expected\n", recv_uri);
187     adv_arrived = GNUNET_YES;
188   }
189   else
190     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
191                 "Expected URI `%s' and recieved URI `%s' differ\n", expected_uri, recv_uri);
192   GNUNET_free ( expected_uri );
193   GNUNET_free ( hostname );
194   shutdown_testcase();
195   return GNUNET_OK;
196 }
197
198 /**
199  * List of handlers if we are learning.
200  */
201 static struct GNUNET_CORE_MessageHandler learn_handlers[] = {
202   { &ad_arrive_handler, GNUNET_MESSAGE_TYPE_HOSTLIST_ADVERTISEMENT, 0},
203   { NULL, 0, 0 }
204 };
205
206 static void
207 setup_learn_peer (struct PeerContext *p, const char *cfgname)
208 {
209   char * filename;
210   unsigned int result;
211   p->cfg = GNUNET_CONFIGURATION_create ();
212 #if START_ARM
213   p->arm_pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
214                                         "gnunet-service-arm",
215 #if VERBOSE
216                                         "-L", "DEBUG",
217 #endif
218                                         "-c", cfgname, NULL);
219 #endif
220   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
221   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (p->cfg,
222                                                           "HOSTLIST",
223                                                           "HOSTLISTFILE",
224                                                           &filename))
225   {
226   if ( GNUNET_YES == GNUNET_DISK_file_test (filename) )
227     {
228       result = remove (filename);
229       if (result == 0)
230       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
231             _("Hostlist hostlist file `%s' was removed\n"),filename);
232     }
233   }
234   GNUNET_free ( filename );
235   GNUNET_ARM_start_services (p->cfg, sched, "core", NULL);
236
237   p->core = GNUNET_CORE_connect (sched, p->cfg,
238                               GNUNET_TIME_UNIT_FOREVER_REL,
239                               NULL,
240                               NULL,
241                               NULL, NULL,
242                               NULL, GNUNET_NO,
243                               NULL, GNUNET_NO,
244                               learn_handlers );
245   GNUNET_assert ( NULL != p->core );
246 }
247
248
249 static void
250 setup_adv_peer (struct PeerContext *p, const char *cfgname)
251 {
252   p->cfg = GNUNET_CONFIGURATION_create ();
253 #if START_ARM
254   p->arm_pid = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
255                                         "gnunet-service-arm",
256 #if VERBOSE
257                                         "-L", "DEBUG",
258 #endif
259                                         "-c", cfgname, NULL);
260 #endif
261   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
262   GNUNET_ARM_start_services (p->cfg, sched, "core", NULL);
263 }
264
265
266
267 static void
268 waitpid_task (void *cls, 
269               const struct GNUNET_SCHEDULER_TaskContext *tc)
270 {
271   struct PeerContext *p = cls;
272
273 #if START_ARM 
274   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
275               "Killing ARM process.\n");
276   if (0 != PLIBC_KILL (p->arm_pid, SIGTERM))
277     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
278   if (GNUNET_OS_process_wait(p->arm_pid) != GNUNET_OK)
279     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
280   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
281               "ARM process %u stopped\n", p->arm_pid);
282 #endif
283   GNUNET_CONFIGURATION_destroy (p->cfg);
284 }
285
286
287 static void
288 stop_cb (void *cls, 
289          int success)
290 {
291   struct PeerContext *p = cls;
292
293   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
294               success
295               ? "ARM stopped core service\n"
296               : "ARM failed to stop core service\n");
297   GNUNET_ARM_disconnect (p->arm);
298   p->arm = NULL;
299   /* make sure this runs after all other tasks are done */
300   GNUNET_SCHEDULER_add_delayed (sched,
301                                 GNUNET_TIME_UNIT_SECONDS,
302                                 &waitpid_task, p);
303 }
304
305
306 static void
307 stop_arm (struct PeerContext *p)
308 {
309   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
310               "Asking ARM to stop core service\n");
311   p->arm = GNUNET_ARM_connect (p->cfg, sched, NULL);
312   GNUNET_ARM_stop_service (p->arm, "core", GNUNET_TIME_UNIT_SECONDS,
313                            &stop_cb, p);
314 }
315
316
317 /**
318  * Try again to connect to transport service.
319  */
320 static void
321 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
322 {
323   stop_arm (&adv_peer);
324   stop_arm (&learn_peer);
325 }
326
327
328 static void
329 run (void *cls,
330      struct GNUNET_SCHEDULER_Handle *s,
331      char *const *args,
332      const char *cfgfile, 
333      const struct GNUNET_CONFIGURATION_Handle *cfg)
334 {
335   timeout = GNUNET_NO;
336   adv_arrived = GNUNET_NO;
337   sched = s;
338   timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
339                                                TIMEOUT,
340                                                &timeout_error,
341                                                NULL);
342   check_task = GNUNET_SCHEDULER_add_delayed (sched,
343                                 CHECK_INTERVALL,
344                                 &check_statistics,
345                                 NULL);
346   GNUNET_SCHEDULER_add_delayed (sched,
347                                 GNUNET_TIME_UNIT_FOREVER_REL,
348                                 &shutdown_task,
349                                 NULL);
350   setup_adv_peer (&adv_peer, "test_learning_adv_peer.conf");
351   setup_learn_peer (&learn_peer, "test_learning_learn_peer.conf");
352 }
353
354
355 static int
356 check ()
357 {
358   char *const argv[] = { "test-gnunet-daemon-hostlist",
359     "-c", "learning_data.conf",
360 #if VERBOSE
361     "-L", "DEBUG",
362 #endif
363     NULL
364   };
365   struct GNUNET_GETOPT_CommandLineOption options[] = {
366     GNUNET_GETOPT_OPTION_END
367   };
368
369   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
370                       argv, "test-gnunet-daemon-hostlist",
371                       "nohelp", options, &run, NULL);
372
373   if ( (timeout == GNUNET_YES) || (adv_arrived == GNUNET_NO))
374     return GNUNET_YES;
375   else
376     return GNUNET_NO;
377 }
378
379 int
380 main (int argc, char *argv[])
381 {
382   
383   int ret;
384
385   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-1");
386   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-2");
387   GNUNET_log_setup ("test-gnunet-daemon-hostlist",
388 #if VERBOSE
389                     "DEBUG",
390 #else
391                     "WARNING",
392 #endif
393                     NULL);
394   ret = check ();
395   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-1");
396   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-2");
397   return ret; 
398 }
399
400 /* end of test_gnunet_daemon_hostlist.c */