more refactoring of tests for new send API
[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
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
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 * FACTOR)
52
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", 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 - 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; 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_MessageHeader *message)
212 {
213   static int n;
214   unsigned int s;
215   char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
216   const struct GNUNET_TRANSPORT_TESTING_TestMessage *hdr;
217
218   hdr = (const struct GNUNET_TRANSPORT_TESTING_TestMessage *) message;
219
220   if (GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (message->type))
221     return;
222   msg_recv = ntohl (hdr->num);
223   s = get_size (ntohl (hdr->num));
224
225   if (ntohs (message->size) != s)
226   {
227     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
228                 "Expected message %u of size %u, got %u bytes of message %u\n",
229                 ntohl (hdr->num),
230                 s,
231                 ntohs (message->size),
232                 ntohl (hdr->num));
233     ccc->global_ret = GNUNET_SYSERR;
234     GNUNET_SCHEDULER_shutdown ();
235     return;
236   }
237
238   memset (cbuf,
239           ntohl (hdr->num),
240           s - sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage));
241   if (0 !=
242       memcmp (cbuf,
243               &hdr[1],
244               s - sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage)))
245   {
246     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
247                 "Expected message %u with bits %u, but body did not match\n",
248                 ntohl (hdr->num),
249                 (unsigned char) ntohl (hdr->num));
250     ccc->global_ret = GNUNET_SYSERR;
251     GNUNET_SCHEDULER_shutdown ();
252     return;
253   }
254 #if VERBOSE
255   if (0 == ntohl (hdr->num) % 5)
256   {
257     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
258                 "Got message %u of size %u\n",
259                 ntohl (hdr->num),
260                 ntohs (message->size));
261   }
262 #endif
263   n++;
264   if (GNUNET_SYSERR == set_bit (ntohl (hdr->num)))
265   {
266       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
267                   "Message id %u is bigger than maxmimum number of messages %u expected\n",
268                   ntohl (hdr->num),
269                   TOTAL_MSGS);
270   }
271   if (0 == (n % (TOTAL_MSGS / 100)))
272   {
273     FPRINTF (stderr, "%s",  ".");
274   }
275   if (n == TOTAL_MSGS)
276   {
277     /* end testcase with success */
278     ccc->global_ret = GNUNET_OK;
279     GNUNET_SCHEDULER_shutdown ();
280   }
281 }
282
283
284 int
285 main (int argc, char *argv[])
286 {
287   struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
288     .num_messages = TOTAL_MSGS,
289     .get_size_cb = &get_size_cnt
290   };
291   struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
292     .connect_continuation = &GNUNET_TRANSPORT_TESTING_simple_send,
293     .connect_continuation_cls = &sc,
294     .config_file = "test_transport_api_data.conf",
295     .rec = &notify_receive,
296     .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
297     .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
298     .shutdown_task = &custom_shutdown,
299     .timeout = TIMEOUT,
300     .global_ret = GNUNET_SYSERR
301   };
302
303   ccc = &my_ccc;
304   sc.ccc = ccc;
305   start_time = GNUNET_TIME_absolute_get ();
306   if (GNUNET_OK !=
307       GNUNET_TRANSPORT_TESTING_main (2,
308                                      &GNUNET_TRANSPORT_TESTING_connect_check,
309                                      ccc))
310     return 1;
311   return 0;
312 }
313
314
315 /* end of test_transport_api_reliability.c */