6309c3278f7ffcd834021daef25a6ac3a489dda7
[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 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 /**
19  * @file transport/test_quota_compliance.c
20  * @brief base test case for transport implementations
21  *
22  * This test case tests quota compliance both on transport level
23  */
24 #include "platform.h"
25 #include "gnunet_transport_service.h"
26 #include "gnunet_ats_service.h"
27 #include "gauger.h"
28 #include "transport-testing.h"
29
30 /**
31  * Testcase timeout
32  */
33 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 480)
34
35 #define DURATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 80)
36
37
38 static struct GNUNET_SCHEDULER_Task *measure_task;
39
40 static char *gen_cfgs[2];
41
42 static unsigned long long quota_in[] = { 10000, 10000 };
43
44 static unsigned long long quota_out[] = { 10000, 10000 };
45
46 static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
47
48
49 /**
50  * Note that this value must not significantly exceed
51  * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise
52  * messages may be dropped even for a reliable transport.
53  */
54 #define TOTAL_MSGS (1024 * 32)
55
56 static unsigned long long total_bytes_recv;
57
58 static struct GNUNET_TIME_Absolute start_time;
59
60
61 static void
62 report ()
63 {
64   unsigned long long delta;
65   unsigned long long datarate;
66
67   delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value_us;
68   if (0 == delta)
69     delta = 1;
70   datarate = (total_bytes_recv * 1000 * 1000) / delta;
71
72   FPRINTF (stderr,
73            "Throughput was %llu b/s\n",
74            datarate);
75   ccc->global_ret = GNUNET_OK;
76   if (datarate > 1.5 * quota_in[1])
77   {
78     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
79                 "Datarate of %llu b/s significantly higher than allowed inbound quota of %llu b/s\n",
80                 datarate,
81                 quota_in[1]);
82     ccc->global_ret = GNUNET_SYSERR;
83   }
84   if (datarate > 1.5 * quota_out[0])
85   {
86     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
87                 "Datarate of %llu b/s significantly higher than allowed outbound quota of %llu b/s\n",
88                 datarate,
89                 quota_out[0]);
90     ccc->global_ret = GNUNET_SYSERR;
91   }
92   if (GNUNET_OK == ccc->global_ret)
93   {
94     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
95                 "Datarate of %llu b/s complied to allowed outbound quota of %llu b/s and inbound quota of %llu b/s\n",
96                 datarate,
97                 quota_out[0],
98                 quota_in[1]);
99   }
100 }
101
102
103 static void
104 custom_shutdown (void *cls)
105 {
106   if (NULL != measure_task)
107   {
108     GNUNET_SCHEDULER_cancel (measure_task);
109     measure_task = NULL;
110   }
111   report ();
112 }
113
114
115 static size_t
116 get_size (unsigned int iter)
117 {
118   size_t ret;
119
120   ret = (iter * iter * iter) % 60000;
121   ret += sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage);
122   return ret;
123 }
124
125
126 static void
127 notify_receive (void *cls,
128                 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
129                 const struct GNUNET_PeerIdentity *sender,
130                 const struct GNUNET_TRANSPORT_TESTING_TestMessage *hdr)
131 {
132
133   if (GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (hdr->header.type))
134     return;
135   total_bytes_recv += ntohs (hdr->header.size);
136
137   {
138     char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
139
140     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
141                 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n",
142                 receiver->no,
143                 ps,
144                 ntohl (hdr->num),
145                 ntohs (hdr->header.size),
146                 GNUNET_i2s (sender));
147     GNUNET_free (ps);
148   }
149 }
150
151
152 static void
153 measure (void *cls)
154 {
155   static int counter;
156
157   measure_task = NULL;
158   counter++;
159   if ((DURATION.rel_value_us / 1000 / 1000LL) < counter)
160   {
161     FPRINTF (stderr, "%s",  ".\n");
162     GNUNET_SCHEDULER_shutdown ();
163     return;
164   }
165   FPRINTF (stderr, "%s",  ".");
166   measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
167                                                &measure,
168                                                NULL);
169 }
170
171
172 static void
173 start_task (void *cls)
174 {
175   static struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
176     .num_messages = TOTAL_MSGS,
177     .get_size_cb = &get_size
178   };
179
180   sc.ccc = ccc;
181   measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
182                                                &measure,
183                                                NULL);
184   start_time = GNUNET_TIME_absolute_get ();
185   GNUNET_SCHEDULER_add_now (&GNUNET_TRANSPORT_TESTING_simple_send,
186                             &sc);
187 }
188
189
190 static char *
191 generate_config (const char *cfg_file,
192                  unsigned long long quota_in,
193                  unsigned long long quota_out)
194 {
195   char *in_name;
196   char *out_name;
197   char *fname = NULL;
198   struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
199
200   GNUNET_assert (GNUNET_OK ==
201                  GNUNET_CONFIGURATION_load (cfg,
202                                             cfg_file));
203   GNUNET_asprintf (&fname,
204                    "q_in_%llu_q_out_%llu_%s",
205                    quota_in,
206                    quota_out,
207                    cfg_file);
208   GNUNET_CONFIGURATION_set_value_string (cfg,
209                                          "PATHS",
210                                          "DEFAULTCONFIG",
211                                          fname);
212   for (int c = 0; c < GNUNET_NT_COUNT; c++)
213   {
214     GNUNET_asprintf (&in_name,
215                      "%s_QUOTA_IN",
216                      GNUNET_NT_to_string (c));
217     GNUNET_asprintf (&out_name,
218                      "%s_QUOTA_OUT",
219                      GNUNET_NT_to_string (c));
220     GNUNET_CONFIGURATION_set_value_number (cfg,
221                                            "ats",
222                                            in_name,
223                                            quota_in);
224     GNUNET_CONFIGURATION_set_value_number (cfg,
225                                            "ats",
226                                            out_name,
227                                            quota_out);
228     GNUNET_free (in_name);
229     GNUNET_free (out_name);
230   }
231   GNUNET_assert (GNUNET_OK ==
232                  GNUNET_CONFIGURATION_write (cfg,
233                                              fname));
234   GNUNET_CONFIGURATION_destroy (cfg);
235   return fname;
236 }
237
238
239 static int
240 check (void *cls,
241        struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
242        const char *test_plugin_,
243        const char *test_name_,
244        unsigned int num_peers,
245        char *cfg_files[])
246 {
247   struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
248     .connect_continuation = &start_task,
249     .config_file = "test_quota_compliance_data.conf",
250     .rec = &notify_receive,
251     .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
252     .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
253     .shutdown_task = &custom_shutdown,
254     .timeout = TIMEOUT
255   };
256   ccc = &my_ccc;
257
258   if (NULL != strstr (test_name_,
259                       "asymmetric"))
260   {
261     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
262                 "Running asymmetric test with sending peer unlimited, receiving peer (in/out): %llu/%llu b/s \n",
263                 quota_in[1],
264                 quota_out[1]);
265     quota_out[0] = 1024 * 1024 * 1024;
266     quota_in[0] = 1024 * 1024 * 1024;
267   }
268   else
269   {
270     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
271                 "Running symmetric test with (in/out) %llu/%llu b/s \n",
272                 quota_in[1],
273                 quota_out[1]);
274   }
275   for (unsigned int i=0;i<2;i++)
276   {
277     gen_cfgs[i] = generate_config (cfg_files[i],
278                                    quota_in[i],
279                                    quota_out[i]);
280     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
281                 "Generated config file `%s'\n",
282                 gen_cfgs[i]);
283   }
284
285   return GNUNET_TRANSPORT_TESTING_connect_check (&my_ccc,
286                                                  tth_,
287                                                  test_plugin_,
288                                                  test_name_,
289                                                  num_peers,
290                                                  gen_cfgs);
291 }
292
293
294 int
295 main (int argc,
296       char *argv[])
297 {
298   if (GNUNET_OK !=
299       GNUNET_TRANSPORT_TESTING_main (2,
300                                      &check,
301                                      NULL))
302   {
303     GNUNET_break (0);
304     return 1;
305   }
306   for (unsigned int i=0;i<2;i++)
307   {
308     if ( (NULL != gen_cfgs[i]) &&
309          (GNUNET_YES == GNUNET_DISK_file_test (gen_cfgs[i])) )
310     {
311       GNUNET_DISK_directory_remove (gen_cfgs[i]);
312       GNUNET_free (gen_cfgs[i]);
313     }
314   }
315   return 0;
316 }
317
318
319 /* end of test_quota_compliance.c */