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