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