- wip
[oweals/gnunet.git] / src / mesh / test_mesh_local_traffic.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 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_traffic.c
23  * @brief test mesh local traffic: 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_mesh_service.h"
30 #include "gnunet_testing_lib-new.h"
31 #include <gauger.h>
32
33 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
34
35 #define TARGET 10
36
37 GNUNET_NETWORK_STRUCT_BEGIN
38
39 struct test_traffic_message
40 {
41   struct GNUNET_MessageHeader header;
42   uint32_t data GNUNET_PACKED;
43 };
44
45 GNUNET_NETWORK_STRUCT_END
46
47
48 static struct GNUNET_MESH_Handle *mesh_peer_1;
49
50 static struct GNUNET_MESH_Handle *mesh_peer_2;
51
52 static struct GNUNET_MESH_Tunnel *t;
53
54 static unsigned int one = 1;
55
56 static unsigned int two = 2;
57
58 static int result = GNUNET_SYSERR;
59
60 static unsigned int sent = 0;
61
62 static unsigned int got = 0;
63
64 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
65
66 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
67
68 static struct GNUNET_TIME_Absolute start_time;
69
70 static struct GNUNET_TIME_Absolute end_time;
71
72 static struct GNUNET_PeerIdentity peer_id;
73
74
75 /**
76  * Shutdown nicely
77  */
78 static void
79 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
80 {
81   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutdown\n");
82   if (0 != abort_task)
83   {
84     GNUNET_SCHEDULER_cancel (abort_task);
85   }
86   if (NULL != t)
87   {
88     GNUNET_MESH_tunnel_destroy(t);
89   }
90   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "D1\n");
91   if (NULL != mesh_peer_1)
92   {
93     GNUNET_MESH_disconnect (mesh_peer_1);
94   }
95   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "D2\n");
96   if (NULL != mesh_peer_2)
97   {
98     GNUNET_MESH_disconnect (mesh_peer_2);
99   }
100 }
101
102
103 /**
104  * Something went wrong and timed out. Kill everything and set error flag
105  */
106 static void
107 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
108 {
109   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "ABORT\n");
110   result = GNUNET_SYSERR;
111   abort_task = 0;
112   if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
113   {
114     GNUNET_SCHEDULER_cancel (shutdown_task);
115     shutdown_task = GNUNET_SCHEDULER_NO_TASK;
116   }
117   do_shutdown (cls, tc);
118 }
119
120 static void
121 finish(void)
122 {
123   if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
124     GNUNET_SCHEDULER_cancel(shutdown_task);
125   shutdown_task =  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
126                                                  &do_shutdown, NULL);
127 }
128
129
130 /**
131  * Function is called whenever a message is received.
132  *
133  * @param cls closure (set from GNUNET_MESH_connect)
134  * @param tunnel connection to the other end
135  * @param tunnel_ctx place to store local state associated with the tunnel
136  * @param sender who sent the message
137  * @param message the actual message
138  * @param atsi performance data for the connection
139  * @return GNUNET_OK to keep the connection open,
140  *         GNUNET_SYSERR to close it (signal serious error)
141  */
142 static int
143 data_callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx,
144                const struct GNUNET_PeerIdentity *sender,
145                const struct GNUNET_MessageHeader *message,
146                const struct GNUNET_ATS_Information *atsi)
147 {
148   struct test_traffic_message *msg;
149
150   msg = (struct test_traffic_message *) message;
151   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got data packet # %u [%u]\n",
152               ntohl (msg->data), got + 1);
153   got++;
154   if (TARGET == got)
155   {
156     end_time = GNUNET_TIME_absolute_get();
157     result = GNUNET_OK;
158     finish();
159     return GNUNET_OK;
160   }
161   if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
162     GNUNET_SCHEDULER_cancel (shutdown_task);
163   shutdown_task =
164     GNUNET_SCHEDULER_add_delayed (TIMEOUT, &do_shutdown,
165                                   NULL);
166   return GNUNET_OK;
167 }
168
169
170 /**
171  * Method called whenever another peer has added us to a tunnel
172  * the other peer initiated.
173  *
174  * @param cls closure
175  * @param tunnel new handle to the tunnel
176  * @param initiator peer that started the tunnel
177  * @param atsi performance information for the tunnel
178  * @return initial tunnel context for the tunnel (can be NULL -- that's not an error)
179  */
180 static void *
181 inbound_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
182                 const struct GNUNET_PeerIdentity *initiator,
183                 const struct GNUNET_ATS_Information *atsi)
184 {
185   unsigned int id = *(unsigned int *) cls;
186
187   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "received incoming tunnel\n");
188   if (id != 1)
189   {
190     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
191                 "received incoming tunnel on peer 2\n");
192     result = GNUNET_SYSERR;
193   }
194   return NULL;
195 }
196
197
198 /**
199  * Function called whenever an inbound tunnel is destroyed.  Should clean up
200  * any associated state.
201  *
202  * @param cls closure (set from GNUNET_MESH_connect)
203  * @param tunnel connection to the other end (henceforth invalid)
204  * @param tunnel_ctx place where local state associated
205  *                   with the tunnel is stored
206  */
207 static void
208 inbound_end (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
209              void *tunnel_ctx)
210 {
211   unsigned int id = *(unsigned int *) cls;
212
213   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "incoming tunnel closed\n");
214   if (id != 1)
215   {
216     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
217                 "received closing tunnel on peer 2\n");
218     result = GNUNET_SYSERR;
219   }
220 }
221
222
223 /**
224  * Transmit ready callback.
225  * 
226  * @param cls Closure.
227  * @param size Buffer size.
228  * @param buf Buffer.
229  */
230 static size_t
231 tmt_rdy (void *cls, size_t size, void *buf)
232 {
233   struct GNUNET_MessageHeader *m = buf;
234   struct test_traffic_message *msg = buf;
235   size_t msize = sizeof (struct test_traffic_message);
236
237   if (0 == size || NULL == buf)
238     return 0;
239   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending data packet # %u\n",
240               sent);
241   GNUNET_assert (size >= msize);
242   sent++;
243   if (TARGET > sent)
244     GNUNET_MESH_notify_transmit_ready (t, GNUNET_NO,
245                                        GNUNET_TIME_UNIT_FOREVER_REL,
246                                        &peer_id, msize, &tmt_rdy, NULL);
247   m->size = htons (msize);
248   m->type = htons (1);
249   msg->data = htonl (sent - 1);
250   return msize;
251 }
252
253
254 /**
255  * Method called whenever a peer has connected to the tunnel.
256  *
257  * @param cls Closure.
258  * @param peer Peer identity of connected peer.
259  */
260 static void
261 peer_connected (void *cls, const struct GNUNET_PeerIdentity *peer,
262                const struct GNUNET_ATS_Information *atsi)
263 {
264   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "peer connected\n");
265   peer_id = *peer;
266   start_time = GNUNET_TIME_absolute_get();
267   GNUNET_MESH_notify_transmit_ready (t, GNUNET_NO, GNUNET_TIME_UNIT_FOREVER_REL,
268                                      peer, sizeof (struct test_traffic_message),
269                                      &tmt_rdy, NULL);
270 }
271
272
273 /**
274  * Method called whenever a peer has connected to the tunnel.
275  *
276  * @param cls closure
277  * @param peer peer identity the tunnel was created to, NULL on timeout
278  * @param atsi performance data for the connection
279  */
280 static void
281 peer_disconnected (void *cls, const struct GNUNET_PeerIdentity *peer)
282 {
283   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "peer disconnected\n");
284 }
285
286
287 /**
288  * Handler array for traffic received on peer1
289  */
290 static struct GNUNET_MESH_MessageHandler handlers1[] = {
291   {&data_callback, 1, 0},
292   {NULL, 0, 0}
293 };
294
295
296 /**
297  * Handler array for traffic received on peer2 (none expected)
298  */
299 static struct GNUNET_MESH_MessageHandler handlers2[] = { {NULL, 0, 0} };
300
301
302 /**
303  * Initialize framework and start test
304  */
305 static void
306 run (void *cls, 
307      const struct GNUNET_CONFIGURATION_Handle *cfg,
308      struct GNUNET_TESTING_Peer *peer)
309 {
310   static const GNUNET_MESH_ApplicationType app1[] = { 1, 0 };
311   static const GNUNET_MESH_ApplicationType app2[] = { 0 };
312
313   abort_task =
314       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
315                                     (GNUNET_TIME_UNIT_SECONDS, 20), &do_abort,
316                                     NULL);
317   mesh_peer_1 = GNUNET_MESH_connect (cfg,       /* configuration */
318                                      (void *) &one,     /* cls */
319                                      &inbound_tunnel,   /* inbound new hndlr */
320                                      &inbound_end,      /* inbound end hndlr */
321                                      handlers1, /* traffic handlers */
322                                      app1);     /* apps offered */
323
324   mesh_peer_2 = GNUNET_MESH_connect (cfg,       /* configuration */
325                                      (void *) &two,     /* cls */
326                                      NULL,   /* inbound new hndlr */
327                                      NULL,      /* inbound end hndlr */
328                                      handlers2, /* traffic handlers */
329                                      app2);     /* apps offered */
330   if (NULL == mesh_peer_1 || NULL == mesh_peer_2)
331   {
332     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Couldn't connect to mesh\n");
333     result = GNUNET_SYSERR;
334     return;
335   }
336   else
337   {
338     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected to mesh\n");
339   }
340   t = GNUNET_MESH_tunnel_create (mesh_peer_2, NULL, &peer_connected,
341                                  &peer_disconnected, (void *) &two);
342   GNUNET_MESH_peer_request_connect_by_type (t, 1);
343 }
344
345
346 /**
347  * Main
348  */
349 int
350 main (int argc, char *argv[])
351 {
352   if (0 != GNUNET_TESTING_peer_run ("test-mesh-local-traffic",
353                                     "test_mesh.conf",
354                                     &run, NULL))
355     return 1;
356   if (result != GNUNET_OK)
357   {
358     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
359                 "Failed. Sent: %u, Got: %u\n",
360                 sent, got);
361     return 1;
362   }
363   else
364   {
365     struct GNUNET_TIME_Relative total_time;
366
367     total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time);
368     FPRINTF (stderr, "\nTest time %llu ms\n",
369              (unsigned long long) total_time.rel_value);
370     FPRINTF (stderr, "Test payload bandwidth: %f kb/s\n",
371              4 * 1000.0 / total_time.rel_value); // 4bytes * ms
372     FPRINTF (stderr, "Test throughput: %f packets/s\n\n",
373              TARGET * 1000.0 / total_time.rel_value); // 1000 packets * ms
374     GAUGER ("MESH", "Local traffic default", TARGET * 1000.0 / total_time.rel_value,
375             "packets/s");
376   }
377   return 0;
378 }
379
380 /* end of test_mesh_local_traffic.c */