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