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