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