more refactoring of tests for new send API
[oweals/gnunet.git] / src / transport / test_quota_compliance.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2010, 2011, 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_quota_compliance.c
22  * @brief base test case for transport implementations
23  *
24  * This test case tests quota compliance both on transport level
25  */
26 #include "platform.h"
27 #include "gnunet_transport_service.h"
28 #include "gnunet_ats_service.h"
29 #include "gauger.h"
30 #include "transport-testing.h"
31
32 /**
33  * Testcase timeout
34  */
35 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
36
37 /**
38  * How long until we give up on transmitting the message?
39  */
40 #define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
41
42 #define DURATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
43
44
45 static struct GNUNET_SCHEDULER_Task *measure_task;
46
47 struct GNUNET_TRANSPORT_TransmitHandle *th;
48
49 static char *gen_cfgs[2];
50
51 static unsigned long long quota_in[] = { 10000, 10000 };
52
53 static unsigned long long quota_out[] = { 10000, 10000 };
54
55 static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
56
57
58 /**
59  * Note that this value must not significantly exceed
60  * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise
61  * messages may be dropped even for a reliable transport.
62  */
63 #define TOTAL_MSGS (1024 * 2)
64
65 #define MTYPE 12345
66
67 GNUNET_NETWORK_STRUCT_BEGIN
68 struct TestMessage
69 {
70   struct GNUNET_MessageHeader header;
71
72   uint32_t num GNUNET_PACKED;
73 };
74 GNUNET_NETWORK_STRUCT_END
75
76 static int msg_scheduled;
77
78 static int msg_sent;
79
80 static unsigned long long total_bytes_sent;
81
82 static struct GNUNET_TIME_Absolute start_time;
83
84
85 static void
86 report ()
87 {
88   unsigned long long delta;
89   unsigned long long datarate;
90
91   delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value_us;
92   datarate = (total_bytes_sent * 1000 * 1000) / delta;
93
94   FPRINTF (stderr,
95            "Throughput was %llu b/s\n",
96            datarate);
97
98   if (datarate > quota_in[1])
99   {
100     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
101                 "Datarate of %llu b/s higher than allowed inbound quota of %llu b/s\n",
102                 datarate,
103                 quota_in[1]);
104     ccc->global_ret = GNUNET_SYSERR;
105   }
106   if (datarate > quota_out[0])
107   {
108     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
109                 "Datarate of %llu b/s higher than allowed outbound quota of %llu b/s\n",
110                 datarate,
111                 quota_out[0]);
112     ccc->global_ret = GNUNET_SYSERR;
113   }
114   if (GNUNET_OK == ccc->global_ret)
115   {
116     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
117                 "Datarate of %llu b/s complied to allowed outbound quota of %llu b/s and inbound quota of %llu b/s\n",
118                 datarate,
119                 quota_out[0],
120                 quota_in[1]);
121   }
122 }
123
124
125 static void
126 custom_shutdown (void *cls)
127 {
128   if (NULL != measure_task)
129   {
130     GNUNET_SCHEDULER_cancel (measure_task);
131     measure_task = NULL;
132   }
133   if (NULL != th)
134   {
135     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
136     th = NULL;
137   }
138   report ();
139 }
140
141
142 static unsigned int
143 get_size (unsigned int iter)
144 {
145   unsigned int ret;
146
147   ret = (iter * iter * iter);
148   return sizeof (struct TestMessage) + (ret % 60000);
149 }
150
151
152 static void
153 notify_receive (void *cls,
154                 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
155                 const struct GNUNET_PeerIdentity *sender,
156                 const struct GNUNET_MessageHeader *message)
157 {
158   const struct TestMessage *hdr;
159
160   hdr = (const struct TestMessage *) message;
161   if (MTYPE != ntohs (message->type))
162     return;
163
164   {
165     char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
166
167     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
168                 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n",
169                 receiver->no,
170                 ps,
171                 ntohl (hdr->num),
172                 ntohs (message->size),
173                 GNUNET_i2s (sender));
174     GNUNET_free (ps);
175   }
176 }
177
178
179 static size_t
180 notify_ready (void *cls,
181               size_t size,
182               void *buf)
183 {
184   static int n;
185   char *cbuf = buf;
186   struct TestMessage hdr;
187   unsigned int s;
188   unsigned int ret;
189
190   th = NULL;
191   if (NULL == buf)
192   {
193     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
194                 "Timeout occurred while waiting for transmit_ready for message %u of %u\n",
195                 msg_scheduled, TOTAL_MSGS);
196     GNUNET_SCHEDULER_shutdown ();
197     ccc->global_ret = GNUNET_SYSERR;
198     return 0;
199   }
200
201   ret = 0;
202   s = get_size (n);
203   GNUNET_assert (size >= s);
204   GNUNET_assert (buf != NULL);
205   cbuf = buf;
206   do
207   {
208     hdr.header.size = htons (s);
209     hdr.header.type = htons (MTYPE);
210     hdr.num = htonl (n);
211     msg_sent = n;
212     GNUNET_memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage));
213     ret += sizeof (struct TestMessage);
214     memset (&cbuf[ret], n, s - sizeof (struct TestMessage));
215     ret += s - sizeof (struct TestMessage);
216 #if VERBOSE
217     if (n % 5000 == 0)
218     {
219 #endif
220       char *receiver_s = GNUNET_strdup (GNUNET_i2s (&ccc->p[0]->id));
221
222       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
223                   "Sending message %u of size %u from peer %u (`%4s') -> peer %u (`%s') !\n",
224                   n, s,
225                   ccc->p[1]->no,
226                   GNUNET_i2s (&ccc->p[1]->id),
227                   ccc->p[0]->no,
228                   receiver_s);
229       GNUNET_free (receiver_s);
230 #if 0
231     }
232 #endif
233     n++;
234     s = get_size (n);
235     if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16))
236       break;                    /* sometimes pack buffer full, sometimes not */
237   }
238   while (size - ret >= s);
239   if (n < TOTAL_MSGS)
240   {
241     if (th == NULL)
242       th = GNUNET_TRANSPORT_notify_transmit_ready (ccc->p[1]->th,
243                                                    &ccc->p[0]->id,
244                                                    s,
245                                                    TIMEOUT_TRANSMIT,
246                                                    &notify_ready,
247                                                    NULL);
248     msg_scheduled = n;
249   }
250   if (n % 5000 == 0)
251   {
252     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
253                 "Returning total message block of size %u\n",
254                 ret);
255   }
256   total_bytes_sent += ret;
257   if (n == TOTAL_MSGS)
258   {
259     FPRINTF (stderr, "%s",  "\n");
260     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
261                 "All messages sent\n");
262   }
263   return ret;
264 }
265
266
267 static void
268 notify_disconnect (void *cls,
269                    struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
270                    const struct GNUNET_PeerIdentity *other)
271 {
272   GNUNET_TRANSPORT_TESTING_log_disconnect (cls,
273                                            me,
274                                            other);
275   if (th != NULL)
276   {
277     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
278     th = NULL;
279   }
280 }
281
282
283 static void
284 sendtask ()
285 {
286   start_time = GNUNET_TIME_absolute_get ();
287   th = GNUNET_TRANSPORT_notify_transmit_ready (ccc->p[1]->th,
288                                                &ccc->p[0]->id,
289                                                get_size (0),
290                                                TIMEOUT_TRANSMIT,
291                                                &notify_ready,
292                                                NULL);
293 }
294
295
296 static void
297 measure (void *cls)
298 {
299   static int counter;
300
301   measure_task = NULL;
302   counter++;
303   if ((DURATION.rel_value_us / 1000 / 1000LL) < counter)
304   {
305     FPRINTF (stderr, "%s",  ".\n");
306     GNUNET_SCHEDULER_shutdown ();
307     return;
308   }
309   FPRINTF (stderr, "%s",  ".");
310   measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
311                                                &measure,
312                                                NULL);
313 }
314
315
316 static void
317 start_task (void *cls)
318 {
319   measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
320                                                &measure,
321                                                NULL);
322   GNUNET_SCHEDULER_add_now (&sendtask,
323                             NULL);
324 }
325
326
327 static char *
328 generate_config (const char *cfg_file,
329                  unsigned long long quota_in,
330                  unsigned long long quota_out)
331 {
332   char *in_name;
333   char *out_name;
334   char *fname = NULL;
335   struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
336
337   GNUNET_assert (GNUNET_OK ==
338                  GNUNET_CONFIGURATION_load (cfg,
339                                             cfg_file));
340   GNUNET_asprintf (&fname,
341                    "q_in_%llu_q_out_%llu_%s",
342                    quota_in,
343                    quota_out,
344                    cfg_file);
345   GNUNET_CONFIGURATION_set_value_string (cfg,
346                                          "PATHS",
347                                          "DEFAULTCONFIG",
348                                          fname);
349   for (int c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
350   {
351     GNUNET_asprintf (&in_name,
352                      "%s_QUOTA_IN",
353                      GNUNET_ATS_print_network_type (c));
354     GNUNET_asprintf (&out_name,
355                      "%s_QUOTA_OUT",
356                      GNUNET_ATS_print_network_type (c));
357     GNUNET_CONFIGURATION_set_value_number (cfg,
358                                            "ats",
359                                            in_name,
360                                            quota_in);
361     GNUNET_CONFIGURATION_set_value_number (cfg,
362                                            "ats",
363                                            out_name,
364                                            quota_out);
365     GNUNET_free (in_name);
366     GNUNET_free (out_name);
367   }
368   GNUNET_assert (GNUNET_OK ==
369                  GNUNET_CONFIGURATION_write (cfg,
370                                              fname));
371   GNUNET_CONFIGURATION_destroy (cfg);
372   return fname;
373 }
374
375
376 static int
377 check (void *cls,
378        struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
379        const char *test_plugin_,
380        const char *test_name_,
381        unsigned int num_peers,
382        char *cfg_files[])
383 {
384   struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
385     .connect_continuation = &start_task,
386     .config_file = "test_quota_compliance_data.conf",
387     .rec = &notify_receive,
388     .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
389     .nd = &notify_disconnect,
390     .shutdown_task = &custom_shutdown,
391     .timeout = TIMEOUT
392   };
393   ccc = &my_ccc;
394
395   if (NULL != strstr (test_name_,
396                       "asymmetric"))
397   {
398     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
399                 "Running asymmetric test with sending peer unlimited, receiving peer (in/out): %llu/%llu b/s \n",
400                 quota_in[1],
401                 quota_out[1]);
402     quota_out[0] = 1024 * 1024 * 1024;
403     quota_in[0] = 1024 * 1024 * 1024;
404   }
405   else
406   {
407     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
408                 "Running symmetric test with (in/out) %llu/%llu b/s \n",
409                 quota_in[1],
410                 quota_out[1]);
411   }
412   for (unsigned int i=0;i<2;i++)
413   {
414     gen_cfgs[i] = generate_config (cfg_files[i],
415                                    quota_in[i],
416                                    quota_out[i]);
417     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
418                 "Generated config file `%s'\n",
419                 gen_cfgs[i]);
420   }
421
422   return GNUNET_TRANSPORT_TESTING_connect_check (&my_ccc,
423                                                  tth_,
424                                                  test_plugin_,
425                                                  test_name_,
426                                                  num_peers,
427                                                  gen_cfgs);
428 }
429
430
431 int
432 main (int argc, char *argv[])
433 {
434   if (GNUNET_OK !=
435       GNUNET_TRANSPORT_TESTING_main (2,
436                                      &check,
437                                      NULL))
438   {
439     GNUNET_break (0);
440     return 1;
441   }
442   for (unsigned int i=0;i<2;i++)
443   {
444     if ( (NULL != gen_cfgs[0]) &&
445          (GNUNET_YES == GNUNET_DISK_file_test (gen_cfgs[0])) )
446     {
447       GNUNET_DISK_directory_remove (gen_cfgs[0]);
448       GNUNET_free (gen_cfgs[0]);
449     }
450   }
451   return 0;
452 }
453
454
455 /* end of test_quota_compliance.c */