error handling
[oweals/gnunet.git] / src / core / test_core_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2010, 2015, 2016 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @file core/test_core_api.c
22  * @brief testcase for core_api.c
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include "gnunet_arm_service.h"
27 #include "gnunet_core_service.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_transport_service.h"
30 #include "gnunet_transport_hello_service.h"
31 #include "gnunet_ats_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_OfferHelloHandle *oh;
41   struct GNUNET_TRANSPORT_HelloGetHandle *ghh;
42   struct GNUNET_ATS_ConnectivityHandle *ats;
43   struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh;
44   struct GNUNET_MessageHeader *hello;
45   int connect_status;
46   struct GNUNET_OS_Process *arm_proc;
47 };
48
49 static struct PeerContext p1;
50
51 static struct PeerContext p2;
52
53 static struct GNUNET_SCHEDULER_Task *err_task;
54
55 static int ok;
56
57 #define OKPP                                  \
58   do                                          \
59   {                                           \
60     ok++;                                     \
61     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,      \
62                 "Now at stage %u at %s:%u\n", \
63                 ok,                           \
64                 __FILE__,                     \
65                 __LINE__);                    \
66   } while (0)
67
68
69 static void
70 offer_hello_done (void *cls)
71 {
72   struct PeerContext *p = cls;
73
74   p->oh = NULL;
75 }
76
77
78 static void
79 process_hello (void *cls, const struct GNUNET_MessageHeader *message)
80 {
81   struct PeerContext *p = cls;
82
83   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
84               "Received (my) HELLO from transport service\n");
85   GNUNET_assert (message != NULL);
86   if ((p == &p1) && (NULL == p2.oh))
87     p2.oh =
88       GNUNET_TRANSPORT_offer_hello (p2.cfg, message, &offer_hello_done, &p2);
89   if ((p == &p2) && (NULL == p1.oh))
90     p1.oh =
91       GNUNET_TRANSPORT_offer_hello (p1.cfg, message, &offer_hello_done, &p1);
92 }
93
94
95 static void
96 terminate_peer (struct PeerContext *p)
97 {
98   if (NULL != p->ch)
99   {
100     GNUNET_CORE_disconnect (p->ch);
101     p->ch = NULL;
102   }
103   if (NULL != p->ghh)
104   {
105     GNUNET_TRANSPORT_hello_get_cancel (p->ghh);
106     p->ghh = NULL;
107   }
108   if (NULL != p->oh)
109   {
110     GNUNET_TRANSPORT_offer_hello_cancel (p->oh);
111     p->oh = NULL;
112   }
113   if (NULL != p->ats_sh)
114   {
115     GNUNET_ATS_connectivity_suggest_cancel (p->ats_sh);
116     p->ats_sh = NULL;
117   }
118   if (NULL != p->ats)
119   {
120     GNUNET_ATS_connectivity_done (p->ats);
121     p->ats = NULL;
122   }
123 }
124
125
126 static void
127 terminate_task (void *cls)
128 {
129   GNUNET_assert (ok == 6);
130   terminate_peer (&p1);
131   terminate_peer (&p2);
132   ok = 0;
133 }
134
135
136 static void
137 terminate_task_error (void *cls)
138 {
139   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ENDING ANGRILY %u\n", ok);
140   GNUNET_break (0);
141   terminate_peer (&p1);
142   terminate_peer (&p2);
143   ok = 42;
144 }
145
146
147 static void *
148 connect_notify (void *cls,
149                 const struct GNUNET_PeerIdentity *peer,
150                 struct GNUNET_MQ_Handle *mq)
151 {
152   struct PeerContext *pc = cls;
153   struct GNUNET_MQ_Envelope *env;
154   struct GNUNET_MessageHeader *msg;
155
156   if (0 == memcmp (&pc->id, peer, sizeof(struct GNUNET_PeerIdentity)))
157     return (void *) peer;
158   GNUNET_assert (pc->connect_status == 0);
159   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
160               "Encrypted connection established to peer `%s'\n",
161               GNUNET_i2s (peer));
162   pc->connect_status = 1;
163   if (pc == &p1)
164   {
165     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
166                 "Asking core (1) for transmission to peer `%s'\n",
167                 GNUNET_i2s (&p2.id));
168     env = GNUNET_MQ_msg (msg, MTYPE);
169     /* enable corking for this test */
170     GNUNET_MQ_env_set_options (env,
171                                GNUNET_MQ_PRIO_BEST_EFFORT
172                                | GNUNET_MQ_PREF_CORK_ALLOWED);
173     /* now actually transmit message */
174     GNUNET_assert (ok == 4);
175     OKPP;
176     GNUNET_MQ_send (mq, env);
177   }
178   return (void *) peer;
179 }
180
181
182 static void
183 disconnect_notify (void *cls,
184                    const struct GNUNET_PeerIdentity *peer,
185                    void *internal_cls)
186 {
187   struct PeerContext *pc = cls;
188
189   if (0 == memcmp (&pc->id, peer, sizeof(struct GNUNET_PeerIdentity)))
190     return;
191   pc->connect_status = 0;
192   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
193               "Encrypted connection to `%s' cut\n",
194               GNUNET_i2s (peer));
195 }
196
197
198 static void
199 handle_test (void *cls, const struct GNUNET_MessageHeader *message)
200 {
201   const struct GNUNET_PeerIdentity *peer = cls;
202
203   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
204               "Receiving message from `%s'.\n",
205               GNUNET_i2s (peer));
206   GNUNET_assert (ok == 5);
207   OKPP;
208   GNUNET_SCHEDULER_cancel (err_task);
209   err_task = GNUNET_SCHEDULER_add_now (&terminate_task, NULL);
210 }
211
212
213 static void
214 init_notify (void *cls, const struct GNUNET_PeerIdentity *my_identity)
215 {
216   struct PeerContext *p = cls;
217   struct GNUNET_MQ_MessageHandler handlers[] =
218   { GNUNET_MQ_hd_fixed_size (test, MTYPE, struct GNUNET_MessageHeader, NULL),
219     GNUNET_MQ_handler_end () };
220
221   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
222               "Core connection to `%s' established\n",
223               GNUNET_i2s (my_identity));
224   p->id = *my_identity;
225   if (cls == &p1)
226   {
227     GNUNET_assert (ok == 2);
228     OKPP;
229     /* connect p2 */
230     p2.ch = GNUNET_CORE_connect (p2.cfg,
231                                  &p2,
232                                  &init_notify,
233                                  &connect_notify,
234                                  &disconnect_notify,
235                                  handlers);
236   }
237   else
238   {
239     GNUNET_assert (ok == 3);
240     OKPP;
241     GNUNET_assert (cls == &p2);
242     p1.ats_sh = GNUNET_ATS_connectivity_suggest (p1.ats, &p2.id, 1);
243   }
244 }
245
246
247 static void
248 setup_peer (struct PeerContext *p, const char *cfgname)
249 {
250   char *binary;
251
252   binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
253   p->cfg = GNUNET_CONFIGURATION_create ();
254   p->arm_proc = GNUNET_OS_start_process (GNUNET_YES,
255                                          GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
256                                          NULL,
257                                          NULL,
258                                          NULL,
259                                          binary,
260                                          "gnunet-service-arm",
261                                          "-c",
262                                          cfgname,
263                                          NULL);
264   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
265   p->ats = GNUNET_ATS_connectivity_init (p->cfg);
266   GNUNET_assert (NULL != p->ats);
267   p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg,
268                                        GNUNET_TRANSPORT_AC_ANY,
269                                        &process_hello,
270                                        p);
271   GNUNET_free (binary);
272 }
273
274
275 static void
276 run (void *cls,
277      char *const *args,
278      const char *cfgfile,
279      const struct GNUNET_CONFIGURATION_Handle *cfg)
280 {
281   struct GNUNET_MQ_MessageHandler handlers[] =
282   { GNUNET_MQ_hd_fixed_size (test, MTYPE, struct GNUNET_MessageHeader, NULL),
283     GNUNET_MQ_handler_end () };
284
285   GNUNET_assert (ok == 1);
286   OKPP;
287   setup_peer (&p1, "test_core_api_peer1.conf");
288   setup_peer (&p2, "test_core_api_peer2.conf");
289   err_task = GNUNET_SCHEDULER_add_delayed (
290     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300),
291     &terminate_task_error,
292     NULL);
293   p1.ch = GNUNET_CORE_connect (p1.cfg,
294                                &p1,
295                                &init_notify,
296                                &connect_notify,
297                                &disconnect_notify,
298                                handlers);
299 }
300
301
302 static void
303 stop_arm (struct PeerContext *p)
304 {
305   if (0 != GNUNET_OS_process_kill (p->arm_proc, GNUNET_TERM_SIG))
306     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
307   if (GNUNET_OK != GNUNET_OS_process_wait (p->arm_proc))
308     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
309   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
310               "ARM process %u stopped\n",
311               GNUNET_OS_process_get_pid (p->arm_proc));
312   GNUNET_OS_process_destroy (p->arm_proc);
313   p->arm_proc = NULL;
314   GNUNET_CONFIGURATION_destroy (p->cfg);
315 }
316
317
318 int
319 main (int argc, char *argv1[])
320 {
321   char *const argv[] = { "test-core-api", "-c", "test_core_api_data.conf",
322                          NULL };
323   struct GNUNET_GETOPT_CommandLineOption options[] =
324   { GNUNET_GETOPT_OPTION_END };
325
326   ok = 1;
327   GNUNET_log_setup ("test-core-api", "WARNING", NULL);
328   GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1,
329                       argv,
330                       "test-core-api",
331                       "nohelp",
332                       options,
333                       &run,
334                       &ok);
335   stop_arm (&p1);
336   stop_arm (&p2);
337   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1");
338   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2");
339
340   return ok;
341 }
342
343
344 /* end of test_core_api.c */