replace printf() with GNUNET_log()
[oweals/gnunet.git] / src / transport / test_communicator_basic.c
1 /*
2     This file is part of GNUnet.
3     Copyright (C) 2019 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 /**
22 * @file transport/test_communicator_basic.c
23 * @brief test the communicators
24 * @author Julius Bünger
25 * @author Martin Schanzenbach
26 */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "transport-testing2.h"
30 #include "gnunet_ats_transport_service.h"
31 #include "gnunet_signatures.h"
32 #include "gnunet_testing_lib.h"
33 #include "transport.h"
34
35 #include <inttypes.h>
36
37
38 #define LOG(kind, ...) GNUNET_log_from (kind, \
39                                         "test_transport_communicator", \
40                                         __VA_ARGS__)
41
42 #define NUM_PEERS 2
43
44 static struct GNUNET_SCHEDULER_Task *to_task;
45
46 static struct GNUNET_SCHEDULER_Task *active_task;
47
48 static int queue_est = GNUNET_NO;
49
50 static struct GNUNET_PeerIdentity peer_id[NUM_PEERS];
51
52 static char *communicator_binary;
53
54 static struct
55 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_hs[NUM_PEERS];
56
57 static struct GNUNET_CONFIGURATION_Handle *cfg_peers[NUM_PEERS];
58
59 static char *cfg_peers_name[NUM_PEERS];
60
61 static int ret;
62
63 static struct GNUNET_TIME_Absolute start_short;
64
65 static struct GNUNET_TIME_Absolute start_long;
66
67 static struct GNUNET_TIME_Absolute timeout;
68
69 static struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *my_tc;
70
71 #define SHORT_MESSAGE_SIZE 128
72
73 #define LONG_MESSAGE_SIZE 32000
74
75 #define BURST_PACKETS 5000
76
77 #define FIXME_DEAD_BURST_RUNS 1
78
79 #define TOTAL_ITERATIONS 20
80
81 static unsigned int iterations_left = TOTAL_ITERATIONS;
82
83 #define SHORT_BURST_WINDOW \
84   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,2)
85
86 #define LONG_BURST_WINDOW \
87   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,2)
88
89 enum TestPhase
90 {
91   TP_BURST_SHORT,
92   TP_BURST_LONG,
93   TP_SIZE_CHECK
94 };
95
96
97 static size_t num_sent = 0;
98
99 static uint32_t ack = 0;
100
101 static enum TestPhase phase;
102
103 static size_t num_received = 0;
104
105 static uint64_t avg_latency = 0;
106
107 static struct GNUNET_TIME_Relative duration;
108
109
110 static void
111 communicator_available_cb (void *cls,
112                            struct
113                            GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
114                            *tc_h,
115                            enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc,
116                            char *address_prefix)
117 {
118   LOG (GNUNET_ERROR_TYPE_INFO,
119        "Communicator available. (cc: %u, prefix: %s)\n",
120        cc,
121        address_prefix);
122 }
123
124
125 static void
126 add_address_cb (void *cls,
127                 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
128                 tc_h,
129                 const char *address,
130                 struct GNUNET_TIME_Relative expiration,
131                 uint32_t aid,
132                 enum GNUNET_NetworkType nt)
133 {
134   LOG (GNUNET_ERROR_TYPE_DEBUG,
135        "New address. (addr: %s, expir: %" PRIu32 ", ID: %" PRIu32 ", nt: %u\n",
136        address,
137        expiration.rel_value_us,
138        aid,
139        nt);
140   // addresses[1] = GNUNET_strdup (address);
141   if ((0 == strcmp ((char*) cls, cfg_peers_name[NUM_PEERS - 1])) &&
142       (GNUNET_NO == queue_est))
143   {
144     queue_est = GNUNET_YES;
145     GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue (tc_hs[0],
146                                                                 &peer_id[
147                                                                   NUM_PEERS
148                                                                   - 1],
149                                                                 address);
150   }
151 }
152
153
154 /**
155  * @brief Callback that informs whether the requested queue will be
156  * established
157  *
158  * Implements #GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback.
159  *
160  * @param cls Closure - unused
161  * @param tc_h Communicator handle - unused
162  * @param will_try #GNUNET_YES if queue will be established
163  *                #GNUNET_NO if queue will not be established (bogous address)
164  */
165 static void
166 queue_create_reply_cb (void *cls,
167                        struct
168                        GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
169                        tc_h,
170                        int will_try)
171 {
172   if (GNUNET_YES == will_try)
173     LOG (GNUNET_ERROR_TYPE_DEBUG,
174          "Queue will be established!\n");
175   else
176     LOG (GNUNET_ERROR_TYPE_WARNING,
177          "Queue won't be established (bougus address?)!\n");
178 }
179
180
181 static char*
182 make_payload (size_t payload_size)
183 {
184   struct GNUNET_TIME_Absolute ts;
185   struct GNUNET_TIME_AbsoluteNBO ts_n;
186   char *payload = GNUNET_malloc (payload_size);
187
188   GNUNET_assert (payload_size >= 8); // So that out timestamp fits
189   ts = GNUNET_TIME_absolute_get ();
190   ts_n = GNUNET_TIME_absolute_hton (ts);
191   memset (payload, 0, payload_size);
192   memcpy (payload, &ts_n, sizeof (struct GNUNET_TIME_AbsoluteNBO));
193   return payload;
194 }
195
196
197 static void
198 latency_timeout (void *cls)
199 {
200   to_task = NULL;
201   if (GNUNET_TIME_absolute_get_remaining (timeout).rel_value_us > 0)
202   {
203     to_task = GNUNET_SCHEDULER_add_at (timeout,
204                                        &latency_timeout,
205                                        NULL);
206     return;
207   }
208
209   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
210               "Latency too high. Test failed. (Phase: %d. Sent: %lu, Received: %lu)\n",
211               phase, num_sent, num_received);
212   ret = 2;
213   GNUNET_SCHEDULER_shutdown ();
214 }
215
216
217 static void
218 size_test (void *cls)
219 {
220   char *payload;
221
222   active_task = NULL;
223   GNUNET_assert (TP_SIZE_CHECK == phase);
224   if (ack >= 64000)
225     return; /* Leave some room for our protocol, so not 2^16 exactly */
226   payload = make_payload (ack);
227   GNUNET_TRANSPORT_TESTING_transport_communicator_send (my_tc,
228                                                         payload,
229                                                         ack);
230   GNUNET_free (payload);
231   ack += 5;
232   num_sent++;
233   timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_SECONDS);
234   if (ack < 64000)
235     active_task = GNUNET_SCHEDULER_add_now (&size_test,
236                                             NULL);
237 }
238
239
240 static void
241 long_test (void *cls)
242 {
243   char *payload;
244
245   active_task = NULL;
246   payload = make_payload (LONG_MESSAGE_SIZE);
247   GNUNET_TRANSPORT_TESTING_transport_communicator_send (my_tc,
248                                                         payload,
249                                                         LONG_MESSAGE_SIZE);
250   num_sent++;
251   GNUNET_free (payload);
252   timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_SECONDS);
253   if (num_sent == BURST_PACKETS)
254     return;
255   active_task = GNUNET_SCHEDULER_add_now (&long_test,
256                                           NULL);
257 }
258
259
260 static void
261 short_test (void *cls)
262 {
263   char *payload;
264
265   active_task = NULL;
266   payload = make_payload (SHORT_MESSAGE_SIZE);
267   GNUNET_TRANSPORT_TESTING_transport_communicator_send (my_tc,
268                                                         payload,
269                                                         SHORT_MESSAGE_SIZE);
270   num_sent++;
271   GNUNET_free (payload);
272   timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_SECONDS);
273   if (num_sent >= BURST_PACKETS)
274     return;
275   active_task = GNUNET_SCHEDULER_add_now (&short_test,
276                                           NULL);
277 }
278
279
280 /**
281  * @brief Handle opening of queue
282  *
283  * Issues sending of test data
284  *
285  * Implements #GNUNET_TRANSPORT_TESTING_AddQueueCallback
286  *
287  * @param cls Closure
288  * @param tc_h Communicator handle
289  * @param tc_queue Handle to newly opened queue
290  */
291 static void
292 add_queue_cb (void *cls,
293               struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
294               struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *
295               tc_queue)
296 {
297   if (0 != strcmp ((char*) cls, cfg_peers_name[0]))
298     return; // TODO?
299   LOG (GNUNET_ERROR_TYPE_DEBUG,
300        "Queue established, starting test...\n");
301   start_short = GNUNET_TIME_absolute_get ();
302   my_tc = tc_queue;
303   phase = TP_BURST_SHORT;
304   timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_SECONDS);
305   GNUNET_assert (NULL == to_task);
306   to_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
307                                           &latency_timeout,
308                                           NULL);
309   GNUNET_assert (NULL == active_task);
310   active_task = GNUNET_SCHEDULER_add_now (&short_test,
311                                           NULL);
312 }
313
314
315 static void
316 update_avg_latency (const char*payload)
317 {
318   struct GNUNET_TIME_AbsoluteNBO *ts_n;
319   struct GNUNET_TIME_Absolute ts;
320   struct GNUNET_TIME_Relative latency;
321
322   ts_n = (struct GNUNET_TIME_AbsoluteNBO *) payload;
323   ts = GNUNET_TIME_absolute_ntoh (*ts_n);
324   latency = GNUNET_TIME_absolute_get_duration (ts);
325   if (1 == num_received)
326     avg_latency = latency.rel_value_us;
327   else
328     avg_latency = ((avg_latency * (num_received - 1)) + latency.rel_value_us)
329                   / num_received;
330
331 }
332
333
334 /**
335  * @brief Handle an incoming message
336  *
337  * Implements #GNUNET_TRANSPORT_TESTING_IncomingMessageCallback
338
339  * @param cls Closure
340  * @param tc_h Handle to the receiving communicator
341  * @param msg Received message
342  */
343 static void
344 incoming_message_cb (void *cls,
345                      struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
346                      *tc_h,
347                      const char*payload,
348                      size_t payload_len)
349 {
350   if (0 != strcmp ((char*) cls, cfg_peers_name[NUM_PEERS - 1]))
351   {
352     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
353                 "unexpected receiver...\n");
354     return;
355   }
356   /* Reset timeout */
357   timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_SECONDS);
358   switch (phase)
359   {
360   case TP_BURST_SHORT:
361     {
362       GNUNET_assert (SHORT_MESSAGE_SIZE == payload_len);
363       num_received++;
364       duration = GNUNET_TIME_absolute_get_duration (start_short);
365       update_avg_latency (payload);
366       if (num_received == BURST_PACKETS)
367       {
368         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
369                     "Short size packet test done.\n");
370         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
371                     "%lu/%lu packets in %llu us (%llu kb/s) -- avg latency: %llu us\n",
372                     (unsigned long) num_received,
373                     (unsigned long) num_sent,
374                     (unsigned long long) duration.rel_value_us,
375                     (unsigned long long) ((SHORT_MESSAGE_SIZE * num_received)
376                                           / (duration.rel_value_us
377                                              /
378                                              1000)),
379                     (unsigned long long) avg_latency);
380         start_long = GNUNET_TIME_absolute_get ();
381         phase = TP_BURST_LONG;
382         num_sent = 0;
383         avg_latency = 0;
384         num_received = 0;
385         active_task = GNUNET_SCHEDULER_add_now (&long_test,
386                                                 NULL);
387       }
388       break;
389     }
390   case TP_BURST_LONG:
391     {
392       if (LONG_MESSAGE_SIZE != payload_len)
393       {
394         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
395                     "Ignoring packet with wrong length\n");
396         return; // Ignore
397       }
398       num_received++;
399       duration = GNUNET_TIME_absolute_get_duration (start_long);
400       update_avg_latency (payload);
401       if (num_received == BURST_PACKETS)
402       {
403         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
404                     "Long size packet test done.\n");
405         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
406                     "%lu/%lu packets in %llu us (%llu kb/s) -- avg latency: %llu us\n",
407                     (unsigned long) num_received,
408                     (unsigned long) num_sent,
409                     (unsigned long long) duration.rel_value_us,
410                     (unsigned long long) ((LONG_MESSAGE_SIZE * num_received)
411                                           / (duration.rel_value_us
412                                              /
413                                              1000)),
414                     (unsigned long long) avg_latency);
415         ack = 10;
416         phase = TP_SIZE_CHECK;
417         num_received = 0;
418         num_sent = 0;
419         avg_latency = 0;
420         active_task = GNUNET_SCHEDULER_add_now (&size_test,
421                                                 NULL);
422       }
423       break;
424     }
425   case TP_SIZE_CHECK:
426     {
427       num_received++;
428       update_avg_latency (payload);
429       if (num_received >= (64000 - 10) / 5)
430       {
431         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
432                     "Size packet test done.\n");
433         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
434                     "%lu/%lu packets -- avg latency: %llu us\n",
435                     (unsigned long) num_received,
436                     (unsigned long) num_sent,
437                     (unsigned long long) avg_latency);
438         num_received = 0;
439         num_sent = 0;
440         avg_latency = 0;
441         iterations_left--;
442         if (0 != iterations_left)
443         {
444           phase = TP_BURST_SHORT;
445           active_task = GNUNET_SCHEDULER_add_now (&short_test,
446                                                   NULL);
447           break;
448         }
449         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
450                     "Finished\n");
451         GNUNET_SCHEDULER_shutdown ();
452       }
453       break;
454     }
455   }
456 }
457
458
459 static void
460 do_shutdown (void *cls)
461 {
462   if (NULL != to_task)
463   {
464     GNUNET_SCHEDULER_cancel (to_task);
465     to_task = NULL;
466   }
467   if (NULL != active_task)
468   {
469     GNUNET_SCHEDULER_cancel (active_task);
470     active_task = NULL;
471   }
472 }
473
474
475 /**
476  * @brief Main function called by the scheduler
477  *
478  * @param cls Closure - Handle to configuration
479  */
480 static void
481 run (void *cls)
482 {
483   ret = 0;
484   num_received = 0;
485   num_sent = 0;
486   for (unsigned int i = 0; i < NUM_PEERS; i++)
487   {
488     tc_hs[i] = GNUNET_TRANSPORT_TESTING_transport_communicator_service_start (
489       "transport",
490       communicator_binary,
491       cfg_peers_name[i],
492       &communicator_available_cb,
493       &add_address_cb,
494       &queue_create_reply_cb,
495       &add_queue_cb,
496       &incoming_message_cb,
497       cfg_peers_name[i]);   /* cls */
498   }
499   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
500                                  NULL);
501 }
502
503
504 int
505 main (int argc,
506       char *const *argv)
507 {
508   struct GNUNET_CRYPTO_EddsaPrivateKey *private_key;
509   char *communicator_name;
510   char *cfg_peer;
511
512   ret = 1;
513   communicator_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
514   GNUNET_asprintf (&communicator_binary,
515                    "gnunet-communicator-%s",
516                    communicator_name);
517   if (GNUNET_OK !=
518       GNUNET_log_setup ("test_communicator_basic",
519                         "DEBUG",
520                         NULL))
521   {
522     fprintf (stderr, "Unable to setup log\n");
523     GNUNET_break (0);
524     return 2;
525   }
526   for (unsigned int i = 0; i < NUM_PEERS; i++)
527   {
528     GNUNET_asprintf ((&cfg_peer),
529                      "test_communicator_%s_peer%u.conf",
530                      communicator_name, i + 1);
531     cfg_peers_name[i] = cfg_peer;
532     cfg_peers[i] = GNUNET_CONFIGURATION_create ();
533     if (GNUNET_YES ==
534         GNUNET_DISK_file_test (cfg_peers_name[i]))
535     {
536       if (GNUNET_SYSERR ==
537           GNUNET_CONFIGURATION_load (cfg_peers[i],
538                                      cfg_peers_name[i]))
539       {
540         fprintf (stderr,
541                  "Malformed configuration file `%s', exiting ...\n",
542                  cfg_peers_name[i]);
543         return 1;
544       }
545     }
546     else
547     {
548       if (GNUNET_SYSERR ==
549           GNUNET_CONFIGURATION_load (cfg_peers[i],
550                                      NULL))
551       {
552         fprintf (stderr,
553                  "Configuration file %s does not exist, exiting ...\n",
554                  cfg_peers_name[i]);
555         return 1;
556       }
557     }
558     private_key =
559       GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg_peers[i]);
560     if (NULL == private_key)
561     {
562       LOG (GNUNET_ERROR_TYPE_ERROR,
563            "Unable to get peer ID\n");
564       return 1;
565     }
566     GNUNET_CRYPTO_eddsa_key_get_public (private_key,
567                                         &peer_id[i].public_key);
568     GNUNET_free (private_key);
569     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
570                 "Identity of peer %u is %s\n",
571                 i,
572                 GNUNET_i2s_full (&peer_id[i]));
573   }
574   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Starting test...\n");
575   GNUNET_SCHEDULER_run (&run,
576                         NULL);
577   return ret;
578 }