glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / transport / test_transport_api_reliability.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2010, 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 /**
16  * @file transport/test_transport_api_reliability.c
17  * @brief base test case for transport implementations
18  *
19  * This test case serves ensures that messages are reliably sent between peers
20  *
21  * This test sends TOTAL_MSGS with message type MTYPE from peer 1 to peer 2
22  * and ensures that all message were received.
23  */
24 #include "platform.h"
25 #include "gnunet_transport_service.h"
26 #include "gauger.h"
27 #include "transport-testing.h"
28
29 /**
30  * Allow making the problem "bigger".
31  */
32 #define FACTOR 1
33
34 /**
35  * Total number of messages to send
36  *
37  * Note that this value must not significantly exceed
38  * 'MAX_PENDING' in 'gnunet-service-transport_clients.c', otherwise
39  * messages may be dropped even for a reliable transport.
40  */
41 #define TOTAL_MSGS (1024 * 3 * FACTOR)
42
43 /**
44  * Testcase timeout
45  */
46 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 450 * FACTOR)
47
48 /**
49  * If we are in an "xhdr" test, the factor by which we divide
50  * #TOTAL_MSGS for a more sane test duration.
51  */
52 static unsigned int xhdr = 1;
53
54 static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
55
56 /**
57  * Total amount of bytes sent
58  */
59 static unsigned long long total_bytes;
60
61 /**
62  * Time of start
63  */
64 static struct GNUNET_TIME_Absolute start_time;
65
66 /**
67  * No. of last message received
68  */
69 static unsigned int msg_recv;
70
71 /**
72  * Bitmap storing which messages were received
73  */
74 static char bitmap[TOTAL_MSGS / 8];
75
76
77 /**
78  * Get the desired message size for message number @a iter.
79  */
80 static size_t
81 get_size (unsigned int iter)
82 {
83   size_t ret;
84
85   ret = (iter * iter * iter);
86 #ifndef LINUX
87   /* FreeBSD/OSX etc. Unix DGRAMs do not work
88    * with large messages */
89   if (0 == strcmp ("unix", ccc->test_plugin))
90     ret = sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage) + (ret % 1024);
91 #endif
92   ret = sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage) + (ret % 60000);
93   return ret;
94 }
95
96
97 /**
98  * Implementation of the callback for obtaining the
99  * size of messages for transmission.  Counts the total
100  * number of bytes sent as a side-effect.
101  *
102  * @param cnt_down count down from `TOTAL_MSGS - 1`
103  * @return message size of the message
104  */
105 static size_t
106 get_size_cnt (unsigned int cnt_down)
107 {
108   size_t ret = get_size (TOTAL_MSGS / xhdr - 1 - cnt_down);
109
110   total_bytes += ret;
111   return ret;
112 }
113
114
115 /**
116  * Sets a bit active in the bitmap.
117  *
118  * @param bitIdx which bit to set
119  * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
120  */
121 static int
122 set_bit (unsigned int bitIdx)
123 {
124   size_t arraySlot;
125   unsigned int targetBit;
126
127   if (bitIdx >= sizeof (bitmap) * 8)
128   {
129     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
130                 "tried to set bit %u of %u(!?!?)\n",
131                 bitIdx,
132                 (unsigned int) sizeof (bitmap) * 8);
133     return GNUNET_SYSERR;
134   }
135   arraySlot = bitIdx / 8;
136   targetBit = (1L << (bitIdx % 8));
137   bitmap[arraySlot] |= targetBit;
138   return GNUNET_OK;
139 }
140
141
142 /**
143  * Obtain a bit from bitmap.
144  * @param map the bitmap
145  * @param bit index from bitmap
146  *
147  * @return Bit @a bit from @a map
148  */
149 static int
150 get_bit (const char *map,
151          unsigned int bit)
152 {
153   if (bit > TOTAL_MSGS)
154   {
155     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
156                 "get bit %u of %u(!?!?)\n",
157                 bit,
158                 (unsigned int) sizeof (bitmap) * 8);
159     return 0;
160   }
161   return ((map)[bit >> 3] & (1 << (bit & 7))) > 0;
162 }
163
164
165 static void
166 custom_shutdown (void *cls)
167 {
168   unsigned long long delta;
169   unsigned long long rate;
170   int ok;
171
172   /* Calculcate statistics   */
173   delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value_us;
174   rate = (1000LL* 1000ll * total_bytes) / (1024 * delta);
175   FPRINTF (stderr,
176            "\nThroughput was %llu KiBytes/s\n",
177            rate);
178   {
179     char *value_name;
180
181     GNUNET_asprintf (&value_name,
182                      "unreliable_%s",
183                      ccc->test_plugin);
184     GAUGER ("TRANSPORT",
185             value_name,
186             (int) rate,
187             "kb/s");
188     GNUNET_free (value_name);
189   }
190
191   ok = 0;
192   for (unsigned int i = 0; i < TOTAL_MSGS / xhdr; i++)
193   {
194     if (get_bit (bitmap, i) == 0)
195     {
196       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
197                   "Did not receive message %d\n",
198                   i);
199       ok = -1;
200     }
201   }
202   if (0 != ok)
203     ccc->global_ret = GNUNET_SYSERR; /* fail: messages missing! */
204 }
205
206
207 static void
208 notify_receive (void *cls,
209                 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
210                 const struct GNUNET_PeerIdentity *sender,
211                 const struct GNUNET_TRANSPORT_TESTING_TestMessage *hdr)
212 {
213   static int n;
214   unsigned int s;
215   char cbuf[GNUNET_MAX_MESSAGE_SIZE - 1];
216
217   if (GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (hdr->header.type))
218     return;
219   msg_recv = ntohl (hdr->num);
220   s = get_size (ntohl (hdr->num));
221
222   if (ntohs (hdr->header.size) != s)
223   {
224     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
225                 "Expected message %u of size %u, got %u bytes of message %u\n",
226                 (uint32_t) ntohl (hdr->num),
227                 s,
228                 ntohs (hdr->header.size),
229                 (uint32_t) ntohl (hdr->num));
230     ccc->global_ret = GNUNET_SYSERR;
231     GNUNET_SCHEDULER_shutdown ();
232     return;
233   }
234
235   memset (cbuf,
236           ntohl (hdr->num),
237           s - sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage));
238   if (0 !=
239       memcmp (cbuf,
240               &hdr[1],
241               s - sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage)))
242   {
243     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
244                 "Expected message %u with bits %u, but body did not match\n",
245                 (uint32_t) ntohl (hdr->num),
246                 (unsigned char) ntohl (hdr->num));
247     ccc->global_ret = GNUNET_SYSERR;
248     GNUNET_SCHEDULER_shutdown ();
249     return;
250   }
251 #if VERBOSE
252   if (0 == ntohl (hdr->num) % 5)
253   {
254     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
255                 "Got message %u of size %u\n",
256                 (uint32_t) ntohl (hdr->num),
257                 ntohs (hdr->header.size));
258   }
259 #endif
260   n++;
261   if (GNUNET_SYSERR == set_bit (ntohl (hdr->num)))
262   {
263       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
264                   "Message id %u is bigger than maxmimum number of messages %u expected\n",
265                   (uint32_t) ntohl (hdr->num),
266                   TOTAL_MSGS / xhdr);
267   }
268   if (0 == (n % (TOTAL_MSGS / xhdr / 100)))
269   {
270     FPRINTF (stderr, "%s",  ".");
271   }
272   if (n == TOTAL_MSGS / xhdr)
273   {
274     /* end testcase with success */
275     ccc->global_ret = GNUNET_OK;
276     GNUNET_SCHEDULER_shutdown ();
277   }
278 }
279
280
281 int
282 main (int argc, char *argv[])
283 {
284   if (0 == strstr (argv[0], "xhdr"))
285     xhdr = 30;
286   struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
287     .num_messages = TOTAL_MSGS / xhdr,
288     .get_size_cb = &get_size_cnt
289   };
290   struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
291     .connect_continuation = &GNUNET_TRANSPORT_TESTING_simple_send,
292     .connect_continuation_cls = &sc,
293     .config_file = "test_transport_api_data.conf",
294     .rec = &notify_receive,
295     .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
296     .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
297     .shutdown_task = &custom_shutdown,
298     .timeout = TIMEOUT,
299     .global_ret = GNUNET_SYSERR
300   };
301
302   ccc = &my_ccc;
303   sc.ccc = ccc;
304   start_time = GNUNET_TIME_absolute_get ();
305   if (GNUNET_OK !=
306       GNUNET_TRANSPORT_TESTING_main (2,
307                                      &GNUNET_TRANSPORT_TESTING_connect_check,
308                                      ccc))
309     return 1;
310   return 0;
311 }
312
313
314 /* end of test_transport_api_reliability.c */