bed9bdc8546b782d8039318b0ce88f0b128f38cd
[oweals/gnunet.git] / src / transport / gnunet-transport.c
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2011-2014 GNUnet e.V.
4
5  GNUnet is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published
7  by the Free Software Foundation; either version 3, or (at your
8  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  General Public License for more details.
14
15  You should have received a copy of the GNU General Public License
16  along with GNUnet; see the file COPYING.  If not, write to the
17  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * @file src/transport/gnunet-transport.c
23  * @brief Tool to help configure, measure and control the transport subsystem.
24  * @author Christian Grothoff
25  * @author Nathan Evans
26  *
27  * This utility can be used to test if a transport mechanism for
28  * GNUnet is properly configured.
29  */
30 #include "platform.h"
31 #include "gnunet_util_lib.h"
32 #include "gnunet_resolver_service.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_nat_lib.h"
36
37 /**
38  * How long do we wait for the NAT test to report success?
39  * Should match NAT_SERVER_TIMEOUT in 'nat_test.c'.
40  */
41 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
42
43 /**
44  * Timeout for a name resolution
45  */
46 #define RESOLUTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
47
48 /**
49  * Timeout for an operation
50  */
51 #define OP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
52
53
54 /**
55  * Context to store name resolutions for valiation
56  */
57 struct ValidationResolutionContext
58 {
59   /**
60    * Next in DLL
61    */
62   struct ValidationResolutionContext *next;
63
64   /**
65    * Previous in DLL
66    */
67   struct ValidationResolutionContext *prev;
68
69   /**
70    * Address to resolve
71    */
72   struct GNUNET_HELLO_Address *addrcp;
73
74   /**
75    * Time of last validation
76    */
77   struct GNUNET_TIME_Absolute last_validation;
78
79   /**
80    * Address is valid until
81    */
82   struct GNUNET_TIME_Absolute valid_until;
83
84   /**
85    * Time of next validation
86    */
87   struct GNUNET_TIME_Absolute next_validation;
88
89   /**
90    * state of validation process
91    */
92   enum GNUNET_TRANSPORT_ValidationState state;
93
94   /**
95    * Tranport conversion handle
96    */
97   struct GNUNET_TRANSPORT_AddressToStringContext *asc;
98
99   /**
100    * plugin name
101    */
102   char *transport;
103
104   /**
105    * was the entry printed
106    */
107   int printed;
108 };
109
110 /**
111  * Struct to store information about peers in monitor mode
112  */
113 struct MonitoredPeer
114 {
115   /**
116    * State of the peer
117    */
118   enum GNUNET_TRANSPORT_PeerState state;
119
120   /**
121    * Timeout
122    */
123   struct GNUNET_TIME_Absolute state_timeout;
124
125   /**
126    * The address to convert
127    */
128   struct GNUNET_HELLO_Address *address;
129 };
130
131 /**
132  * Context to store name resolutions for valiation
133  */
134 struct PeerResolutionContext
135 {
136   /**
137    * Next in DLL
138    */
139   struct PeerResolutionContext *next;
140
141   /**
142    * Prev in DLL
143    */
144   struct PeerResolutionContext *prev;
145
146   /**
147    * address to resolve
148    */
149   struct GNUNET_HELLO_Address *addrcp;
150
151   /**
152    * transport conversiion context
153    */
154   struct GNUNET_TRANSPORT_AddressToStringContext *asc;
155
156   /**
157    * peer state
158    */
159   enum GNUNET_TRANSPORT_PeerState state;
160
161   /**
162    * state timeout
163    */
164   struct GNUNET_TIME_Absolute state_timeout;
165
166   /**
167    * transport plugin
168    */
169   char *transport;
170
171   /**
172    * was the entry printed
173    */
174   int printed;
175 };
176
177
178 /**
179  * Context for a plugin test.
180  */
181 struct TestContext
182 {
183   /**
184    * Previous in DLL
185    */
186   struct TestContext *prev;
187
188   /**
189    * Next in DLL
190    */
191   struct TestContext *next;
192
193   /**
194    * Handle to the active NAT test.
195    */
196   struct GNUNET_NAT_Test *tst;
197
198   /**
199    * Task identifier for the timeout.
200    */
201   struct GNUNET_SCHEDULER_Task * tsk;
202
203   /**
204    * Name of plugin under test.
205    */
206   char *name;
207
208   /**
209    * Bound port
210    */
211   unsigned long long bnd_port;
212
213   /**
214    * Advertised ports
215    */
216   unsigned long long adv_port;
217
218 };
219
220
221 /**
222  *
223  */
224 enum TestResult
225 {
226   /**
227    * NAT returned success
228    */
229   NAT_TEST_SUCCESS = GNUNET_OK,
230
231   /**
232    * NAT returned failure
233    */
234   NAT_TEST_FAIL = GNUNET_NO,
235
236   /**
237    * NAT returned failure while running test
238    */
239   NAT_TEST_INTERNAL_FAIL = GNUNET_SYSERR,
240
241   /**
242    * We could not start the test
243    */
244   NAT_TEST_FAILED_TO_START = 2,
245
246   /**
247    * We had a timeout while running the test
248    */
249   NAT_TEST_TIMEOUT = 3
250 };
251
252
253 /**
254  * Benchmarking block size in KB
255  */
256 #define BLOCKSIZE 4
257
258 /**
259  * Which peer should we connect to?
260  */
261 static char *cpid;
262
263 /**
264  * Handle to transport service.
265  */
266 static struct GNUNET_TRANSPORT_Handle *handle;
267
268 /**
269  * Configuration handle
270  */
271 static struct GNUNET_CONFIGURATION_Handle *cfg;
272
273 /**
274  * Blacklisting handle
275  */
276 struct GNUNET_TRANSPORT_Blacklist *blacklist;
277
278 /**
279  * Option -s.
280  */
281 static int benchmark_send;
282
283 /**
284  * Option -b.
285  */
286 static int benchmark_receive;
287
288 /**
289  * Option -l.
290  */
291 static int benchmark_receive;
292
293 /**
294  * Option -i.
295  */
296 static int iterate_connections;
297
298 /**
299  * Option -d.
300  */
301 static int iterate_validation;
302
303 /**
304  * Option -a.
305  */
306 static int iterate_all;
307
308 /**
309  * Option -t.
310  */
311 static int test_configuration;
312
313 /**
314  * Option -c.
315  */
316 static int monitor_connects;
317
318 /**
319  * Option -m.
320  */
321 static int monitor_connections;
322
323 /**
324  * Option -f.
325  */
326 static int monitor_validation;
327
328 /**
329  * Option -P.
330  */
331 static int monitor_plugins;
332
333 /**
334  * Option -D.
335  */
336 static int do_disconnect;
337
338 /**
339  * Option -n.
340  */
341 static int numeric;
342
343 /**
344  * Global return value (0 success).
345  */
346 static int ret;
347
348 /**
349  * Current number of connections in monitor mode
350  */
351 static int monitor_connect_counter;
352
353 /**
354  * Number of bytes of traffic we received so far.
355  */
356 static unsigned long long traffic_received;
357
358 /**
359  * Number of bytes of traffic we sent so far.
360  */
361 static unsigned long long traffic_sent;
362
363 /**
364  * Starting time of transmitting/receiving data.
365  */
366 static struct GNUNET_TIME_Absolute start_time;
367
368 /**
369  * Handle for current transmission request.
370  */
371 static struct GNUNET_TRANSPORT_TransmitHandle *th;
372
373 /**
374  * Map storing information about monitored peers
375  */
376 static struct GNUNET_CONTAINER_MultiPeerMap *monitored_peers;
377
378 /**
379  * Map storing information about monitored plugins's sessions.
380  */
381 static struct GNUNET_CONTAINER_MultiPeerMap *monitored_plugins;
382
383 /**
384  * Handle if we are monitoring peers at the transport level.
385  */
386 static struct GNUNET_TRANSPORT_PeerMonitoringContext *pic;
387
388 /**
389  * Handle if we are monitoring transport validation activity.
390  */
391 static struct GNUNET_TRANSPORT_ValidationMonitoringContext *vic;
392
393 /**
394  * Handle if we are monitoring plugin session activity.
395  */
396 static struct GNUNET_TRANSPORT_PluginMonitor *pm;
397
398 /**
399  * Identity of the peer we transmit to / connect to.
400  * (equivalent to 'cpid' string).
401  */
402 static struct GNUNET_PeerIdentity pid;
403
404 /**
405  * Task scheduled for cleanup / termination of the process.
406  */
407 static struct GNUNET_SCHEDULER_Task * end;
408
409 /**
410  * Task for operation timeout
411  */
412 static struct GNUNET_SCHEDULER_Task * op_timeout;
413
414 /**
415  * Selected level of verbosity.
416  */
417 static int verbosity;
418
419 /**
420  * Resolver process handle.
421  */
422 struct GNUNET_OS_Process *resolver;
423
424 /**
425  * Number of address resolutions pending
426  */
427 static unsigned int address_resolutions;
428
429 /**
430  * DLL for NAT Test Contexts: head
431  */
432 struct TestContext *head;
433
434 /**
435  * DLL for NAT Test Contexts: tail
436  */
437 struct TestContext *tail;
438
439 /**
440  * DLL: head of validation resolution entries
441  */
442 static struct ValidationResolutionContext *vc_head;
443
444 /**
445  * DLL: tail of validation resolution entries
446  */
447 static struct ValidationResolutionContext *vc_tail;
448
449 /**
450  * DLL: head of resolution entries
451  */
452 static struct PeerResolutionContext *rc_head;
453
454 /**
455  * DLL: head of resolution entries
456  */
457 static struct PeerResolutionContext *rc_tail;
458
459
460 /**
461  * Function called to release data stored in the #monitored_peers map.
462  *
463  * @param cls unused
464  * @param key the peer identity
465  * @param value a `struct MonitoredPeer` to release
466  * @return #GNUNET_OK (continue to iterate)
467  */
468 static int
469 destroy_it (void *cls,
470             const struct GNUNET_PeerIdentity *key,
471             void *value)
472 {
473   struct MonitoredPeer *m = value;
474
475   GNUNET_assert (GNUNET_OK ==
476                  GNUNET_CONTAINER_multipeermap_remove (monitored_peers,
477                                                        key,
478                                                        value));
479   GNUNET_free_non_null (m->address);
480   GNUNET_free (value);
481   return GNUNET_OK;
482 }
483
484
485 /**
486  * Task run in monitor mode when the user presses CTRL-C to abort.
487  * Stops monitoring activity.
488  *
489  * @param cls NULL
490  */
491 static void
492 shutdown_task (void *cls)
493 {
494   struct GNUNET_TIME_Relative duration;
495   struct ValidationResolutionContext *cur;
496   struct ValidationResolutionContext *next;
497   struct PeerResolutionContext *rc;
498
499   end = NULL;
500   if (NULL != op_timeout)
501   {
502     GNUNET_SCHEDULER_cancel (op_timeout);
503     op_timeout = NULL;
504   }
505   if (NULL != pic)
506   {
507     GNUNET_TRANSPORT_monitor_peers_cancel (pic);
508     pic = NULL;
509   }
510   if (NULL != vic)
511   {
512     GNUNET_TRANSPORT_monitor_validation_entries_cancel (vic);
513     vic = NULL;
514   }
515   if (NULL != pm)
516   {
517     GNUNET_TRANSPORT_monitor_plugins_cancel (pm);
518     pm = NULL;
519   }
520
521   next = vc_head;
522   for (cur = next; NULL != cur; cur = next)
523   {
524     next = cur->next;
525
526     GNUNET_TRANSPORT_address_to_string_cancel (cur->asc);
527     GNUNET_CONTAINER_DLL_remove (vc_head,
528                                  vc_tail,
529                                  cur);
530     GNUNET_free (cur->transport);
531     GNUNET_HELLO_address_free (cur->addrcp);
532     GNUNET_free (cur);
533   }
534   while (NULL != (rc = rc_head))
535   {
536     GNUNET_CONTAINER_DLL_remove (rc_head,
537                                  rc_tail,
538                                  rc);
539     GNUNET_TRANSPORT_address_to_string_cancel (rc->asc);
540     GNUNET_free (rc->transport);
541     GNUNET_free (rc->addrcp);
542     GNUNET_free (rc);
543   }
544   if (NULL != th)
545   {
546     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
547     th = NULL;
548   }
549   if (NULL != handle)
550   {
551     GNUNET_TRANSPORT_disconnect (handle);
552     handle = NULL;
553   }
554   if (benchmark_send)
555   {
556     duration = GNUNET_TIME_absolute_get_duration (start_time);
557     FPRINTF (stdout,
558              _("Transmitted %llu bytes/s (%llu bytes in %s)\n"),
559              1000LL * 1000LL * traffic_sent / (1 + duration.rel_value_us),
560              traffic_sent,
561              GNUNET_STRINGS_relative_time_to_string (duration, GNUNET_YES));
562   }
563   if (benchmark_receive)
564   {
565     duration = GNUNET_TIME_absolute_get_duration (start_time);
566     FPRINTF (stdout,
567              _("Received %llu bytes/s (%llu bytes in %s)\n"),
568              1000LL * 1000LL * traffic_received / (1 + duration.rel_value_us),
569              traffic_received,
570              GNUNET_STRINGS_relative_time_to_string (duration, GNUNET_YES));
571   }
572
573   if (NULL != monitored_peers)
574   {
575     GNUNET_CONTAINER_multipeermap_iterate (monitored_peers, &destroy_it, NULL);
576     GNUNET_CONTAINER_multipeermap_destroy (monitored_peers);
577     monitored_peers = NULL;
578   }
579   if (NULL != monitored_plugins)
580   {
581     GNUNET_break (0 ==
582                   GNUNET_CONTAINER_multipeermap_size (monitored_plugins));
583     GNUNET_CONTAINER_multipeermap_destroy (monitored_plugins);
584     monitored_plugins = NULL;
585   }
586   if (NULL != blacklist)
587   {
588     GNUNET_TRANSPORT_blacklist_cancel (blacklist);
589     blacklist = NULL;
590     ret = 0;
591   }
592 }
593
594
595 /**
596  * We are done, shut down.
597  */
598 static void
599 operation_timeout (void *cls)
600 {
601   struct PeerResolutionContext *cur;
602   struct PeerResolutionContext *next;
603
604   op_timeout = NULL;
605   if ((benchmark_send) || (benchmark_receive))
606   {
607     FPRINTF (stdout,
608              _("Failed to connect to `%s'\n"),
609              GNUNET_i2s_full (&pid));
610     if (NULL != end)
611       GNUNET_SCHEDULER_cancel (end);
612     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
613     ret = 1;
614     return;
615   }
616   if (iterate_connections)
617   {
618     next = rc_head;
619     while (NULL != (cur = next))
620     {
621       next = cur->next;
622       FPRINTF (stdout,
623                _("Failed to resolve address for peer `%s'\n"),
624                GNUNET_i2s (&cur->addrcp->peer));
625
626       GNUNET_CONTAINER_DLL_remove(rc_head, rc_tail, cur);
627       GNUNET_TRANSPORT_address_to_string_cancel (cur->asc);
628       GNUNET_free(cur->transport);
629       GNUNET_free(cur->addrcp);
630       GNUNET_free(cur);
631
632     }
633     FPRINTF (stdout,
634              "%s",
635              _("Failed to list connections, timeout occured\n"));
636     if (NULL != end)
637       GNUNET_SCHEDULER_cancel (end);
638     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
639     ret = 1;
640     return;
641   }
642 }
643
644
645 static void
646 run_nat_test (void);
647
648
649 /**
650  * Display the result of the test.
651  *
652  * @param tc test context
653  * @param result #GNUNET_YES on success
654  */
655 static void
656 display_test_result (struct TestContext *tc,
657                      enum TestResult result)
658 {
659   switch (result) {
660     case NAT_TEST_FAIL:
661       FPRINTF (stderr,
662                _("Configuration for plugin `%s' did not work!\n"),
663                tc->name);
664       break;
665     case NAT_TEST_SUCCESS:
666       FPRINTF (stderr,
667                _("Configuration for plugin `%s' did work!\n"),
668                tc->name);
669       break;
670     case NAT_TEST_INTERNAL_FAIL:
671       FPRINTF (stderr,
672                _("Internal NAT error while running test for plugin `%s'\n"),
673                tc->name);
674       break;
675     case NAT_TEST_FAILED_TO_START:
676       FPRINTF (stderr,
677                _("Failed to start NAT test for plugin `%s'\n"),
678                tc->name);
679       break;
680     case NAT_TEST_TIMEOUT:
681       FPRINTF (stderr,
682                _("Timeout while waiting for result of NAT test for plugin `%s'\n"),
683                tc->name);
684       break;
685     default:
686       FPRINTF (stderr,
687                _("Configuration for plugin `%s' did not work!\n"),
688                tc->name);
689       break;
690   }
691   if (NULL != tc->tsk)
692   {
693     GNUNET_SCHEDULER_cancel (tc->tsk);
694     tc->tsk = NULL;
695   }
696   if (NULL != tc->tst)
697   {
698     GNUNET_NAT_test_stop (tc->tst);
699     tc->tst = NULL;
700   }
701
702   GNUNET_CONTAINER_DLL_remove (head, tail, tc);
703   GNUNET_free (tc->name);
704   GNUNET_free (tc);
705
706   if ((NULL == head) && (NULL != resolver))
707   {
708     GNUNET_break (0 == GNUNET_OS_process_kill (resolver,
709                                                GNUNET_TERM_SIG));
710     GNUNET_OS_process_destroy (resolver);
711     resolver = NULL;
712   }
713   if (NULL != head)
714     run_nat_test ();
715 }
716
717
718 /**
719  * Function called by NAT to report the outcome of the nat-test.
720  * Clean up and update GUI.
721  *
722  * @param cls test context
723  * @param result status code
724  */
725 static void
726 result_callback (void *cls,
727                  enum GNUNET_NAT_StatusCode result)
728 {
729   struct TestContext *tc = cls;
730
731   display_test_result (tc,
732                        result);
733 }
734
735
736 /**
737  * Resolve address we got a validation state for to a string.
738  *
739  * @param address the address itself
740  * @param numeric #GNUNET_YES to disable DNS, #GNUNET_NO to try reverse lookup
741  * @param last_validation when was the address validated last
742  * @param valid_until until when is the address valid
743  * @param next_validation when will we try to revalidate the address next
744  * @param state where are we in the validation state machine
745  */
746 static void
747 resolve_validation_address (const struct GNUNET_HELLO_Address *address,
748                             int numeric,
749                             struct GNUNET_TIME_Absolute last_validation,
750                             struct GNUNET_TIME_Absolute valid_until,
751                             struct GNUNET_TIME_Absolute next_validation,
752                             enum GNUNET_TRANSPORT_ValidationState state);
753
754
755 /**
756  * Function to call with a textual representation of an address.  This
757  * function will be called several times with different possible
758  * textual representations, and a last time with @a address being NULL
759  * to signal the end of the iteration.  Note that @a address NULL
760  * always is the last call, regardless of the value in @a res.
761  *
762  * @param cls closure
763  * @param address NULL on end of iteration,
764  *        otherwise 0-terminated printable UTF-8 string,
765  *        in particular an empty string if @a res is #GNUNET_NO
766  * @param res result of the address to string conversion:
767  *        if #GNUNET_OK: conversion successful
768  *        if #GNUNET_NO: address was invalid (or not supported)
769  *        if #GNUNET_SYSERR: communication error (IPC error)
770  */
771 static void
772 process_validation_string (void *cls,
773                            const char *address,
774                            int res)
775 {
776   struct ValidationResolutionContext *vc = cls;
777   char *s_valid;
778   char *s_last;
779   char *s_next;
780
781   if (NULL != address)
782   {
783     if (GNUNET_SYSERR == res)
784     {
785       FPRINTF (stderr,
786                "Failed to convert address for peer `%s' plugin `%s' length %u to string \n",
787                GNUNET_i2s (&vc->addrcp->peer),
788                vc->addrcp->transport_name,
789                (unsigned int) vc->addrcp->address_length);
790     }
791     if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == vc->valid_until.abs_value_us)
792       s_valid = GNUNET_strdup ("never");
793     else
794       s_valid = GNUNET_strdup (GNUNET_STRINGS_absolute_time_to_string (vc->valid_until));
795
796     if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == vc->last_validation.abs_value_us)
797       s_last = GNUNET_strdup ("never");
798     else
799       s_last = GNUNET_strdup (GNUNET_STRINGS_absolute_time_to_string (vc->last_validation));
800
801     if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == vc->next_validation.abs_value_us)
802       s_next = GNUNET_strdup ("never");
803     else
804       s_next = GNUNET_strdup (GNUNET_STRINGS_absolute_time_to_string (vc->next_validation));
805
806     FPRINTF (stdout,
807              _("Peer `%s' %s %s\n\t%s%s\n\t%s%s\n\t%s%s\n"),
808              GNUNET_i2s (&vc->addrcp->peer),
809              (GNUNET_OK == res) ? address : "<invalid address>",
810              (monitor_validation) ? GNUNET_TRANSPORT_vs2s (vc->state) : "",
811              "Valid until    : ", s_valid,
812              "Last validation: ",s_last,
813              "Next validation: ", s_next);
814     GNUNET_free (s_valid);
815     GNUNET_free (s_last);
816     GNUNET_free (s_next);
817     vc->printed = GNUNET_YES;
818     return;
819   }
820   /* last call, we are done */
821   GNUNET_assert (address_resolutions > 0);
822   address_resolutions--;
823   if ( (GNUNET_SYSERR == res) &&
824        (GNUNET_NO == vc->printed))
825   {
826     if (numeric == GNUNET_NO)
827     {
828       /* Failed to resolve address, try numeric lookup
829          (note: this should be unnecessary, as
830          transport should fallback to numeric lookup
831          internally if DNS takes too long anyway) */
832       resolve_validation_address (vc->addrcp,
833                                   GNUNET_NO,
834                                   vc->last_validation,
835                                   vc->valid_until,
836                                   vc->next_validation,
837                                   vc->state);
838     }
839     else
840     {
841       FPRINTF (stdout,
842                _("Peer `%s' %s `%s' \n"),
843                GNUNET_i2s (&vc->addrcp->peer),
844                "<unable to resolve address>",
845                GNUNET_TRANSPORT_vs2s (vc->state));
846     }
847   }
848   GNUNET_free (vc->transport);
849   GNUNET_free (vc->addrcp);
850   GNUNET_CONTAINER_DLL_remove (vc_head, vc_tail, vc);
851   GNUNET_free (vc);
852   if ((0 == address_resolutions) && (iterate_validation))
853   {
854     if (NULL != end)
855     {
856       GNUNET_SCHEDULER_cancel (end);
857       end = NULL;
858     }
859     if (NULL != op_timeout)
860     {
861       GNUNET_SCHEDULER_cancel (op_timeout);
862       op_timeout = NULL;
863     }
864     ret = 0;
865     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
866   }
867 }
868
869
870 /**
871  * Resolve address we got a validation state for to a string.
872  *
873  * @param address the address itself
874  * @param numeric #GNUNET_YES to disable DNS, #GNUNET_NO to try reverse lookup
875  * @param last_validation when was the address validated last
876  * @param valid_until until when is the address valid
877  * @param next_validation when will we try to revalidate the address next
878  * @param state where are we in the validation state machine
879  */
880 static void
881 resolve_validation_address (const struct GNUNET_HELLO_Address *address,
882                             int numeric,
883                             struct GNUNET_TIME_Absolute last_validation,
884                             struct GNUNET_TIME_Absolute valid_until,
885                             struct GNUNET_TIME_Absolute next_validation,
886                             enum GNUNET_TRANSPORT_ValidationState state)
887 {
888   struct ValidationResolutionContext *vc;
889
890   vc = GNUNET_new (struct ValidationResolutionContext);
891   GNUNET_assert(NULL != vc);
892   GNUNET_CONTAINER_DLL_insert(vc_head, vc_tail, vc);
893   address_resolutions++;
894
895   vc->transport = GNUNET_strdup(address->transport_name);
896   vc->addrcp = GNUNET_HELLO_address_copy (address);
897   vc->printed = GNUNET_NO;
898   vc->state = state;
899   vc->last_validation = last_validation;
900   vc->valid_until = valid_until;
901   vc->next_validation = next_validation;
902
903   /* Resolve address to string */
904   vc->asc = GNUNET_TRANSPORT_address_to_string (cfg,
905                                                 address,
906                                                 numeric,
907                                                 RESOLUTION_TIMEOUT,
908                                                 &process_validation_string, vc);
909 }
910
911
912 /**
913  * Resolve address we got a validation state for to a string.
914  *
915  * @param cls NULL
916  * @param address the address itself
917  * @param last_validation when was the address validated last
918  * @param valid_until until when is the address valid
919  * @param next_validation when will we try to revalidate the address next
920  * @param state where are we in the validation state machine
921  */
922 static void
923 process_validation_cb (void *cls,
924                        const struct GNUNET_HELLO_Address *address,
925                        struct GNUNET_TIME_Absolute last_validation,
926                        struct GNUNET_TIME_Absolute valid_until,
927                        struct GNUNET_TIME_Absolute next_validation,
928                        enum GNUNET_TRANSPORT_ValidationState state)
929 {
930   if (NULL == address)
931   {
932     if (monitor_validation)
933     {
934       FPRINTF (stdout,
935                "%s",
936                _("Monitor disconnected from transport service. Reconnecting.\n"));
937       return;
938     }
939     vic = NULL;
940     if (NULL != end)
941       GNUNET_SCHEDULER_cancel (end);
942     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
943     return;
944   }
945   resolve_validation_address (address,
946                               numeric,
947                               last_validation,
948                               valid_until,
949                               next_validation,
950                               state);
951 }
952
953
954 static void
955 run_nat_test ()
956 {
957   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
958               "Running test for plugin `%s' using bind port %u and advertised port %u \n",
959               head->name,
960               (uint16_t) head->bnd_port,
961               (uint16_t) head->adv_port);
962
963   head->tst = GNUNET_NAT_test_start (cfg,
964                                      (0 == strcasecmp (head->name, "udp"))
965                                      ? GNUNET_NO : GNUNET_YES,
966                                      (uint16_t) head->bnd_port,
967                                      (uint16_t) head->adv_port,
968                                      TIMEOUT,
969                                      &result_callback, head);
970 }
971
972
973 /**
974  * Test our plugin's configuration (NAT traversal, etc.).
975  *
976  * @param cfg configuration to test
977  */
978 static void
979 do_test_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
980 {
981   char *plugins;
982   char *tok;
983   unsigned long long bnd_port;
984   unsigned long long adv_port;
985   struct TestContext *tc;
986   char *binary;
987
988   if (GNUNET_OK
989       != GNUNET_CONFIGURATION_get_value_string (cfg, "transport", "plugins",
990           &plugins))
991   {
992     FPRINTF (stderr, "%s", _
993     ("No transport plugins configured, peer will never communicate\n"));
994     ret = 4;
995     return;
996   }
997
998   for (tok = strtok (plugins, " "); tok != NULL ; tok = strtok (NULL, " "))
999   {
1000     char section[12 + strlen (tok)];
1001     GNUNET_snprintf (section, sizeof(section), "transport-%s", tok);
1002     if (GNUNET_OK
1003         != GNUNET_CONFIGURATION_get_value_number (cfg, section, "PORT",
1004             &bnd_port))
1005     {
1006       FPRINTF (stderr,
1007           _("No port configured for plugin `%s', cannot test it\n"), tok);
1008       continue;
1009     }
1010     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, section,
1011             "ADVERTISED_PORT", &adv_port))
1012       adv_port = bnd_port;
1013
1014     tc = GNUNET_new (struct TestContext);
1015     tc->name = GNUNET_strdup (tok);
1016     tc->adv_port = adv_port;
1017     tc->bnd_port = bnd_port;
1018     GNUNET_CONTAINER_DLL_insert_tail (head, tail, tc);
1019   }
1020   GNUNET_free(plugins);
1021
1022   if ((NULL != head) && (NULL == resolver))
1023   {
1024     binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
1025     resolver = GNUNET_OS_start_process (GNUNET_YES,
1026                                         GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1027                                         NULL, NULL, NULL,
1028                                         binary,
1029                                         "gnunet-service-resolver", NULL);
1030     if (NULL == resolver)
1031     {
1032       FPRINTF (stderr, _("Failed to start resolver!\n"));
1033       return;
1034     }
1035
1036     GNUNET_free(binary);
1037     GNUNET_RESOLVER_connect (cfg);
1038     run_nat_test ();
1039   }
1040 }
1041
1042
1043 /**
1044  * Function called to notify a client about the socket
1045  * begin ready to queue more data.  @a buf will be
1046  * NULL and @a size zero if the socket was closed for
1047  * writing in the meantime.
1048  *
1049  * @param cls closure
1050  * @param size number of bytes available in @a buf
1051  * @param buf where the callee should write the message
1052  * @return number of bytes written to @a buf
1053  */
1054 static size_t
1055 transmit_data (void *cls,
1056                size_t size,
1057                void *buf)
1058 {
1059   struct GNUNET_MessageHeader *m = buf;
1060
1061   if ((NULL == buf) || (0 == size))
1062   {
1063     th = NULL;
1064     return 0;
1065   }
1066
1067   GNUNET_assert(size >= sizeof(struct GNUNET_MessageHeader));
1068   GNUNET_assert(size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
1069   m->size = ntohs (size);
1070   m->type = ntohs (GNUNET_MESSAGE_TYPE_DUMMY);
1071   memset (&m[1], 52, size - sizeof(struct GNUNET_MessageHeader));
1072   traffic_sent += size;
1073   th = GNUNET_TRANSPORT_notify_transmit_ready (handle, &pid,
1074                                                BLOCKSIZE * 1024,
1075                                                GNUNET_TIME_UNIT_FOREVER_REL,
1076                                                &transmit_data, NULL);
1077   if (verbosity > 0)
1078     FPRINTF (stdout, _("Transmitting %u bytes to %s\n"), (unsigned int) size,
1079         GNUNET_i2s (&pid));
1080   return size;
1081 }
1082
1083
1084 /**
1085  * Function called to notify transport users that another
1086  * peer connected to us.
1087  *
1088  * @param cls closure
1089  * @param peer the peer that connected
1090  */
1091 static void
1092 notify_connect (void *cls,
1093                 const struct GNUNET_PeerIdentity *peer)
1094 {
1095   if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
1096     return;
1097   ret = 0;
1098   if (benchmark_send)
1099   {
1100     if (NULL != op_timeout)
1101     {
1102       GNUNET_SCHEDULER_cancel (op_timeout);
1103       op_timeout = NULL;
1104     }
1105     if (verbosity > 0)
1106       FPRINTF (stdout,
1107           _("Successfully connected to `%s', starting to send benchmark data in %u Kb blocks\n"),
1108           GNUNET_i2s (&pid), BLOCKSIZE);
1109     start_time = GNUNET_TIME_absolute_get ();
1110     if (NULL == th)
1111       th = GNUNET_TRANSPORT_notify_transmit_ready (handle, peer,
1112                                                    BLOCKSIZE * 1024,
1113                                                    GNUNET_TIME_UNIT_FOREVER_REL,
1114                                                    &transmit_data,
1115                                                    NULL);
1116     else
1117       GNUNET_break(0);
1118     return;
1119   }
1120 }
1121
1122
1123 /**
1124  * Function called to notify transport users that another
1125  * peer disconnected from us.
1126  *
1127  * @param cls closure
1128  * @param peer the peer that disconnected
1129  */
1130 static void
1131 notify_disconnect (void *cls,
1132                    const struct GNUNET_PeerIdentity *peer)
1133 {
1134   if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
1135     return;
1136
1137   if (NULL != th)
1138   {
1139     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
1140     th = NULL;
1141   }
1142   if (benchmark_send)
1143   {
1144     FPRINTF (stdout, _("Disconnected from peer `%s' while benchmarking\n"),
1145         GNUNET_i2s (&pid));
1146     if (NULL != end)
1147       GNUNET_SCHEDULER_cancel (end);
1148     return;
1149   }
1150 }
1151
1152
1153 /**
1154  * Function called to notify transport users that another
1155  * peer connected to us.
1156  *
1157  * @param cls closure
1158  * @param peer the peer that connected
1159  */
1160 static void
1161 monitor_notify_connect (void *cls,
1162                         const struct GNUNET_PeerIdentity *peer)
1163 {
1164   monitor_connect_counter++;
1165   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1166   const char *now_str = GNUNET_STRINGS_absolute_time_to_string (now);
1167
1168   FPRINTF (stdout,
1169            _("%24s: %-17s %4s   (%u connections in total)\n"),
1170            now_str,
1171            _("Connected to"),
1172            GNUNET_i2s (peer),
1173            monitor_connect_counter);
1174 }
1175
1176
1177 /**
1178  * Function called to notify transport users that another
1179  * peer disconnected from us.
1180  *
1181  * @param cls closure
1182  * @param peer the peer that disconnected
1183  */
1184 static void
1185 monitor_notify_disconnect (void *cls,
1186                            const struct GNUNET_PeerIdentity *peer)
1187 {
1188   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1189   const char *now_str = GNUNET_STRINGS_absolute_time_to_string (now);
1190
1191   GNUNET_assert(monitor_connect_counter > 0);
1192   monitor_connect_counter--;
1193
1194   FPRINTF (stdout,
1195            _("%24s: %-17s %4s   (%u connections in total)\n"),
1196            now_str,
1197            _("Disconnected from"),
1198            GNUNET_i2s (peer),
1199            monitor_connect_counter);
1200 }
1201
1202
1203 /**
1204  * Function called by the transport for each received message.
1205  *
1206  * @param cls closure
1207  * @param peer (claimed) identity of the other peer
1208  * @param message the message
1209  */
1210 static void
1211 notify_receive (void *cls,
1212                 const struct GNUNET_PeerIdentity *peer,
1213                 const struct GNUNET_MessageHeader *message)
1214 {
1215   if (benchmark_receive)
1216   {
1217     if (GNUNET_MESSAGE_TYPE_DUMMY != ntohs (message->type))
1218       return;
1219     if (verbosity > 0)
1220       FPRINTF (stdout,
1221                _("Received %u bytes from %s\n"),
1222                (unsigned int) ntohs (message->size),
1223                GNUNET_i2s (peer));
1224
1225     if (traffic_received == 0)
1226       start_time = GNUNET_TIME_absolute_get ();
1227     traffic_received += ntohs (message->size);
1228     return;
1229   }
1230 }
1231
1232
1233 /**
1234  * Convert address to a printable format.
1235  *
1236  * @param address the address
1237  * @param numeric #GNUNET_YES to convert to numeric format, #GNUNET_NO
1238  *                to try to use reverse DNS
1239  * @param state state the peer is in
1240  * @param state_timeout when will the peer's state expire
1241  */
1242 static void
1243 resolve_peer_address (const struct GNUNET_HELLO_Address *address,
1244                       int numeric,
1245                       enum GNUNET_TRANSPORT_PeerState state,
1246                       struct GNUNET_TIME_Absolute state_timeout);
1247
1248
1249 static void
1250 print_info (const struct GNUNET_PeerIdentity *id,
1251             const char *transport,
1252             const char *addr,
1253             enum GNUNET_TRANSPORT_PeerState state,
1254             struct GNUNET_TIME_Absolute state_timeout)
1255 {
1256
1257   if ( ((GNUNET_YES == iterate_connections) && (GNUNET_YES == iterate_all)) ||
1258        (GNUNET_YES == monitor_connections))
1259   {
1260     FPRINTF (stdout,
1261              _("Peer `%s': %s %s in state `%s' until %s\n"),
1262              GNUNET_i2s (id),
1263              (NULL == transport) ? "<none>" : transport,
1264              (NULL == transport) ? "<none>" : addr,
1265              GNUNET_TRANSPORT_ps2s (state),
1266              GNUNET_STRINGS_absolute_time_to_string (state_timeout));
1267   }
1268   else if ( (GNUNET_YES == iterate_connections) &&
1269              (GNUNET_TRANSPORT_is_connected(state)))
1270   {
1271     /* Only connected peers, skip state */
1272     FPRINTF (stdout,
1273              _("Peer `%s': %s %s\n"),
1274              GNUNET_i2s (id),
1275              transport,
1276              addr);
1277   }
1278 }
1279
1280
1281 /**
1282  * Function called with a textual representation of an address.  This
1283  * function will be called several times with different possible
1284  * textual representations, and a last time with @a address being NULL
1285  * to signal the end of the iteration.  Note that @a address NULL
1286  * always is the last call, regardless of the value in @a res.
1287  *
1288  * @param cls closure
1289  * @param address NULL on end of iteration,
1290  *        otherwise 0-terminated printable UTF-8 string,
1291  *        in particular an empty string if @a res is #GNUNET_NO
1292  * @param res result of the address to string conversion:
1293  *        if #GNUNET_OK: conversion successful
1294  *        if #GNUNET_NO: address was invalid (or not supported)
1295  *        if #GNUNET_SYSERR: communication error (IPC error)
1296  */
1297 static void
1298 process_peer_string (void *cls,
1299                      const char *address,
1300                      int res)
1301 {
1302   struct PeerResolutionContext *rc = cls;
1303
1304   if (NULL != address)
1305   {
1306     if (GNUNET_SYSERR == res)
1307     {
1308       FPRINTF (stderr,
1309                "Failed to convert address for peer `%s' plugin `%s' length %u to string \n",
1310                GNUNET_i2s (&rc->addrcp->peer),
1311                rc->addrcp->transport_name,
1312                (unsigned int) rc->addrcp->address_length);
1313       print_info (&rc->addrcp->peer,
1314                   rc->transport,
1315                   NULL,
1316                   rc->state,
1317                   rc->state_timeout);
1318       rc->printed = GNUNET_YES;
1319       return;
1320     }
1321     if (GNUNET_OK == res)
1322     {
1323       print_info (&rc->addrcp->peer,
1324                   rc->transport,
1325                   address,
1326                   rc->state,
1327                   rc->state_timeout);
1328       rc->printed = GNUNET_YES;
1329       return; /* Wait for done call */
1330     }
1331     /* GNUNET_NO == res: ignore, was simply not supported */
1332     return;
1333   }
1334   /* NULL == address, last call, we are done */
1335
1336   rc->asc = NULL;
1337   GNUNET_assert (address_resolutions > 0);
1338   address_resolutions--;
1339   if (GNUNET_NO == rc->printed)
1340   {
1341     if (numeric == GNUNET_NO)
1342     {
1343       /* Failed to resolve address, try numeric lookup
1344          (note: this should not be needed, as transport
1345          should fallback to numeric conversion if DNS takes
1346          too long) */
1347       resolve_peer_address (rc->addrcp,
1348                             GNUNET_YES,
1349                             rc->state,
1350                             rc->state_timeout);
1351     }
1352     else
1353     {
1354       print_info (&rc->addrcp->peer,
1355                   rc->transport,
1356                   NULL,
1357                   rc->state,
1358                   rc->state_timeout);
1359     }
1360   }
1361   GNUNET_free (rc->transport);
1362   GNUNET_free (rc->addrcp);
1363   GNUNET_CONTAINER_DLL_remove (rc_head, rc_tail, rc);
1364   GNUNET_free (rc);
1365   if ((0 == address_resolutions) && (iterate_connections))
1366   {
1367     if (NULL != end)
1368     {
1369       GNUNET_SCHEDULER_cancel (end);
1370       end = NULL;
1371     }
1372     if (NULL != op_timeout)
1373     {
1374       GNUNET_SCHEDULER_cancel (op_timeout);
1375       op_timeout = NULL;
1376     }
1377     ret = 0;
1378     end = GNUNET_SCHEDULER_add_now (&shutdown_task,
1379                                     NULL);
1380   }
1381 }
1382
1383
1384 /**
1385  * Convert address to a printable format and print it
1386  * together with the given state data.
1387  *
1388  * @param address the address
1389  * @param numeric #GNUNET_YES to convert to numeric format, #GNUNET_NO
1390  *                to try to use reverse DNS
1391  * @param state state the peer is in
1392  * @param state_timeout when will the peer's state expire
1393  */
1394 static void
1395 resolve_peer_address (const struct GNUNET_HELLO_Address *address,
1396                       int numeric,
1397                       enum GNUNET_TRANSPORT_PeerState state,
1398                       struct GNUNET_TIME_Absolute state_timeout)
1399 {
1400   struct PeerResolutionContext *rc;
1401
1402   rc = GNUNET_new (struct PeerResolutionContext);
1403   GNUNET_CONTAINER_DLL_insert (rc_head,
1404                                rc_tail,
1405                                rc);
1406   address_resolutions++;
1407   rc->transport = GNUNET_strdup (address->transport_name);
1408   rc->addrcp = GNUNET_HELLO_address_copy (address);
1409   rc->printed = GNUNET_NO;
1410   rc->state = state;
1411   rc->state_timeout = state_timeout;
1412   /* Resolve address to string */
1413   rc->asc = GNUNET_TRANSPORT_address_to_string (cfg,
1414                                                 address,
1415                                                 numeric,
1416                                                 RESOLUTION_TIMEOUT,
1417                                                 &process_peer_string, rc);
1418 }
1419
1420
1421 /**
1422  * Function called with information about a peers during a one shot iteration
1423  *
1424  * @param cls closure
1425  * @param peer identity of the peer, NULL for final callback when operation done
1426  * @param address binary address used to communicate with this peer,
1427  *  NULL on disconnect or when done
1428  * @param state current state this peer is in
1429  * @param state_timeout time out for the current state
1430  */
1431 static void
1432 process_peer_iteration_cb (void *cls,
1433                            const struct GNUNET_PeerIdentity *peer,
1434                            const struct GNUNET_HELLO_Address *address,
1435                            enum GNUNET_TRANSPORT_PeerState state,
1436                            struct GNUNET_TIME_Absolute state_timeout)
1437 {
1438   if (NULL == peer)
1439   {
1440     /* done */
1441     pic = NULL;
1442     return;
1443   }
1444
1445   if ( (GNUNET_NO == iterate_all) &&
1446        (GNUNET_NO == GNUNET_TRANSPORT_is_connected(state)))
1447       return; /* Display only connected peers */
1448
1449   if (NULL != op_timeout)
1450     GNUNET_SCHEDULER_cancel (op_timeout);
1451   op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1452                                              &operation_timeout,
1453                                              NULL);
1454
1455   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1456               "Received address for peer `%s': %s\n",
1457               GNUNET_i2s (peer),
1458               address ? address->transport_name : "");
1459
1460   if (NULL != address)
1461     resolve_peer_address (address,
1462                           numeric,
1463                           state,
1464                           state_timeout);
1465   else
1466     print_info (peer,
1467                 NULL,
1468                 NULL,
1469                 state,
1470                 state_timeout);
1471 }
1472
1473
1474 /**
1475  * Context for address resolution by #plugin_monitoring_cb().
1476  */
1477 struct PluginMonitorAddress
1478 {
1479
1480   /**
1481    * Ongoing resolution request.
1482    */
1483   struct GNUNET_TRANSPORT_AddressToStringContext *asc;
1484
1485   /**
1486    * Resolved address as string.
1487    */
1488   char *str;
1489
1490   /**
1491    * Last event we got and did not yet print because
1492    * @e str was NULL (address not yet resolved).
1493    */
1494   struct GNUNET_TRANSPORT_SessionInfo si;
1495 };
1496
1497
1498 /**
1499  * Print information about a plugin monitoring event.
1500  *
1501  * @param addr out internal context
1502  * @param info the monitoring information
1503  */
1504 static void
1505 print_plugin_event_info (struct PluginMonitorAddress *addr,
1506                          const struct GNUNET_TRANSPORT_SessionInfo *info)
1507 {
1508   const char *state;
1509
1510   switch (info->state)
1511   {
1512   case GNUNET_TRANSPORT_SS_INIT:
1513     state = "INIT";
1514     break;
1515   case GNUNET_TRANSPORT_SS_HANDSHAKE:
1516     state = "HANDSHAKE";
1517     break;
1518   case GNUNET_TRANSPORT_SS_UP:
1519     state = "UP";
1520     break;
1521   case GNUNET_TRANSPORT_SS_UPDATE:
1522     state = "UPDATE";
1523     break;
1524   case GNUNET_TRANSPORT_SS_DONE:
1525     state = "DONE";
1526     break;
1527   default:
1528     state = "UNKNOWN";
1529     break;
1530   }
1531   fprintf (stdout,
1532            "%s: state %s timeout in %s @ %s%s\n",
1533            GNUNET_i2s (&info->address->peer),
1534            state,
1535            GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (info->session_timeout),
1536                                                    GNUNET_YES),
1537            addr->str,
1538            (info->is_inbound == GNUNET_YES) ? " (INBOUND)" : "");
1539   fprintf (stdout,
1540            "%s: queue has %3u messages and %6u bytes\n",
1541            GNUNET_i2s (&info->address->peer),
1542            info->num_msg_pending,
1543            info->num_bytes_pending);
1544   if (0 != GNUNET_TIME_absolute_get_remaining (info->receive_delay).rel_value_us)
1545     fprintf (stdout,
1546              "%s: receiving blocked until %s\n",
1547              GNUNET_i2s (&info->address->peer),
1548              GNUNET_STRINGS_absolute_time_to_string (info->receive_delay));
1549 }
1550
1551
1552 /**
1553  * Function called with a textual representation of an address.  This
1554  * function will be called several times with different possible
1555  * textual representations, and a last time with @a address being NULL
1556  * to signal the end of the iteration.  Note that @a address NULL
1557  * always is the last call, regardless of the value in @a res.
1558  *
1559  * @param cls closure
1560  * @param address NULL on end of iteration,
1561  *        otherwise 0-terminated printable UTF-8 string,
1562  *        in particular an empty string if @a res is #GNUNET_NO
1563  * @param res result of the address to string conversion:
1564  *        if #GNUNET_OK: conversion successful
1565  *        if #GNUNET_NO: address was invalid (or not supported)
1566  *        if #GNUNET_SYSERR: communication error (IPC error)
1567  */
1568 static void
1569 address_cb (void *cls,
1570             const char *address,
1571             int res)
1572 {
1573   struct PluginMonitorAddress *addr = cls;
1574
1575   if (NULL == address)
1576   {
1577     addr->asc = NULL;
1578     return;
1579   }
1580   if (NULL != addr->str)
1581     return;
1582   addr->str = GNUNET_strdup (address);
1583   print_plugin_event_info (addr,
1584                            &addr->si);
1585 }
1586
1587
1588 /**
1589  * Function called by the plugin with information about the
1590  * current sessions managed by the plugin (for monitoring).
1591  *
1592  * @param cls closure (NULL)
1593  * @param session session handle this information is about,
1594  *        NULL to indicate that we are "in sync" (initial
1595  *        iteration complete)
1596  * @param session_ctx storage location where the application
1597  *        can store data; will point to NULL on #GNUNET_TRANSPORT_SS_INIT,
1598  *        and must be reset to NULL on #GNUNET_TRANSPORT_SS_DONE
1599  * @param info information about the state of the session,
1600  *        NULL if @a session is also NULL and we are
1601  *        merely signalling that the initial iteration is over;
1602  *        NULL with @a session being non-NULL if the monitor
1603  *        was being cancelled while sessions were active
1604  */
1605 static void
1606 plugin_monitoring_cb (void *cls,
1607                       struct GNUNET_TRANSPORT_PluginSession *session,
1608                       void **session_ctx,
1609                       const struct GNUNET_TRANSPORT_SessionInfo *info)
1610 {
1611   struct PluginMonitorAddress *addr;
1612
1613   if ( (NULL == info) &&
1614        (NULL == session) )
1615     return; /* in sync with transport service */
1616   addr = *session_ctx;
1617   if (NULL == info)
1618   {
1619     if (NULL != addr)
1620     {
1621       if (NULL != addr->asc)
1622       {
1623         GNUNET_TRANSPORT_address_to_string_cancel (addr->asc);
1624         addr->asc = NULL;
1625       }
1626       GNUNET_free_non_null (addr->str);
1627       GNUNET_free (addr);
1628       *session_ctx = NULL;
1629     }
1630     return; /* shutdown */
1631   }
1632   if ( (NULL != cpid) &&
1633        (0 != memcmp (&info->address->peer,
1634                      cpid,
1635                      sizeof (struct GNUNET_PeerIdentity))) )
1636     return; /* filtered */
1637   if (NULL == addr)
1638   {
1639     addr = GNUNET_new (struct PluginMonitorAddress);
1640     addr->asc = GNUNET_TRANSPORT_address_to_string (cfg,
1641                                                     info->address,
1642                                                     numeric,
1643                                                     GNUNET_TIME_UNIT_FOREVER_REL,
1644                                                     &address_cb,
1645                                                     addr);
1646     *session_ctx = addr;
1647   }
1648   if (NULL == addr->str)
1649     addr->si = *info;
1650   else
1651     print_plugin_event_info (addr,
1652                              info);
1653   if (GNUNET_TRANSPORT_SS_DONE == info->state)
1654   {
1655     if (NULL != addr->asc)
1656     {
1657       GNUNET_TRANSPORT_address_to_string_cancel (addr->asc);
1658       addr->asc = NULL;
1659     }
1660     GNUNET_free_non_null (addr->str);
1661     GNUNET_free (addr);
1662     *session_ctx = NULL;
1663   }
1664 }
1665
1666
1667 /**
1668  * Function called with information about a peers
1669  *
1670  * @param cls closure, NULL
1671  * @param peer identity of the peer, NULL for final callback when operation done
1672  * @param address binary address used to communicate with this peer,
1673  *  NULL on disconnect or when done
1674  * @param state current state this peer is in
1675  * @param state_timeout time out for the current state
1676  */
1677 static void
1678 process_peer_monitoring_cb (void *cls,
1679                             const struct GNUNET_PeerIdentity *peer,
1680                             const struct GNUNET_HELLO_Address *address,
1681                             enum GNUNET_TRANSPORT_PeerState state,
1682                             struct GNUNET_TIME_Absolute state_timeout)
1683 {
1684   struct MonitoredPeer *m;
1685
1686   if (NULL == peer)
1687   {
1688     FPRINTF (stdout,
1689              "%s",
1690              _("Monitor disconnected from transport service. Reconnecting.\n"));
1691     return;
1692   }
1693
1694   if (NULL != op_timeout)
1695     GNUNET_SCHEDULER_cancel (op_timeout);
1696   op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1697                                              &operation_timeout,
1698                                              NULL);
1699
1700   if (NULL == (m = GNUNET_CONTAINER_multipeermap_get (monitored_peers,
1701                                                       peer)))
1702   {
1703     m = GNUNET_new (struct MonitoredPeer);
1704     GNUNET_CONTAINER_multipeermap_put (monitored_peers,
1705                                        peer,
1706                                        m,
1707                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1708   }
1709   else
1710   {
1711     if ( (m->state == state) &&
1712          (m->state_timeout.abs_value_us == state_timeout.abs_value_us) &&
1713          (NULL == address) &&
1714          (NULL == m->address) )
1715     {
1716       return; /* No real change */
1717     }
1718     if ( (m->state == state) &&
1719          (NULL != address) &&
1720          (NULL != m->address) &&
1721          (0 == GNUNET_HELLO_address_cmp(m->address, address)) )
1722       return; /* No real change */
1723   }
1724
1725   if (NULL != m->address)
1726   {
1727     GNUNET_free (m->address);
1728     m->address = NULL;
1729   }
1730   if (NULL != address)
1731     m->address = GNUNET_HELLO_address_copy (address);
1732   m->state = state;
1733   m->state_timeout = state_timeout;
1734
1735   if (NULL != address)
1736     resolve_peer_address (m->address,
1737                           numeric,
1738                           m->state,
1739                           m->state_timeout);
1740   else
1741     print_info (peer,
1742                 NULL,
1743                 NULL,
1744                 m->state,
1745                 m->state_timeout);
1746 }
1747
1748
1749 /**
1750  * Function called with the transport service checking if we
1751  * want to blacklist a peer. Return #GNUNET_SYSERR for the
1752  * peer that we should disconnect from.
1753  *
1754  * @param cls NULL
1755  * @param cpid peer to check blacklisting for
1756  * @return #GNUNET_OK if the connection is allowed, #GNUNET_SYSERR if not
1757  */
1758 static int
1759 blacklist_cb (void *cls,
1760               const struct GNUNET_PeerIdentity *cpid)
1761 {
1762   if (0 == memcmp (cpid,
1763                    &pid,
1764                    sizeof (struct GNUNET_PeerIdentity)))
1765     return GNUNET_SYSERR;
1766   return GNUNET_OK;
1767 }
1768
1769
1770 /**
1771  * Function called with the result of the check if the 'transport'
1772  * service is running.
1773  *
1774  * @param cls closure with our configuration
1775  * @param result #GNUNET_YES if transport is running
1776  */
1777 static void
1778 testservice_task (void *cls,
1779                   int result)
1780 {
1781   int counter = 0;
1782   ret = 1;
1783
1784   if (GNUNET_YES != result)
1785   {
1786     FPRINTF (stderr, _("Service `%s' is not running\n"), "transport");
1787     return;
1788   }
1789
1790   if ( (NULL != cpid) &&
1791        (GNUNET_OK !=
1792         GNUNET_CRYPTO_eddsa_public_key_from_string (cpid,
1793                                                     strlen (cpid),
1794                                                     &pid.public_key)))
1795   {
1796     FPRINTF (stderr,
1797              _("Failed to parse peer identity `%s'\n"),
1798              cpid);
1799     return;
1800   }
1801
1802   counter = benchmark_send + benchmark_receive + iterate_connections
1803       + monitor_connections + monitor_connects + do_disconnect +
1804       + iterate_validation + monitor_validation + monitor_plugins;
1805
1806   if (1 < counter)
1807   {
1808     FPRINTF (stderr,
1809              _("Multiple operations given. Please choose only one operation: %s, %s, %s, %s, %s, %s %s\n"),
1810              "disconnect", "benchmark send", "benchmark receive", "information",
1811              "monitor", "events", "plugins");
1812     return;
1813   }
1814   if (0 == counter)
1815   {
1816     FPRINTF (stderr,
1817         _("No operation given. Please choose one operation: %s, %s, %s, %s, %s, %s, %s\n"),
1818              "disconnect", "benchmark send", "benchmark receive", "information",
1819              "monitor", "events", "plugins");
1820     return;
1821   }
1822
1823   if (do_disconnect) /* -D: Disconnect from peer */
1824   {
1825     if (NULL == cpid)
1826     {
1827       FPRINTF (stderr,
1828                _("Option `%s' makes no sense without option `%s'.\n"),
1829                "-D", "-p");
1830       ret = 1;
1831       return;
1832     }
1833     blacklist = GNUNET_TRANSPORT_blacklist (cfg,
1834                                             &blacklist_cb,
1835                                             NULL);
1836     if (NULL == blacklist)
1837     {
1838       FPRINTF (stderr,
1839                "%s",
1840                _("Failed to connect to transport service for disconnection\n"));
1841       ret = 1;
1842       return;
1843     }
1844     FPRINTF (stdout,
1845              "%s",
1846              _("Blacklisting request in place, stop with CTRL-C\n"));
1847   }
1848   else if (benchmark_send) /* -s: Benchmark sending */
1849   {
1850     if (NULL == cpid)
1851     {
1852       FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
1853           "-s", "-p");
1854       ret = 1;
1855       return;
1856     }
1857     handle = GNUNET_TRANSPORT_connect (cfg,
1858                                        NULL,
1859                                        NULL,
1860                                        &notify_receive,
1861                                        &notify_connect,
1862                                        &notify_disconnect);
1863     if (NULL == handle)
1864     {
1865       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n"));
1866       ret = 1;
1867       return;
1868     }
1869     start_time = GNUNET_TIME_absolute_get ();
1870     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1871                                                &operation_timeout,
1872                                                NULL);
1873   }
1874   else if (benchmark_receive) /* -b: Benchmark receiving */
1875   {
1876     handle = GNUNET_TRANSPORT_connect (cfg,
1877                                        NULL,
1878                                        NULL,
1879                                        &notify_receive,
1880                                        NULL,
1881                                        NULL);
1882     if (NULL == handle)
1883     {
1884       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n"));
1885       ret = 1;
1886       return;
1887     }
1888     if (verbosity > 0)
1889       FPRINTF (stdout, "%s", _("Starting to receive benchmark data\n"));
1890     start_time = GNUNET_TIME_absolute_get ();
1891
1892   }
1893   else if (iterate_connections) /* -i: List information about peers once */
1894   {
1895     pic = GNUNET_TRANSPORT_monitor_peers (cfg, (NULL == cpid) ? NULL : &pid,
1896         GNUNET_YES, TIMEOUT, &process_peer_iteration_cb, (void *) cfg);
1897     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1898                                                &operation_timeout,
1899                                                NULL);
1900   }
1901   else if (monitor_connections) /* -m: List information about peers continuously */
1902   {
1903     monitored_peers = GNUNET_CONTAINER_multipeermap_create (10,
1904                                                             GNUNET_NO);
1905     pic = GNUNET_TRANSPORT_monitor_peers (cfg,
1906                                           (NULL == cpid) ? NULL : &pid,
1907                                           GNUNET_NO,
1908                                           TIMEOUT,
1909                                           &process_peer_monitoring_cb, NULL);
1910   }
1911   else if (monitor_plugins) /* -P: List information about plugins continuously */
1912   {
1913     monitored_plugins = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1914     pm = GNUNET_TRANSPORT_monitor_plugins (cfg,
1915                                            &plugin_monitoring_cb,
1916                                            NULL);
1917   }
1918   else if (iterate_validation) /* -d: Print information about validations */
1919   {
1920     vic = GNUNET_TRANSPORT_monitor_validation_entries (cfg,
1921                                                        (NULL == cpid) ? NULL : &pid,
1922                                                        GNUNET_YES, TIMEOUT,
1923                                                        &process_validation_cb, (void *) cfg);
1924   }
1925   else if (monitor_validation) /* -f: Print information about validations continuously */
1926   {
1927     vic = GNUNET_TRANSPORT_monitor_validation_entries (cfg,
1928                                                        (NULL == cpid) ? NULL : &pid,
1929                                                        GNUNET_NO, TIMEOUT,
1930                                                        &process_validation_cb, (void *) cfg);
1931   }
1932   else if (monitor_connects) /* -e : Monitor (dis)connect events continuously */
1933   {
1934     monitor_connect_counter = 0;
1935     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, NULL,
1936                                        &monitor_notify_connect,
1937                                        &monitor_notify_disconnect);
1938     if (NULL == handle)
1939     {
1940       FPRINTF (stderr,
1941                "%s",
1942                _("Failed to connect to transport service\n"));
1943       ret = 1;
1944       return;
1945     }
1946     ret = 0;
1947   }
1948   else
1949   {
1950     GNUNET_break(0);
1951     return;
1952   }
1953
1954   end = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1955                                       &shutdown_task,
1956                                       NULL);
1957 }
1958
1959
1960 /**
1961  * Main function that will be run by the scheduler.
1962  *
1963  * @param cls closure
1964  * @param args remaining command-line arguments
1965  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1966  * @param mycfg configuration
1967  */
1968 static void
1969 run (void *cls,
1970      char * const *args,
1971      const char *cfgfile,
1972      const struct GNUNET_CONFIGURATION_Handle *mycfg)
1973 {
1974   cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
1975   if (test_configuration)
1976   {
1977     do_test_configuration (cfg);
1978     return;
1979   }
1980   GNUNET_CLIENT_service_test ("transport", cfg, GNUNET_TIME_UNIT_SECONDS,
1981       &testservice_task, (void *) cfg);
1982 }
1983
1984 int
1985 main (int argc, char * const *argv)
1986 {
1987   int res;
1988   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1989     { 'a', "all", NULL,
1990       gettext_noop ("print information for all peers (instead of only connected peers)"),
1991       0, &GNUNET_GETOPT_set_one, &iterate_all },
1992     { 'b', "benchmark", NULL,
1993       gettext_noop ("measure how fast we are receiving data from all peers (until CTRL-C)"),
1994       0, &GNUNET_GETOPT_set_one, &benchmark_receive },
1995     { 'D', "disconnect",
1996       NULL, gettext_noop ("disconnect to a peer"), 0,
1997       &GNUNET_GETOPT_set_one, &do_disconnect },
1998     { 'd', "validation", NULL,
1999       gettext_noop ("print information for all pending validations "),
2000       0, &GNUNET_GETOPT_set_one, &iterate_validation },
2001     { 'f', "monitorvalidation", NULL,
2002       gettext_noop ("print information for all pending validations continuously"),
2003       0, &GNUNET_GETOPT_set_one, &monitor_validation },
2004     { 'i', "information", NULL,
2005       gettext_noop ("provide information about all current connections (once)"),
2006       0, &GNUNET_GETOPT_set_one, &iterate_connections },
2007     { 'm', "monitor", NULL,
2008       gettext_noop ("provide information about all current connections (continuously)"),
2009       0, &GNUNET_GETOPT_set_one, &monitor_connections },
2010     { 'e', "events", NULL,
2011       gettext_noop ("provide information about all connects and disconnect events (continuously)"),
2012       0, &GNUNET_GETOPT_set_one, &monitor_connects },
2013     { 'n', "numeric",
2014       NULL, gettext_noop ("do not resolve hostnames"), 0,
2015       &GNUNET_GETOPT_set_one, &numeric },
2016     { 'p', "peer", "PEER",
2017       gettext_noop ("peer identity"), 1, &GNUNET_GETOPT_set_string,
2018       &cpid },
2019     { 'P', "plugins", NULL,
2020       gettext_noop ("monitor plugin sessions"), 0, &GNUNET_GETOPT_set_one,
2021       &monitor_plugins },
2022     { 's', "send", NULL, gettext_noop
2023       ("send data for benchmarking to the other peer (until CTRL-C)"), 0,
2024       &GNUNET_GETOPT_set_one, &benchmark_send },
2025     { 't', "test", NULL,
2026       gettext_noop ("test transport configuration (involves external server)"),
2027       0, &GNUNET_GETOPT_set_one, &test_configuration },
2028     GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
2029     GNUNET_GETOPT_OPTION_END
2030   };
2031
2032   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
2033     return 2;
2034
2035   res = GNUNET_PROGRAM_run (argc, argv,
2036                             "gnunet-transport",
2037                             gettext_noop ("Direct access to transport service."),
2038                             options,
2039                             &run, NULL);
2040   GNUNET_free((void *) argv);
2041   if (GNUNET_OK == res)
2042     return ret;
2043   return 1;
2044 }
2045
2046 /* end of gnunet-transport.c */