-style fix
[oweals/gnunet.git] / src / core / test_core_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 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 core/test_core_api.c
22  * @brief testcase for core_api.c
23  */
24 #include "platform.h"
25 #include "gnunet_arm_service.h"
26 #include "gnunet_core_service.h"
27 #include "gnunet_getopt_lib.h"
28 #include "gnunet_os_lib.h"
29 #include "gnunet_program_lib.h"
30 #include "gnunet_scheduler_lib.h"
31 #include "gnunet_transport_service.h"
32
33 #define MTYPE 12345
34
35 struct PeerContext
36 {
37   struct GNUNET_CONFIGURATION_Handle *cfg;
38   struct GNUNET_CORE_Handle *ch;
39   struct GNUNET_PeerIdentity id;
40   struct GNUNET_TRANSPORT_Handle *th;
41   struct GNUNET_TRANSPORT_GetHelloHandle *ghh;
42   struct GNUNET_MessageHeader *hello;
43   int connect_status;
44   struct GNUNET_OS_Process *arm_proc;
45 };
46
47 static struct PeerContext p1;
48
49 static struct PeerContext p2;
50
51 static GNUNET_SCHEDULER_TaskIdentifier err_task;
52
53 static GNUNET_SCHEDULER_TaskIdentifier con_task;
54
55 static int ok;
56
57 #define OKPP do { ok++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
58
59
60 static void
61 process_hello (void *cls, const struct GNUNET_MessageHeader *message)
62 {
63   struct PeerContext *p = cls;
64
65   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
66               "Received (my) `%s' from transport service\n", "HELLO");
67   GNUNET_assert (message != NULL);
68   if ((p == &p1) && (p2.th != NULL))
69     GNUNET_TRANSPORT_offer_hello (p2.th, message, NULL, NULL);
70   if ((p == &p2) && (p1.th != NULL))
71     GNUNET_TRANSPORT_offer_hello (p1.th, message, NULL, NULL);
72 }
73
74
75 static void
76 terminate_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
77 {
78   GNUNET_assert (ok == 6);
79   GNUNET_CORE_disconnect (p1.ch);
80   p1.ch = NULL;
81   GNUNET_CORE_disconnect (p2.ch);
82   p2.ch = NULL;
83   GNUNET_TRANSPORT_get_hello_cancel (p1.ghh);
84   p1.ghh = NULL;
85   GNUNET_TRANSPORT_get_hello_cancel (p2.ghh);
86   p2.ghh = NULL;
87   GNUNET_TRANSPORT_disconnect (p1.th);
88   p1.th = NULL;
89   GNUNET_TRANSPORT_disconnect (p2.th);
90   p2.th = NULL;
91   if (GNUNET_SCHEDULER_NO_TASK != con_task)
92   {
93     GNUNET_SCHEDULER_cancel (con_task);
94     con_task = GNUNET_SCHEDULER_NO_TASK;
95   }
96   ok = 0;
97 }
98
99
100 static void
101 terminate_task_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
102 {
103   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
104               "ENDING ANGRILY %u\n", ok);
105   GNUNET_break (0);
106   if (NULL != p1.ch)
107   {
108     GNUNET_CORE_disconnect (p1.ch);
109     p1.ch = NULL;
110   }
111   if (NULL != p2.ch)
112   {
113     GNUNET_CORE_disconnect (p2.ch);
114     p2.ch = NULL;
115   }
116   if (p1.th != NULL)
117   {
118     GNUNET_TRANSPORT_get_hello_cancel (p1.ghh);
119     GNUNET_TRANSPORT_disconnect (p1.th);
120     p1.th = NULL;
121   }
122   if (p2.th != NULL)
123   {
124     GNUNET_TRANSPORT_get_hello_cancel (p2.ghh);
125     GNUNET_TRANSPORT_disconnect (p2.th);
126     p2.th = NULL;
127   }
128   if (GNUNET_SCHEDULER_NO_TASK != con_task)
129   {
130     GNUNET_SCHEDULER_cancel (con_task);
131     con_task = GNUNET_SCHEDULER_NO_TASK;
132   }
133   ok = 42;
134 }
135
136
137 static size_t
138 transmit_ready (void *cls, size_t size, void *buf)
139 {
140   struct PeerContext *p = cls;
141   struct GNUNET_MessageHeader *m;
142
143   GNUNET_assert (ok == 4);
144   OKPP;
145   GNUNET_assert (p == &p1);
146   GNUNET_assert (buf != NULL);
147   m = (struct GNUNET_MessageHeader *) buf;
148   m->type = htons (MTYPE);
149   m->size = htons (sizeof (struct GNUNET_MessageHeader));
150   return sizeof (struct GNUNET_MessageHeader);
151 }
152
153
154 static void
155 connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer)
156 {
157   struct PeerContext *pc = cls;
158
159   if (0 == memcmp (&pc->id, peer, sizeof (struct GNUNET_PeerIdentity)))
160     return;
161   GNUNET_assert (pc->connect_status == 0);
162   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
163               "Encrypted connection established to peer `%4s'\n",
164               GNUNET_i2s (peer));
165   if (GNUNET_SCHEDULER_NO_TASK != con_task)
166   {
167     GNUNET_SCHEDULER_cancel (con_task);
168     con_task = GNUNET_SCHEDULER_NO_TASK;
169   }
170   pc->connect_status = 1;
171   if (pc == &p1)
172   {
173     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
174                 "Asking core (1) for transmission to peer `%4s'\n",
175                 GNUNET_i2s (&p2.id));
176     if (NULL ==
177         GNUNET_CORE_notify_transmit_ready (p1.ch, GNUNET_YES, 0,
178                                            GNUNET_TIME_relative_multiply
179                                            (GNUNET_TIME_UNIT_SECONDS, 145),
180                                            &p2.id,
181                                            sizeof (struct GNUNET_MessageHeader),
182                                            &transmit_ready, &p1))
183     {
184       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
185                   "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n",
186                   GNUNET_i2s (&p2.id));
187     }
188   }
189 }
190
191
192 static void
193 disconnect_notify (void *cls, const struct GNUNET_PeerIdentity *peer)
194 {
195   struct PeerContext *pc = cls;
196
197   if (0 == memcmp (&pc->id, peer, sizeof (struct GNUNET_PeerIdentity)))
198     return;
199   pc->connect_status = 0;
200   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted connection to `%4s' cut\n",
201               GNUNET_i2s (peer));
202 }
203
204
205 static int
206 inbound_notify (void *cls, const struct GNUNET_PeerIdentity *other,
207                 const struct GNUNET_MessageHeader *message)
208 {
209   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
210               "Core provides inbound data from `%4s'.\n", GNUNET_i2s (other));
211   return GNUNET_OK;
212 }
213
214
215 static int
216 outbound_notify (void *cls, const struct GNUNET_PeerIdentity *other,
217                  const struct GNUNET_MessageHeader *message)
218 {
219   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
220               "Core notifies about outbound data for `%4s'.\n",
221               GNUNET_i2s (other));
222   return GNUNET_OK;
223 }
224
225
226
227 static int
228 process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer,
229                const struct GNUNET_MessageHeader *message)
230 {
231   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving message from `%4s'.\n",
232               GNUNET_i2s (peer));
233   GNUNET_assert (ok == 5);
234   OKPP;
235   GNUNET_SCHEDULER_cancel (err_task);
236   err_task = GNUNET_SCHEDULER_add_now (&terminate_task, NULL);
237   return GNUNET_OK;
238 }
239
240
241 static struct GNUNET_CORE_MessageHandler handlers[] = {
242   {&process_mtype, MTYPE, sizeof (struct GNUNET_MessageHeader)},
243   {NULL, 0, 0}
244 };
245
246
247 static void
248 connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
249 {
250   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
251   {
252     con_task = GNUNET_SCHEDULER_NO_TASK;
253     return;
254   }
255   con_task =
256       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &connect_task,
257                                     NULL);
258   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
259               "Asking transport (1) to connect to peer `%4s'\n",
260               GNUNET_i2s (&p2.id));
261   GNUNET_TRANSPORT_try_connect (p1.th, &p2.id, NULL, NULL); /*FIXME TRY_CONNECT change */
262 }
263
264
265 static void
266 init_notify (void *cls,
267              const struct GNUNET_PeerIdentity *my_identity)
268 {
269   struct PeerContext *p = cls;
270
271   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core connection to `%4s' established\n",
272               GNUNET_i2s (my_identity));
273   p->id = *my_identity;
274   if (cls == &p1)
275   {
276     GNUNET_assert (ok == 2);
277     OKPP;
278     /* connect p2 */
279     p2.ch =
280         GNUNET_CORE_connect (p2.cfg, &p2, &init_notify, &connect_notify,
281                              &disconnect_notify, &inbound_notify, GNUNET_YES,
282                              &outbound_notify, GNUNET_YES, handlers);
283   }
284   else
285   {
286     GNUNET_assert (ok == 3);
287     OKPP;
288     GNUNET_assert (cls == &p2);
289     con_task = GNUNET_SCHEDULER_add_now (&connect_task, NULL);
290   }
291 }
292
293
294 static void
295 setup_peer (struct PeerContext *p, const char *cfgname)
296 {
297   char *binary;
298
299   binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
300   p->cfg = GNUNET_CONFIGURATION_create ();
301   p->arm_proc =
302     GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
303                              NULL, NULL,
304                              binary,
305                              "gnunet-service-arm",
306                                "-c", cfgname, NULL);
307   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
308   p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, NULL, NULL);
309   GNUNET_assert (p->th != NULL);
310   p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p);
311   GNUNET_free (binary);
312 }
313
314
315 static void
316 run (void *cls, char *const *args, const char *cfgfile,
317      const struct GNUNET_CONFIGURATION_Handle *cfg)
318 {
319   GNUNET_assert (ok == 1);
320   OKPP;
321   setup_peer (&p1, "test_core_api_peer1.conf");
322   setup_peer (&p2, "test_core_api_peer2.conf");
323   err_task =
324       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
325                                     (GNUNET_TIME_UNIT_SECONDS, 300),
326                                     &terminate_task_error, NULL);
327   p1.ch =
328       GNUNET_CORE_connect (p1.cfg, &p1, &init_notify, &connect_notify,
329                            &disconnect_notify, &inbound_notify, GNUNET_YES,
330                            &outbound_notify, GNUNET_YES, handlers);
331 }
332
333
334 static void
335 stop_arm (struct PeerContext *p)
336 {
337   if (0 != GNUNET_OS_process_kill (p->arm_proc, GNUNET_TERM_SIG))
338     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
339   if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK)
340     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
341   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n",
342               GNUNET_OS_process_get_pid (p->arm_proc));
343   GNUNET_OS_process_destroy (p->arm_proc);
344   p->arm_proc = NULL;
345   GNUNET_CONFIGURATION_destroy (p->cfg);
346 }
347
348
349 int
350 main (int argc, char *argv1[])
351 {
352   char *const argv[] = { "test-core-api",
353     "-c",
354     "test_core_api_data.conf",
355     NULL
356   };
357   struct GNUNET_GETOPT_CommandLineOption options[] = {
358     GNUNET_GETOPT_OPTION_END
359   };
360   ok = 1;
361   GNUNET_log_setup ("test-core-api",
362                     "WARNING",
363                     NULL);
364   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
365                       "test-core-api", "nohelp", options, &run, &ok);
366   stop_arm (&p1);
367   stop_arm (&p2);
368   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1");
369   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2");
370
371   return ok;
372 }
373
374 /* end of test_core_api.c */