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