simplifying transport plugin API
[oweals/gnunet.git] / src / hostlist / test_gnunet_daemon_hostlist.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_transport_service.h"
29
30 #define VERBOSE GNUNET_YES
31
32 #define START_ARM GNUNET_YES
33
34
35 /**
36  * How long until we give up on transmitting the message?
37  */
38 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 150)
39
40 static int ok;
41
42 static struct GNUNET_SCHEDULER_Handle *sched;
43
44 static GNUNET_SCHEDULER_TaskIdentifier timeout_task;
45     
46 struct PeerContext
47 {
48   struct GNUNET_CONFIGURATION_Handle *cfg;
49   struct GNUNET_TRANSPORT_Handle *th;
50   struct GNUNET_MessageHeader *hello;
51   struct GNUNET_ARM_Handle *arm;
52 #if START_ARM
53   pid_t arm_pid;
54 #endif
55 };
56
57 static struct PeerContext p1;
58
59 static struct PeerContext p2;
60
61
62 static void
63 clean_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
64 {
65   GNUNET_TRANSPORT_disconnect (p1.th);
66   p1.th = NULL;
67   GNUNET_TRANSPORT_disconnect (p2.th);
68   p2.th = NULL;
69   GNUNET_SCHEDULER_shutdown (sched);
70 }
71
72 /**
73  * Timeout, give up.
74  */
75 static void
76 timeout_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
77 {
78   timeout_task = GNUNET_SCHEDULER_NO_TASK;
79   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
80               "Timeout trying to connect peers, test failed.\n");
81   clean_up (NULL, tc);
82 }
83
84
85 /**
86  * Function called to notify transport users that another
87  * peer connected to us.
88  *
89  * @param cls closure
90  * @param peer the peer that connected
91  * @param latency current latency of the connection
92  */
93 static void
94 notify_connect (void *cls,
95                 const struct GNUNET_PeerIdentity * peer,
96                 struct GNUNET_TIME_Relative latency)
97 {
98   if (peer == NULL)
99     return;
100   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
101               "Peers connected, shutting down.\n");
102   GNUNET_assert (ok == 4);
103   ok = 0;
104   GNUNET_SCHEDULER_cancel (sched,
105                            timeout_task);
106   timeout_task = GNUNET_SCHEDULER_NO_TASK;
107   GNUNET_SCHEDULER_add_now (sched,
108                             &clean_up, NULL);
109 }
110
111
112 static void
113 process_hello (void *cls,
114                struct GNUNET_TIME_Relative latency,
115                const struct GNUNET_PeerIdentity *peer,
116                const struct GNUNET_MessageHeader *message)
117 {
118   struct PeerContext *p = cls;
119
120   if (message == NULL)
121     return;
122   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
123               "Received HELLO, starting hostlist service.\n");
124   GNUNET_assert ( (ok >= 2) && (ok <= 3) );
125   ok++;
126   GNUNET_ARM_start_services (p->cfg, sched, "hostlist", NULL);
127 }
128
129
130 static void
131 setup_peer (struct PeerContext *p, const char *cfgname)
132 {
133   p->cfg = GNUNET_CONFIGURATION_create ();
134 #if START_ARM
135   p->arm_pid = GNUNET_OS_start_process ("gnunet-service-arm",
136                                         "gnunet-service-arm",
137 #if VERBOSE
138                                         "-L", "DEBUG",
139 #endif
140                                         "-c", cfgname, NULL);
141 #endif
142   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
143   GNUNET_ARM_start_services (p->cfg, sched, "core", NULL);
144   p->th = GNUNET_TRANSPORT_connect (sched, p->cfg, p, NULL, 
145                                     &notify_connect, NULL);
146   GNUNET_assert (p->th != NULL);
147   GNUNET_TRANSPORT_get_hello (p->th, TIMEOUT, &process_hello, p);
148 }
149
150
151 static void
152 waitpid_task (void *cls, 
153               const struct GNUNET_SCHEDULER_TaskContext *tc)
154 {
155   struct PeerContext *p = cls;
156
157 #if START_ARM 
158   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
159               "Killing ARM process.\n");
160   if (0 != PLIBC_KILL (p->arm_pid, SIGTERM))
161     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
162   if (GNUNET_OS_process_wait(p->arm_pid) != GNUNET_OK)
163     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
164   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
165               "ARM process %u stopped\n", p->arm_pid);
166 #endif
167   GNUNET_CONFIGURATION_destroy (p->cfg);
168 }
169
170
171 static void
172 stop_cb (void *cls, 
173          int success)
174 {
175   struct PeerContext *p = cls;
176
177   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
178               success 
179               ? "ARM stopped core service\n" 
180               : "ARM failed to stop core service\n");
181   GNUNET_ARM_disconnect (p->arm);
182   p->arm = NULL;
183   /* make sure this runs after all other tasks are done */
184   GNUNET_SCHEDULER_add_delayed (sched,
185                                 GNUNET_TIME_UNIT_SECONDS,
186                                 &waitpid_task, p);
187 }
188
189
190 static void
191 stop_arm (struct PeerContext *p)
192 {
193   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
194               "Asking ARM to stop core service\n");
195   p->arm = GNUNET_ARM_connect (p->cfg, sched, NULL);
196   GNUNET_ARM_stop_service (p->arm, "core", GNUNET_TIME_UNIT_SECONDS,
197                            &stop_cb, p);
198 }
199
200
201 /**
202  * Try again to connect to transport service.
203  */
204 static void
205 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
206 {
207   stop_arm (&p1);
208   stop_arm (&p2);
209 }
210
211
212 static void
213 run (void *cls,
214      struct GNUNET_SCHEDULER_Handle *s,
215      char *const *args,
216      const char *cfgfile, 
217      const struct GNUNET_CONFIGURATION_Handle *cfg)
218 {
219   GNUNET_assert (ok == 1);
220   ok++;
221   sched = s;
222   timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
223                                                GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
224                                                                               15),
225                                                &timeout_error,
226                                                NULL);
227   GNUNET_SCHEDULER_add_delayed (sched,
228                                 GNUNET_TIME_UNIT_FOREVER_REL,
229                                 &shutdown_task,
230                                 NULL);
231   setup_peer (&p1, "test_gnunet_daemon_hostlist_peer1.conf");
232   setup_peer (&p2, "test_gnunet_daemon_hostlist_peer2.conf");
233 }
234
235
236 static int
237 check ()
238 {
239   char *const argv[] = { "test-gnunet-daemon-hostlist",
240     "-c", "test_gnunet_daemon_hostlist_data.conf",
241 #if VERBOSE
242     "-L", "DEBUG",
243 #endif
244     NULL
245   };
246   struct GNUNET_GETOPT_CommandLineOption options[] = {
247     GNUNET_GETOPT_OPTION_END
248   };
249   ok = 1;
250   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
251                       argv, "test-gnunet-daemon-hostlist",
252                       "nohelp", options, &run, &ok);
253   return ok;
254 }
255
256
257 int
258 main (int argc, char *argv[])
259 {
260   
261   int ret;
262
263   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-1");
264   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-2");
265   GNUNET_log_setup ("test-gnunet-daemon-hostlist",
266 #if VERBOSE
267                     "DEBUG",
268 #else
269                     "WARNING",
270 #endif
271                     NULL);
272   ret = check ();
273   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-1");
274   GNUNET_DISK_directory_remove ("/tmp/test-gnunetd-hostlist-peer-2");
275   return ret; 
276 }
277
278 /* end of test_gnunet_daemon_hostlist.c */