more fixed tcp comm
[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_TRANSPORT_TESTING_TransportCommunicatorQueue *my_tc;
68
69 #define SHORT_MESSAGE_SIZE 128
70
71 #define LONG_MESSAGE_SIZE 32000
72
73 #define BURST_PACKETS 5000
74
75 #define FIXME_DEAD_BURST_RUNS 1
76
77 #define TOTAL_ITERATIONS 10
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   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
200               "Latency too high. Test failed. (Phase: %d. Sent: %lu, Received: %lu)\n",
201               phase, num_sent, num_received);
202   ret = 2;
203   GNUNET_SCHEDULER_shutdown ();
204 }
205
206
207 static void
208 size_test (void *cls)
209 {
210   char *payload;
211
212   active_task = NULL;
213   GNUNET_assert (TP_SIZE_CHECK == phase);
214   if (ack >= 64000)
215     return; /* Leave some room for our protocol, so not 2^16 exactly */
216   payload = make_payload (ack);
217   GNUNET_TRANSPORT_TESTING_transport_communicator_send (my_tc,
218                                                         payload,
219                                                         ack);
220   GNUNET_free (payload);
221   ack += 5;
222   num_sent++;
223   if (NULL == to_task)
224     to_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
225                                             &latency_timeout,
226                                             NULL);
227   if (ack < 64000)
228     active_task = GNUNET_SCHEDULER_add_now (&size_test,
229                                             NULL);
230 }
231
232
233 static void
234 long_test (void *cls)
235 {
236   char *payload;
237
238   active_task = NULL;
239   payload = make_payload (LONG_MESSAGE_SIZE);
240   GNUNET_TRANSPORT_TESTING_transport_communicator_send (my_tc,
241                                                         payload,
242                                                         LONG_MESSAGE_SIZE);
243   num_sent++;
244   GNUNET_free (payload);
245   if (NULL == to_task)
246     to_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
247                                             &latency_timeout,
248                                             NULL);
249   if (num_sent == BURST_PACKETS)
250     return;
251   active_task = GNUNET_SCHEDULER_add_now (&long_test,
252                                           NULL);
253 }
254
255
256 static void
257 short_test (void *cls)
258 {
259   char *payload;
260
261   active_task = NULL;
262   payload = make_payload (SHORT_MESSAGE_SIZE);
263   GNUNET_TRANSPORT_TESTING_transport_communicator_send (my_tc,
264                                                         payload,
265                                                         SHORT_MESSAGE_SIZE);
266   num_sent++;
267   GNUNET_free (payload);
268   if (NULL == to_task)
269     to_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
270                                             &latency_timeout,
271                                             NULL);
272   if (num_sent >= BURST_PACKETS)
273     return;
274   active_task = GNUNET_SCHEDULER_add_now (&short_test,
275                                           NULL);
276 }
277
278
279 /**
280  * @brief Handle opening of queue
281  *
282  * Issues sending of test data
283  *
284  * Implements #GNUNET_TRANSPORT_TESTING_AddQueueCallback
285  *
286  * @param cls Closure
287  * @param tc_h Communicator handle
288  * @param tc_queue Handle to newly opened queue
289  */
290 static void
291 add_queue_cb (void *cls,
292               struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
293               struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *
294               tc_queue)
295 {
296   if (0 != strcmp ((char*) cls, cfg_peers_name[0]))
297     return; // TODO?
298   LOG (GNUNET_ERROR_TYPE_DEBUG,
299        "Queue established, starting test...\n");
300   start_short = GNUNET_TIME_absolute_get ();
301   my_tc = tc_queue;
302   phase = TP_BURST_SHORT;
303   GNUNET_assert (NULL == active_task);
304   active_task = GNUNET_SCHEDULER_add_now (&short_test,
305                                           NULL);
306 }
307
308
309 static void
310 update_avg_latency (const char*payload)
311 {
312   struct GNUNET_TIME_AbsoluteNBO *ts_n;
313   struct GNUNET_TIME_Absolute ts;
314   struct GNUNET_TIME_Relative latency;
315
316   ts_n = (struct GNUNET_TIME_AbsoluteNBO *) payload;
317   ts = GNUNET_TIME_absolute_ntoh (*ts_n);
318   latency = GNUNET_TIME_absolute_get_duration (ts);
319   if (1 == num_received)
320     avg_latency = latency.rel_value_us;
321   else
322     avg_latency = ((avg_latency * (num_received - 1)) + latency.rel_value_us)
323                   / num_received;
324
325 }
326
327
328 /**
329  * @brief Handle an incoming message
330  *
331  * Implements #GNUNET_TRANSPORT_TESTING_IncomingMessageCallback
332
333  * @param cls Closure
334  * @param tc_h Handle to the receiving communicator
335  * @param msg Received message
336  */
337 static void
338 incoming_message_cb (void *cls,
339                      struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
340                      *tc_h,
341                      const char*payload,
342                      size_t payload_len)
343 {
344   if (0 != strcmp ((char*) cls, cfg_peers_name[NUM_PEERS - 1]))
345   {
346     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
347                 "unexpected receiver...\n");
348     return;
349   }
350   switch (phase)
351   {
352   case TP_BURST_SHORT:
353     {
354       GNUNET_assert (SHORT_MESSAGE_SIZE == payload_len);
355       num_received++;
356       duration = GNUNET_TIME_absolute_get_duration (start_short);
357       update_avg_latency (payload);
358       if (num_received == BURST_PACKETS)
359       {
360         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
361                     "Short size packet test done.\n");
362         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
363                     "%lu/%lu packets in %llu us (%llu kb/s) -- avg latency: %llu us\n",
364                     (unsigned long) num_received,
365                     (unsigned long) num_sent,
366                     (unsigned long long) duration.rel_value_us,
367                     (unsigned long long) ((SHORT_MESSAGE_SIZE * num_received)
368                                           / (duration.rel_value_us
369                                              /
370                                              1000)),
371                     (unsigned long long) avg_latency);
372         start_long = GNUNET_TIME_absolute_get ();
373         phase = TP_BURST_LONG;
374         num_sent = 0;
375         avg_latency = 0;
376         num_received = 0;
377         if (NULL != to_task)
378         {
379           GNUNET_SCHEDULER_cancel (to_task);
380           to_task = NULL;
381         }
382         active_task = GNUNET_SCHEDULER_add_now (&long_test,
383                                                 NULL);
384       }
385       break;
386     }
387   case TP_BURST_LONG:
388     {
389       if (LONG_MESSAGE_SIZE != payload_len)
390       {
391         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
392                     "Ignoring packet with wrong length\n");
393         return; // Ignore
394       }
395       num_received++;
396       duration = GNUNET_TIME_absolute_get_duration (start_long);
397       update_avg_latency (payload);
398       if (num_received == BURST_PACKETS)
399       {
400         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
401                     "Long size packet test done.\n");
402         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
403                     "%lu/%lu packets in %llu us (%llu kb/s) -- avg latency: %llu us\n",
404                     (unsigned long) num_received,
405                     (unsigned long) num_sent,
406                     (unsigned long long) duration.rel_value_us,
407                     (unsigned long long) ((LONG_MESSAGE_SIZE * num_received)
408                                           / (duration.rel_value_us
409                                              /
410                                              1000)),
411                     (unsigned long long) avg_latency);
412         ack = 10;
413         phase = TP_SIZE_CHECK;
414         num_received = 0;
415         num_sent = 0;
416         avg_latency = 0;
417         if (NULL != to_task)
418         {
419           GNUNET_SCHEDULER_cancel (to_task);
420           to_task = NULL;
421         }
422         active_task = GNUNET_SCHEDULER_add_now (&size_test,
423                                                 NULL);
424       }
425       break;
426     }
427   case TP_SIZE_CHECK:
428     {
429       num_received++;
430       update_avg_latency (payload);
431       if (num_received >= (64000 - 10) / 5)
432       {
433         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
434                     "Size packet test done.\n");
435         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
436                     "%lu/%lu packets -- avg latency: %llu us\n",
437                     (unsigned long) num_received,
438                     (unsigned long) num_sent,
439                     (unsigned long long) avg_latency);
440         num_received = 0;
441         num_sent = 0;
442         avg_latency = 0;
443         if (NULL != to_task)
444         {
445           GNUNET_SCHEDULER_cancel (to_task);
446           to_task = NULL;
447         }
448         iterations_left--;
449         if (0 != iterations_left)
450         {
451           phase = TP_BURST_SHORT;
452           active_task = GNUNET_SCHEDULER_add_now (&short_test,
453                                                   NULL);
454           break;
455         }
456         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
457                     "Finished\n");
458         GNUNET_SCHEDULER_shutdown ();
459       }
460       break;
461     }
462   }
463   /* Reset timeout */
464   if (NULL != to_task)
465   {
466     GNUNET_SCHEDULER_cancel (to_task);
467     to_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
468                                             &latency_timeout,
469                                             NULL);
470   }
471 }
472
473
474 static void
475 do_shutdown (void *cls)
476 {
477   if (NULL != to_task)
478   {
479     GNUNET_SCHEDULER_cancel (to_task);
480     to_task = NULL;
481   }
482   if (NULL != active_task)
483   {
484     GNUNET_SCHEDULER_cancel (active_task);
485     active_task = NULL;
486   }
487 }
488
489
490 /**
491  * @brief Main function called by the scheduler
492  *
493  * @param cls Closure - Handle to configuration
494  */
495 static void
496 run (void *cls)
497 {
498   ret = 0;
499   num_received = 0;
500   num_sent = 0;
501   for (unsigned int i = 0; i < NUM_PEERS; i++)
502   {
503     tc_hs[i] = GNUNET_TRANSPORT_TESTING_transport_communicator_service_start (
504       "transport",
505       communicator_binary,
506       cfg_peers_name[i],
507       &communicator_available_cb,
508       &add_address_cb,
509       &queue_create_reply_cb,
510       &add_queue_cb,
511       &incoming_message_cb,
512       cfg_peers_name[i]);   /* cls */
513   }
514   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
515                                  NULL);
516 }
517
518
519 int
520 main (int argc,
521       char *const *argv)
522 {
523   struct GNUNET_CRYPTO_EddsaPrivateKey *private_key;
524   char *communicator_name;
525   char *cfg_peer;
526
527   ret = 1;
528   communicator_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
529   GNUNET_asprintf (&communicator_binary,
530                    "gnunet-communicator-%s",
531                    communicator_name);
532   if (GNUNET_OK !=
533       GNUNET_log_setup ("test_communicator_basic",
534                         "DEBUG",
535                         NULL))
536   {
537     fprintf (stderr, "Unable to setup log\n");
538     GNUNET_break (0);
539     return 2;
540   }
541   for (unsigned int i = 0; i < NUM_PEERS; i++)
542   {
543     GNUNET_asprintf ((&cfg_peer),
544                      "test_communicator_%s_peer%u.conf",
545                      communicator_name, i + 1);
546     cfg_peers_name[i] = cfg_peer;
547     cfg_peers[i] = GNUNET_CONFIGURATION_create ();
548     if (GNUNET_YES ==
549         GNUNET_DISK_file_test (cfg_peers_name[i]))
550     {
551       if (GNUNET_SYSERR ==
552           GNUNET_CONFIGURATION_load (cfg_peers[i],
553                                      cfg_peers_name[i]))
554       {
555         fprintf (stderr,
556                  "Malformed configuration file `%s', exiting ...\n",
557                  cfg_peers_name[i]);
558         return 1;
559       }
560     }
561     else
562     {
563       if (GNUNET_SYSERR ==
564           GNUNET_CONFIGURATION_load (cfg_peers[i],
565                                      NULL))
566       {
567         fprintf (stderr,
568                  "Configuration file %s does not exist, exiting ...\n",
569                  cfg_peers_name[i]);
570         return 1;
571       }
572     }
573     private_key =
574       GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg_peers[i]);
575     if (NULL == private_key)
576     {
577       LOG (GNUNET_ERROR_TYPE_ERROR,
578            "Unable to get peer ID\n");
579       return 1;
580     }
581     GNUNET_CRYPTO_eddsa_key_get_public (private_key,
582                                         &peer_id[i].public_key);
583     GNUNET_free (private_key);
584     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
585                 "Identity of peer %u is %s\n",
586                 i,
587                 GNUNET_i2s_full (&peer_id[i]));
588   }
589   fprintf (stderr, "Starting test...\n");
590   GNUNET_SCHEDULER_run (&run,
591                         NULL);
592   return ret;
593 }