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