- fix #2315
[oweals/gnunet.git] / src / mesh / test_mesh_local_1.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 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 /**
22  * @file mesh/test_mesh_local.c
23  * @brief test mesh local: test of tunnels with just one peer
24  * @author Bartlomiej Polot
25  */
26
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_dht_service.h"
30 #include "gnunet_mesh_service.h"
31
32 #define VERBOSE 1
33 #define VERBOSE_ARM 0
34
35 static struct GNUNET_OS_Process *arm_pid;
36 static struct GNUNET_MESH_Handle *mesh_peer_1;
37 static struct GNUNET_MESH_Handle *mesh_peer_2;
38 static struct GNUNET_MESH_Tunnel *t;
39 static unsigned int one = 1;
40 static unsigned int two = 2;
41
42 static int result;
43 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
44 static GNUNET_SCHEDULER_TaskIdentifier test_task;
45 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
46
47
48 /**
49  * Shutdown nicely
50  */
51 static void
52 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
53 {
54   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: shutdown\n");
55   if (0 != abort_task)
56   {
57     GNUNET_SCHEDULER_cancel (abort_task);
58   }
59   if (NULL != t)
60   {
61     GNUNET_MESH_tunnel_destroy(t);
62   }
63   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: D1\n");
64   if (NULL != mesh_peer_1)
65   {
66     GNUNET_MESH_disconnect (mesh_peer_1);
67   }
68   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: D2\n");
69   if (NULL != mesh_peer_2)
70   {
71     GNUNET_MESH_disconnect (mesh_peer_2);
72   }
73   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: arm\n");
74   if (0 != GNUNET_OS_process_kill (arm_pid, SIGTERM))
75   {
76     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
77   }
78   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Wait\n");
79   GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (arm_pid));
80   GNUNET_OS_process_destroy (arm_pid);
81 }
82
83
84 /**
85  * Something went wrong and timed out. Kill everything and set error flag
86  */
87 static void
88 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
89 {
90   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: ABORT\n");
91   if (0 != test_task)
92   {
93     GNUNET_SCHEDULER_cancel (test_task);
94   }
95   result = GNUNET_SYSERR;
96   abort_task = 0;
97   if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
98   {
99     GNUNET_SCHEDULER_cancel (shutdown_task);
100     shutdown_task = GNUNET_SCHEDULER_NO_TASK;
101   }
102   do_shutdown (cls, tc);
103 }
104
105
106 /**
107  * Function is called whenever a message is received.
108  *
109  * @param cls closure (set from GNUNET_MESH_connect)
110  * @param tunnel connection to the other end
111  * @param tunnel_ctx place to store local state associated with the tunnel
112  * @param sender who sent the message
113  * @param message the actual message
114  * @param atsi performance data for the connection
115  * @return GNUNET_OK to keep the connection open,
116  *         GNUNET_SYSERR to close it (signal serious error)
117  */
118 static int
119 data_callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx,
120                const struct GNUNET_PeerIdentity *sender,
121                const struct GNUNET_MessageHeader *message,
122                const struct GNUNET_ATS_Information *atsi)
123 {
124   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Data callback\n");
125   if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
126     GNUNET_SCHEDULER_cancel (shutdown_task);
127   shutdown_task =
128     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
129                                   (GNUNET_TIME_UNIT_SECONDS, 2), &do_shutdown,
130                                   NULL);
131   return GNUNET_OK;
132 }
133
134
135 /**
136  * Method called whenever another peer has added us to a tunnel
137  * the other peer initiated.
138  *
139  * @param cls closure
140  * @param tunnel new handle to the tunnel
141  * @param initiator peer that started the tunnel
142  * @param atsi performance information for the tunnel
143  * @return initial tunnel context for the tunnel (can be NULL -- that's not an error)
144  */
145 static void *
146 inbound_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
147                 const struct GNUNET_PeerIdentity *initiator,
148                 const struct GNUNET_ATS_Information *atsi)
149 {
150   unsigned int id = *(unsigned int *) cls;
151
152   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: received incoming tunnel\n");
153   if (id != 1)
154   {
155     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
156                 "test: received incoming tunnel on peer 2\n");
157     result = GNUNET_SYSERR;
158   }
159   return NULL;
160 }
161
162
163 /**
164  * Function called whenever an inbound tunnel is destroyed.  Should clean up
165  * any associated state.
166  *
167  * @param cls closure (set from GNUNET_MESH_connect)
168  * @param tunnel connection to the other end (henceforth invalid)
169  * @param tunnel_ctx place where local state associated
170  *                   with the tunnel is stored
171  */
172 static void
173 inbound_end (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
174              void *tunnel_ctx)
175 {
176   unsigned int id = *(unsigned int *) cls;
177
178   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: incoming tunnel closed\n");
179   if (id != 1)
180   {
181     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
182                 "test: received closing tunnel on peer 2\n");
183     result = GNUNET_SYSERR;
184   }
185 }
186
187
188 /**
189  * Method called whenever a peer has connected to the tunnel.
190  *
191  * @param cls closure
192  * @param peer peer identity the tunnel stopped working with
193  */
194 static void
195 peer_conected (void *cls, const struct GNUNET_PeerIdentity *peer,
196                const struct GNUNET_ATS_Information *atsi)
197 {
198   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: peer connected\n");
199   if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
200     GNUNET_SCHEDULER_cancel(shutdown_task);
201   shutdown_task =  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
202                                                  &do_shutdown, NULL);
203 }
204
205
206 /**
207  * Method called whenever a peer has connected to the tunnel.
208  *
209  * @param cls closure
210  * @param peer peer identity the tunnel was created to, NULL on timeout
211  * @param atsi performance data for the connection
212  */
213 static void
214 peer_disconnected (void *cls, const struct GNUNET_PeerIdentity *peer)
215 {
216   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: peer disconnected\n");
217 }
218
219
220 /**
221  * Handler array for traffic received on peer1
222  */
223 static struct GNUNET_MESH_MessageHandler handlers1[] = {
224   {&data_callback, 1, 0},
225   {NULL, 0, 0}
226 };
227
228
229 /**
230  * Handler array for traffic received on peer2 (none expected)
231  */
232 static struct GNUNET_MESH_MessageHandler handlers2[] = { {NULL, 0, 0} };
233
234
235 /**
236  * Start looking for a peer by type
237  */
238 static void
239 do_find (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
240 {
241   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: CONNECT BY TYPE\n");
242   GNUNET_MESH_peer_request_connect_by_type (t, 1);
243 }
244
245
246 /**
247  * Main test function
248  */
249 static void
250 test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
251 {
252   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
253   static const GNUNET_MESH_ApplicationType app1[] = { 1, 0 };
254   static const GNUNET_MESH_ApplicationType app2[] = { 0 };
255
256   test_task = GNUNET_SCHEDULER_NO_TASK;
257   mesh_peer_1 = GNUNET_MESH_connect (cfg,       /* configuration */
258                                      10,        /* queue size */
259                                      (void *) &one,     /* cls */
260                                      &inbound_tunnel,   /* inbound new hndlr */
261                                      &inbound_end,      /* inbound end hndlr */
262                                      handlers1, /* traffic handlers */
263                                      app1);     /* apps offered */
264
265   mesh_peer_2 = GNUNET_MESH_connect (cfg,       /* configuration */
266                                      10,        /* queue size */
267                                      (void *) &two,     /* cls */
268                                      &inbound_tunnel,   /* inbound new hndlr */
269                                      &inbound_end,      /* inbound end hndlr */
270                                      handlers2, /* traffic handlers */
271                                      app2);     /* apps offered */
272   if (NULL == mesh_peer_1 || NULL == mesh_peer_2)
273   {
274     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: Couldn't connect to mesh :(\n");
275     return;
276   }
277   else
278   {
279     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: YAY! CONNECTED TO MESH :D\n");
280   }
281
282   t = GNUNET_MESH_tunnel_create (mesh_peer_2, NULL, &peer_conected,
283                                  &peer_disconnected, (void *) &two);
284   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &do_find, NULL);
285 }
286
287
288 /**
289  * Initialize framework and start test
290  */
291 static void
292 run (void *cls, char *const *args, const char *cfgfile,
293      const struct GNUNET_CONFIGURATION_Handle *cfg)
294 {
295   GNUNET_log_setup ("test_mesh_local",
296 #if VERBOSE
297                     "DEBUG",
298 #else
299                     "WARNING",
300 #endif
301                     NULL);
302   arm_pid =
303       GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm",
304                                "gnunet-service-arm",
305 #if VERBOSE_ARM
306                                "-L", "DEBUG",
307 #endif
308                                "-c", "test_mesh.conf", NULL);
309
310   abort_task =
311       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
312                                     (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort,
313                                     NULL);
314
315   test_task = GNUNET_SCHEDULER_add_now (&test, (void *) cfg);
316
317 }
318
319
320 /**
321  * Main
322  */
323 int
324 main (int argc, char *argv[])
325 {
326   int ret;
327
328   char *const argv2[] = { "test-mesh-local",
329     "-c", "test_mesh.conf",
330 #if VERBOSE
331     "-L", "DEBUG",
332 #endif
333     NULL
334   };
335   struct GNUNET_GETOPT_CommandLineOption options[] = {
336     GNUNET_GETOPT_OPTION_END
337   };
338
339   result = GNUNET_OK;
340   ret =
341       GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
342                           "test-mesh-local", "nohelp", options, &run, NULL);
343
344   if (GNUNET_OK != ret)
345   {
346     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "run failed with error code %d\n",
347                 ret);
348     return 1;
349   }
350   if (GNUNET_SYSERR == result)
351   {
352     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
353                 "test failed: connect and find_by_type\n");
354     return 1;
355   }
356   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test ok\n");
357   return 0;
358 }