635213c292d9961179221e48353e0c9546380d57
[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       break;
698   }
699
700   if (GNUNET_YES != result)
701   {
702     FPRINTF (stderr,
703              _("Configuration for plugin `%s' did not work!\n"),
704              tc->name);
705   }
706   else
707   {
708     FPRINTF (stderr,
709              _("Configuration for plugin `%s' is working!\n"),
710              tc->name);
711   }
712   if (NULL != tc->tsk)
713   {
714     GNUNET_SCHEDULER_cancel (tc->tsk);
715     tc->tsk = NULL;
716   }
717   if (NULL != tc->tst)
718   {
719     GNUNET_NAT_test_stop (tc->tst);
720     tc->tst = NULL;
721   }
722
723   GNUNET_CONTAINER_DLL_remove (head, tail, tc);
724   GNUNET_free (tc->name);
725   GNUNET_free (tc);
726
727   if ((NULL == head) && (NULL != resolver))
728   {
729     GNUNET_break (0 == GNUNET_OS_process_kill (resolver,
730                                                GNUNET_TERM_SIG));
731     GNUNET_OS_process_destroy (resolver);
732     resolver = NULL;
733   }
734   if (NULL != head)
735     run_nat_test ();
736 }
737
738 /**
739  * Function called by NAT to report the outcome of the nat-test.
740  * Clean up and update GUI.
741  *
742  * @param cls test context
743  * @param result status code
744  */
745 static void
746 result_callback (void *cls,
747                  enum GNUNET_NAT_StatusCode result)
748 {
749   struct TestContext *tc = cls;
750
751   display_test_result (tc, result);
752 }
753
754
755 /**
756  * Resolve address we got a validation state for to a string.
757  *
758  * @param id peer identity the address is for
759  * @param address the address itself
760  * @param numeric #GNUNET_YES to disable DNS, #GNUNET_NO to try reverse lookup
761  * @param last_validation when was the address validated last
762  * @param valid_until until when is the address valid
763  * @param next_validation when will we try to revalidate the address next
764  * @param state where are we in the validation state machine
765  */
766 static void
767 resolve_validation_address (const struct GNUNET_PeerIdentity *id,
768                             const struct GNUNET_HELLO_Address *address,
769                             int numeric,
770                             struct GNUNET_TIME_Absolute last_validation,
771                             struct GNUNET_TIME_Absolute valid_until,
772                             struct GNUNET_TIME_Absolute next_validation,
773                             enum GNUNET_TRANSPORT_ValidationState state);
774
775
776 /**
777  * Function to call with a textual representation of an address.  This
778  * function will be called several times with different possible
779  * textual representations, and a last time with @a address being NULL
780  * to signal the end of the iteration.  Note that @a address NULL
781  * always is the last call, regardless of the value in @a res.
782  *
783  * @param cls closure
784  * @param address NULL on end of iteration,
785  *        otherwise 0-terminated printable UTF-8 string,
786  *        in particular an empty string if @a res is #GNUNET_NO
787  * @param res result of the address to string conversion:
788  *        if #GNUNET_OK: conversion successful
789  *        if #GNUNET_NO: address was invalid (or not supported)
790  *        if #GNUNET_SYSERR: communication error (IPC error)
791  */
792 static void
793 process_validation_string (void *cls,
794                            const char *address,
795                            int res)
796 {
797   struct ValidationResolutionContext *vc = cls;
798   char *s_valid;
799   char *s_last;
800   char *s_next;
801
802   if (NULL != address)
803   {
804     if (GNUNET_SYSERR == res)
805     {
806       FPRINTF (stderr,
807                "Failed to convert address for peer `%s' plugin `%s' length %u to string \n",
808                GNUNET_i2s (&vc->id),
809                vc->addrcp->transport_name,
810                (unsigned int) vc->addrcp->address_length);
811     }
812     if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == vc->valid_until.abs_value_us)
813       s_valid = GNUNET_strdup ("never");
814     else
815       s_valid = GNUNET_strdup (GNUNET_STRINGS_absolute_time_to_string (vc->valid_until));
816
817     if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == vc->last_validation.abs_value_us)
818       s_last = GNUNET_strdup ("never");
819     else
820       s_last = GNUNET_strdup (GNUNET_STRINGS_absolute_time_to_string (vc->last_validation));
821
822     if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == vc->next_validation.abs_value_us)
823       s_next = GNUNET_strdup ("never");
824     else
825       s_next = GNUNET_strdup (GNUNET_STRINGS_absolute_time_to_string (vc->next_validation));
826
827     FPRINTF (stdout,
828              _("Peer `%s' %s %s\n\t%s%s\n\t%s%s\n\t%s%s\n"),
829              GNUNET_i2s (&vc->id),
830              (GNUNET_OK == res) ? address : "<invalid address>",
831              (monitor_validation) ? GNUNET_TRANSPORT_vs2s (vc->state) : "",
832              "Valid until    : ", s_valid,
833              "Last validation: ",s_last,
834              "Next validation: ", s_next);
835     GNUNET_free (s_valid);
836     GNUNET_free (s_last);
837     GNUNET_free (s_next);
838     vc->printed = GNUNET_YES;
839     return;
840   }
841   /* last call, we are done */
842   GNUNET_assert (address_resolutions > 0);
843   address_resolutions--;
844   if ( (GNUNET_SYSERR == res) &&
845        (GNUNET_NO == vc->printed))
846   {
847     if (numeric == GNUNET_NO)
848     {
849       /* Failed to resolve address, try numeric lookup
850          (note: this should be unnecessary, as
851          transport should fallback to numeric lookup
852          internally if DNS takes too long anyway) */
853       resolve_validation_address (&vc->id,
854                                   vc->addrcp,
855                                   GNUNET_NO,
856                                   vc->last_validation,
857                                   vc->valid_until,
858                                   vc->next_validation,
859                                   vc->state);
860     }
861     else
862     {
863       FPRINTF (stdout,
864                _("Peer `%s' %s `%s' \n"),
865                GNUNET_i2s (&vc->id),
866                "<unable to resolve address>",
867                GNUNET_TRANSPORT_vs2s (vc->state));
868     }
869   }
870   GNUNET_free (vc->transport);
871   GNUNET_free (vc->addrcp);
872   GNUNET_CONTAINER_DLL_remove (vc_head, vc_tail, vc);
873   GNUNET_free (vc);
874   if ((0 == address_resolutions) && (iterate_validation))
875   {
876     if (NULL != end)
877     {
878       GNUNET_SCHEDULER_cancel (end);
879       end = NULL;
880     }
881     if (NULL != op_timeout)
882     {
883       GNUNET_SCHEDULER_cancel (op_timeout);
884       op_timeout = NULL;
885     }
886     ret = 0;
887     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
888   }
889 }
890
891
892 /**
893  * Resolve address we got a validation state for to a string.
894  *
895  * @param id peer identity the address is for
896  * @param address the address itself
897  * @param numeric #GNUNET_YES to disable DNS, #GNUNET_NO to try reverse lookup
898  * @param last_validation when was the address validated last
899  * @param valid_until until when is the address valid
900  * @param next_validation when will we try to revalidate the address next
901  * @param state where are we in the validation state machine
902  */
903 static void
904 resolve_validation_address (const struct GNUNET_PeerIdentity *id,
905                             const struct GNUNET_HELLO_Address *address,
906                             int numeric,
907                             struct GNUNET_TIME_Absolute last_validation,
908                             struct GNUNET_TIME_Absolute valid_until,
909                             struct GNUNET_TIME_Absolute next_validation,
910                             enum GNUNET_TRANSPORT_ValidationState state)
911 {
912   struct ValidationResolutionContext *vc;
913
914   vc = GNUNET_new (struct ValidationResolutionContext);
915   GNUNET_assert(NULL != vc);
916   GNUNET_CONTAINER_DLL_insert(vc_head, vc_tail, vc);
917   address_resolutions++;
918
919   vc->id = (*id);
920   vc->transport = GNUNET_strdup(address->transport_name);
921   vc->addrcp = GNUNET_HELLO_address_copy (address);
922   vc->printed = GNUNET_NO;
923   vc->state = state;
924   vc->last_validation = last_validation;
925   vc->valid_until = valid_until;
926   vc->next_validation = next_validation;
927
928   /* Resolve address to string */
929   vc->asc = GNUNET_TRANSPORT_address_to_string (cfg,
930                                                 address,
931                                                 numeric,
932                                                 RESOLUTION_TIMEOUT,
933                                                 &process_validation_string, vc);
934 }
935
936
937 /**
938  * Resolve address we got a validation state for to a string.
939  *
940  * @param cls NULL
941  * @param peer peer identity the address is for
942  * @param address the address itself
943  * @param last_validation when was the address validated last
944  * @param valid_until until when is the address valid
945  * @param next_validation when will we try to revalidate the address next
946  * @param state where are we in the validation state machine
947  */
948 static void
949 process_validation_cb (void *cls,
950                        const struct GNUNET_PeerIdentity *peer,
951                        const struct GNUNET_HELLO_Address *address,
952                        struct GNUNET_TIME_Absolute last_validation,
953                        struct GNUNET_TIME_Absolute valid_until,
954                        struct GNUNET_TIME_Absolute next_validation,
955                        enum GNUNET_TRANSPORT_ValidationState state)
956 {
957   if ((NULL == peer) && (NULL == address))
958   {
959     if (monitor_validation)
960     {
961       FPRINTF (stdout,
962                "%s",
963                _("Monitor disconnected from transport service. Reconnecting.\n"));
964       return;
965     }
966
967     /* done */
968     vic = NULL;
969     if (NULL != end)
970       GNUNET_SCHEDULER_cancel (end);
971     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
972     return;
973   }
974   if ((NULL == peer) || (NULL == address))
975   {
976     /* invalid response */
977     vic = NULL;
978     if (NULL != end)
979       GNUNET_SCHEDULER_cancel (end);
980     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
981     return;
982   }
983   resolve_validation_address (peer,
984                               address,
985                               numeric,
986                               last_validation,
987                               valid_until,
988                               next_validation,
989                               state);
990 }
991
992
993 static void
994 run_nat_test ()
995 {
996   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
997               "Running test for plugin `%s' using bind port %u and advertised port %u \n",
998               head->name,
999               (uint16_t) head->bnd_port,
1000               (uint16_t) head->adv_port);
1001
1002   head->tst = GNUNET_NAT_test_start (cfg,
1003       (0 == strcasecmp (head->name, "udp")) ? GNUNET_NO : GNUNET_YES,
1004       (uint16_t) head->bnd_port,
1005       (uint16_t) head->adv_port,
1006       TIMEOUT,
1007       &result_callback, head);
1008 }
1009
1010
1011 /**
1012  * Test our plugin's configuration (NAT traversal, etc.).
1013  *
1014  * @param cfg configuration to test
1015  */
1016 static void
1017 do_test_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
1018 {
1019   char *plugins;
1020   char *tok;
1021   unsigned long long bnd_port;
1022   unsigned long long adv_port;
1023   struct TestContext *tc;
1024   char *binary;
1025
1026   if (GNUNET_OK
1027       != GNUNET_CONFIGURATION_get_value_string (cfg, "transport", "plugins",
1028           &plugins))
1029   {
1030     FPRINTF (stderr, "%s", _
1031     ("No transport plugins configured, peer will never communicate\n"));
1032     ret = 4;
1033     return;
1034   }
1035
1036   for (tok = strtok (plugins, " "); tok != NULL ; tok = strtok (NULL, " "))
1037   {
1038     char section[12 + strlen (tok)];
1039     GNUNET_snprintf (section, sizeof(section), "transport-%s", tok);
1040     if (GNUNET_OK
1041         != GNUNET_CONFIGURATION_get_value_number (cfg, section, "PORT",
1042             &bnd_port))
1043     {
1044       FPRINTF (stderr,
1045           _("No port configured for plugin `%s', cannot test it\n"), tok);
1046       continue;
1047     }
1048     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, section,
1049             "ADVERTISED_PORT", &adv_port))
1050       adv_port = bnd_port;
1051
1052     tc = GNUNET_new (struct TestContext);
1053     tc->name = GNUNET_strdup (tok);
1054     tc->adv_port = adv_port;
1055     tc->bnd_port = bnd_port;
1056     GNUNET_CONTAINER_DLL_insert_tail (head, tail, tc);
1057   }
1058   GNUNET_free(plugins);
1059
1060   if ((NULL != head) && (NULL == resolver))
1061   {
1062     binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
1063     resolver = GNUNET_OS_start_process (GNUNET_YES,
1064                                         GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1065                                         NULL, NULL, NULL,
1066                                         binary,
1067                                         "gnunet-service-resolver", NULL);
1068     if (NULL == resolver)
1069     {
1070       FPRINTF (stderr, _("Failed to start resolver!\n"));
1071       return;
1072     }
1073
1074     GNUNET_free(binary);
1075     GNUNET_RESOLVER_connect (cfg);
1076     run_nat_test ();
1077   }
1078 }
1079
1080
1081 /**
1082  * Function called to notify a client about the socket
1083  * begin ready to queue more data.  @a buf will be
1084  * NULL and @a size zero if the socket was closed for
1085  * writing in the meantime.
1086  *
1087  * @param cls closure
1088  * @param size number of bytes available in @a buf
1089  * @param buf where the callee should write the message
1090  * @return number of bytes written to @a buf
1091  */
1092 static size_t
1093 transmit_data (void *cls,
1094                size_t size,
1095                void *buf)
1096 {
1097   struct GNUNET_MessageHeader *m = buf;
1098
1099   if ((NULL == buf) || (0 == size))
1100   {
1101     th = NULL;
1102     return 0;
1103   }
1104
1105   GNUNET_assert(size >= sizeof(struct GNUNET_MessageHeader));
1106   GNUNET_assert(size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
1107   m->size = ntohs (size);
1108   m->type = ntohs (GNUNET_MESSAGE_TYPE_DUMMY);
1109   memset (&m[1], 52, size - sizeof(struct GNUNET_MessageHeader));
1110   traffic_sent += size;
1111   th = GNUNET_TRANSPORT_notify_transmit_ready (handle, &pid,
1112                                                BLOCKSIZE * 1024,
1113                                                GNUNET_TIME_UNIT_FOREVER_REL,
1114                                                &transmit_data, NULL);
1115   if (verbosity > 0)
1116     FPRINTF (stdout, _("Transmitting %u bytes to %s\n"), (unsigned int) size,
1117         GNUNET_i2s (&pid));
1118   return size;
1119 }
1120
1121
1122 /**
1123  * Function called to notify transport users that another
1124  * peer connected to us.
1125  *
1126  * @param cls closure
1127  * @param peer the peer that connected
1128  */
1129 static void
1130 notify_connect (void *cls,
1131                 const struct GNUNET_PeerIdentity *peer)
1132 {
1133   if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
1134     return;
1135   ret = 0;
1136   if (try_connect)
1137   {
1138     /* all done, terminate instantly */
1139     FPRINTF (stdout, _("Successfully connected to `%s'\n"),
1140         GNUNET_i2s_full (peer));
1141     ret = 0;
1142
1143     if (NULL != op_timeout)
1144     {
1145       GNUNET_SCHEDULER_cancel (op_timeout);
1146       op_timeout = NULL;
1147     }
1148
1149     if (NULL != end)
1150       GNUNET_SCHEDULER_cancel (end);
1151     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1152     return;
1153   }
1154   if (benchmark_send)
1155   {
1156     if (NULL != op_timeout)
1157     {
1158       GNUNET_SCHEDULER_cancel (op_timeout);
1159       op_timeout = NULL;
1160     }
1161     if (verbosity > 0)
1162       FPRINTF (stdout,
1163           _("Successfully connected to `%s', starting to send benchmark data in %u Kb blocks\n"),
1164           GNUNET_i2s (&pid), BLOCKSIZE);
1165     start_time = GNUNET_TIME_absolute_get ();
1166     if (NULL == th)
1167       th = GNUNET_TRANSPORT_notify_transmit_ready (handle, peer,
1168                                                    BLOCKSIZE * 1024,
1169                                                    GNUNET_TIME_UNIT_FOREVER_REL,
1170                                                    &transmit_data,
1171                                                    NULL);
1172     else
1173       GNUNET_break(0);
1174     return;
1175   }
1176 }
1177
1178
1179 /**
1180  * Function called to notify transport users that another
1181  * peer disconnected from us.
1182  *
1183  * @param cls closure
1184  * @param peer the peer that disconnected
1185  */
1186 static void
1187 notify_disconnect (void *cls,
1188                    const struct GNUNET_PeerIdentity *peer)
1189 {
1190   if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
1191     return;
1192
1193   if (try_disconnect)
1194   {
1195     /* all done, terminate instantly */
1196     FPRINTF (stdout, _("Successfully disconnected from `%s'\n"),
1197         GNUNET_i2s_full (peer));
1198     ret = 0;
1199
1200     if (NULL != op_timeout)
1201     {
1202       GNUNET_SCHEDULER_cancel (op_timeout);
1203       op_timeout = NULL;
1204     }
1205
1206     if (NULL != end)
1207       GNUNET_SCHEDULER_cancel (end);
1208     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1209     return;
1210   }
1211
1212   if (NULL != th)
1213   {
1214     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
1215     th = NULL;
1216   }
1217   if (benchmark_send)
1218   {
1219     FPRINTF (stdout, _("Disconnected from peer `%s' while benchmarking\n"),
1220         GNUNET_i2s (&pid));
1221     if (NULL != end)
1222       GNUNET_SCHEDULER_cancel (end);
1223     return;
1224   }
1225 }
1226
1227
1228 /**
1229  * Function called to notify transport users that another
1230  * peer connected to us.
1231  *
1232  * @param cls closure
1233  * @param peer the peer that connected
1234  */
1235 static void
1236 monitor_notify_connect (void *cls,
1237                         const struct GNUNET_PeerIdentity *peer)
1238 {
1239   monitor_connect_counter++;
1240   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1241   const char *now_str = GNUNET_STRINGS_absolute_time_to_string (now);
1242
1243   FPRINTF (stdout,
1244            _("%24s: %-17s %4s   (%u connections in total)\n"),
1245            now_str,
1246            _("Connected to"),
1247            GNUNET_i2s (peer),
1248            monitor_connect_counter);
1249 }
1250
1251
1252 /**
1253  * Function called to notify transport users that another
1254  * peer disconnected from us.
1255  *
1256  * @param cls closure
1257  * @param peer the peer that disconnected
1258  */
1259 static void
1260 monitor_notify_disconnect (void *cls,
1261                            const struct GNUNET_PeerIdentity *peer)
1262 {
1263   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1264   const char *now_str = GNUNET_STRINGS_absolute_time_to_string (now);
1265
1266   GNUNET_assert(monitor_connect_counter > 0);
1267   monitor_connect_counter--;
1268
1269   FPRINTF (stdout,
1270            _("%24s: %-17s %4s   (%u connections in total)\n"),
1271            now_str,
1272            _("Disconnected from"),
1273            GNUNET_i2s (peer),
1274            monitor_connect_counter);
1275 }
1276
1277
1278 /**
1279  * Function called by the transport for each received message.
1280  *
1281  * @param cls closure
1282  * @param peer (claimed) identity of the other peer
1283  * @param message the message
1284  */
1285 static void
1286 notify_receive (void *cls,
1287                 const struct GNUNET_PeerIdentity *peer,
1288                 const struct GNUNET_MessageHeader *message)
1289 {
1290   if (benchmark_receive)
1291   {
1292     if (GNUNET_MESSAGE_TYPE_DUMMY != ntohs (message->type))
1293       return;
1294     if (verbosity > 0)
1295       FPRINTF (stdout,
1296                _("Received %u bytes from %s\n"),
1297                (unsigned int) ntohs (message->size),
1298                GNUNET_i2s (peer));
1299
1300     if (traffic_received == 0)
1301       start_time = GNUNET_TIME_absolute_get ();
1302     traffic_received += ntohs (message->size);
1303     return;
1304   }
1305 }
1306
1307
1308 static void
1309 resolve_peer_address (const struct GNUNET_PeerIdentity *id,
1310                       const struct GNUNET_HELLO_Address *address,
1311                       int numeric,
1312                       enum GNUNET_TRANSPORT_PeerState state,
1313                       struct GNUNET_TIME_Absolute state_timeout);
1314
1315
1316 static void
1317 print_info (const struct GNUNET_PeerIdentity *id,
1318             const char *transport,
1319             const char *addr,
1320             enum GNUNET_TRANSPORT_PeerState state,
1321             struct GNUNET_TIME_Absolute state_timeout)
1322 {
1323
1324   if ( ((GNUNET_YES == iterate_connections) && (GNUNET_YES == iterate_all)) ||
1325        (GNUNET_YES == monitor_connections))
1326   {
1327     FPRINTF (stdout,
1328              _("Peer `%s': %s %s in state `%s' until %s\n"),
1329              GNUNET_i2s (id),
1330              (NULL == transport) ? "<none>" : transport,
1331              (NULL == transport) ? "<none>" : addr,
1332              GNUNET_TRANSPORT_ps2s (state),
1333              GNUNET_STRINGS_absolute_time_to_string (state_timeout));
1334   }
1335   else if ( (GNUNET_YES == iterate_connections) &&
1336              (GNUNET_TRANSPORT_is_connected(state)))
1337   {
1338     /* Only connected peers, skip state */
1339     FPRINTF (stdout,
1340              _("Peer `%s': %s %s\n"),
1341              GNUNET_i2s (id),
1342              transport,
1343              addr);
1344   }
1345 }
1346
1347
1348 /**
1349  * Function called with a textual representation of an address.  This
1350  * function will be called several times with different possible
1351  * textual representations, and a last time with @a address being NULL
1352  * to signal the end of the iteration.  Note that @a address NULL
1353  * always is the last call, regardless of the value in @a res.
1354  *
1355  * @param cls closure
1356  * @param address NULL on end of iteration,
1357  *        otherwise 0-terminated printable UTF-8 string,
1358  *        in particular an empty string if @a res is #GNUNET_NO
1359  * @param res result of the address to string conversion:
1360  *        if #GNUNET_OK: conversion successful
1361  *        if #GNUNET_NO: address was invalid (or not supported)
1362  *        if #GNUNET_SYSERR: communication error (IPC error)
1363  */
1364 static void
1365 process_peer_string (void *cls,
1366                      const char *address,
1367                      int res)
1368 {
1369   struct PeerResolutionContext *rc = cls;
1370
1371   if (NULL != address)
1372   {
1373     if (GNUNET_SYSERR == res)
1374     {
1375       FPRINTF (stderr,
1376                "Failed to convert address for peer `%s' plugin `%s' length %u to string \n",
1377                GNUNET_i2s (&rc->id),
1378                rc->addrcp->transport_name,
1379                (unsigned int) rc->addrcp->address_length);
1380       print_info (&rc->id,
1381                   rc->transport,
1382                   NULL,
1383                   rc->state,
1384                   rc->state_timeout);
1385       rc->printed = GNUNET_YES;
1386       return;
1387     }
1388     if (GNUNET_OK == res)
1389     {
1390       print_info (&rc->id,
1391                   rc->transport,
1392                   address,
1393                   rc->state,
1394                   rc->state_timeout);
1395       rc->printed = GNUNET_YES;
1396       return; /* Wait for done call */
1397     }
1398     /* GNUNET_NO == res: ignore, was simply not supported */
1399     return;
1400   }
1401   /* NULL == address, last call, we are done */
1402
1403   GNUNET_assert (address_resolutions > 0);
1404   address_resolutions--;
1405   if (GNUNET_NO == rc->printed)
1406   {
1407     if (numeric == GNUNET_NO)
1408     {
1409       /* Failed to resolve address, try numeric lookup
1410          (note: this should not be needed, as transport
1411          should fallback to numeric conversion if DNS takes
1412          too long) */
1413       resolve_peer_address (&rc->id,
1414                             rc->addrcp,
1415                             GNUNET_YES,
1416                             rc->state,
1417                             rc->state_timeout);
1418     }
1419     else
1420     {
1421       print_info (&rc->id,
1422                   rc->transport,
1423                   NULL,
1424                   rc->state,
1425                   rc->state_timeout);
1426     }
1427   }
1428   GNUNET_free (rc->transport);
1429   GNUNET_free (rc->addrcp);
1430   GNUNET_CONTAINER_DLL_remove (rc_head, rc_tail, rc);
1431   GNUNET_free (rc);
1432   if ((0 == address_resolutions) && (iterate_connections))
1433   {
1434     if (NULL != end)
1435     {
1436       GNUNET_SCHEDULER_cancel (end);
1437       end = NULL;
1438     }
1439     if (NULL != op_timeout)
1440     {
1441       GNUNET_SCHEDULER_cancel (op_timeout);
1442       op_timeout = NULL;
1443     }
1444     ret = 0;
1445     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1446   }
1447 }
1448
1449
1450 static void
1451 resolve_peer_address (const struct GNUNET_PeerIdentity *id,
1452                       const struct GNUNET_HELLO_Address *address,
1453                       int numeric,
1454                       enum GNUNET_TRANSPORT_PeerState state,
1455                       struct GNUNET_TIME_Absolute state_timeout)
1456 {
1457   struct PeerResolutionContext *rc;
1458
1459   rc = GNUNET_new (struct PeerResolutionContext);
1460   GNUNET_assert(NULL != rc);
1461   GNUNET_CONTAINER_DLL_insert(rc_head, rc_tail, rc);
1462   address_resolutions++;
1463
1464   rc->id = (*id);
1465   rc->transport = GNUNET_strdup(address->transport_name);
1466   rc->addrcp = GNUNET_HELLO_address_copy (address);
1467   rc->printed = GNUNET_NO;
1468   rc->state = state;
1469   rc->state_timeout = state_timeout;
1470   /* Resolve address to string */
1471   rc->asc = GNUNET_TRANSPORT_address_to_string (cfg,
1472                                                 address,
1473                                                 numeric,
1474                                                 RESOLUTION_TIMEOUT,
1475                                                 &process_peer_string, rc);
1476 }
1477
1478
1479 /**
1480  * Function called with information about a peers during a one shot iteration
1481  *
1482  * @param cls closure
1483  * @param peer identity of the peer, NULL for final callback when operation done
1484  * @param address binary address used to communicate with this peer,
1485  *  NULL on disconnect or when done
1486  * @param state current state this peer is in
1487  * @param state_timeout time out for the current state
1488  */
1489 static void
1490 process_peer_iteration_cb (void *cls,
1491                            const struct GNUNET_PeerIdentity *peer,
1492                            const struct GNUNET_HELLO_Address *address,
1493                            enum GNUNET_TRANSPORT_PeerState state,
1494                            struct GNUNET_TIME_Absolute state_timeout)
1495 {
1496   if (NULL == peer)
1497   {
1498     /* done */
1499     address_resolution_in_progress = GNUNET_NO;
1500     pic = NULL;
1501     if (NULL != end)
1502       GNUNET_SCHEDULER_cancel (end);
1503     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1504     return;
1505   }
1506
1507   if ( (GNUNET_NO == iterate_all) &&
1508        (GNUNET_NO == GNUNET_TRANSPORT_is_connected(state)))
1509       return; /* Display only connected peers */
1510
1511   if (NULL != op_timeout)
1512     GNUNET_SCHEDULER_cancel (op_timeout);
1513   op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1514                                              &operation_timeout,
1515                                              NULL);
1516
1517   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1518               "Received address for peer `%s': %s\n",
1519               GNUNET_i2s (peer),
1520               address->transport_name);
1521
1522   if (NULL != address)
1523     resolve_peer_address (peer, address, numeric, state, state_timeout);
1524   else
1525     print_info (peer, NULL, NULL, state, state_timeout);
1526 }
1527
1528
1529 /**
1530  * Context for address resolution by #plugin_monitoring_cb().
1531  */
1532 struct PluginMonitorAddress
1533 {
1534
1535   /**
1536    * Ongoing resolution request.
1537    */
1538   struct GNUNET_TRANSPORT_AddressToStringContext *asc;
1539
1540   /**
1541    * Resolved address as string.
1542    */
1543   char *str;
1544 };
1545
1546
1547 /**
1548  * Function called with a textual representation of an address.  This
1549  * function will be called several times with different possible
1550  * textual representations, and a last time with @a address being NULL
1551  * to signal the end of the iteration.  Note that @a address NULL
1552  * always is the last call, regardless of the value in @a res.
1553  *
1554  * @param cls closure
1555  * @param address NULL on end of iteration,
1556  *        otherwise 0-terminated printable UTF-8 string,
1557  *        in particular an empty string if @a res is #GNUNET_NO
1558  * @param res result of the address to string conversion:
1559  *        if #GNUNET_OK: conversion successful
1560  *        if #GNUNET_NO: address was invalid (or not supported)
1561  *        if #GNUNET_SYSERR: communication error (IPC error)
1562  */
1563 static void
1564 address_cb (void *cls,
1565             const char *address,
1566             int res)
1567 {
1568   struct PluginMonitorAddress *addr = cls;
1569
1570   if (NULL == address)
1571   {
1572     addr->asc = NULL;
1573     return;
1574   }
1575   if (NULL != addr->str)
1576     return;
1577   addr->str = GNUNET_strdup (address);
1578 }
1579
1580
1581 /**
1582  * Function called by the plugin with information about the
1583  * current sessions managed by the plugin (for monitoring).
1584  *
1585  * @param cls closure (NULL)
1586  * @param session session handle this information is about,
1587  *        NULL to indicate that we are "in sync" (initial
1588  *        iteration complete)
1589  * @param session_ctx storage location where the application
1590  *        can store data; will point to NULL on #GNUNET_TRANSPORT_SS_INIT,
1591  *        and must be reset to NULL on #GNUNET_TRANSPORT_SS_DONE
1592  * @param info information about the state of the session,
1593  *        NULL if @a session is also NULL and we are
1594  *        merely signalling that the initial iteration is over;
1595  *        NULL with @a session being non-NULL if the monitor
1596  *        was being cancelled while sessions were active
1597  */
1598 static void
1599 plugin_monitoring_cb (void *cls,
1600                       struct GNUNET_TRANSPORT_PluginSession *session,
1601                       void **session_ctx,
1602                       const struct GNUNET_TRANSPORT_SessionInfo *info)
1603 {
1604   const char *state;
1605   struct PluginMonitorAddress *addr;
1606
1607   if ( (NULL == info) &&
1608        (NULL == session) )
1609     return; /* in sync with transport service */
1610   addr = *session_ctx;
1611   if (NULL == info)
1612   {
1613     if (NULL != addr)
1614     {
1615       if (NULL != addr->asc)
1616       {
1617         GNUNET_TRANSPORT_address_to_string_cancel (addr->asc);
1618         addr->asc = NULL;
1619       }
1620       GNUNET_free_non_null (addr->str);
1621       GNUNET_free (addr);
1622       *session_ctx = NULL;
1623     }
1624     return; /* shutdown */
1625   }
1626   if ( (NULL != cpid) &&
1627        (0 != memcmp (&info->address->peer,
1628                      cpid,
1629                      sizeof (struct GNUNET_PeerIdentity))) )
1630     return; /* filtered */
1631   if (NULL == addr)
1632   {
1633     addr = GNUNET_new (struct PluginMonitorAddress);
1634     addr->asc = GNUNET_TRANSPORT_address_to_string (cfg,
1635                                                     info->address,
1636                                                     GNUNET_NO,
1637                                                     GNUNET_TIME_UNIT_FOREVER_REL,
1638                                                     &address_cb,
1639                                                     addr);
1640     *session_ctx = addr;
1641   }
1642   switch (info->state)
1643   {
1644   case GNUNET_TRANSPORT_SS_INIT:
1645     state = "INIT";
1646     break;
1647   case GNUNET_TRANSPORT_SS_HANDSHAKE:
1648     state = "HANDSHAKE";
1649     break;
1650   case GNUNET_TRANSPORT_SS_UP:
1651     state = "UP";
1652     break;
1653   case GNUNET_TRANSPORT_SS_UPDATE:
1654     state = "UPDATE";
1655     break;
1656   case GNUNET_TRANSPORT_SS_DONE:
1657     state = "DONE";
1658     break;
1659   default:
1660     state = "UNKNOWN";
1661     break;
1662   }
1663   fprintf (stdout,
1664            "%s: %s %s (# %u/%u b) blocked until %s timeout in %s [%s]\n",
1665            GNUNET_i2s (&info->address->peer),
1666            addr->str,
1667            (info->is_inbound == GNUNET_YES) ? "<-" : ((info->is_inbound == GNUNET_NO) ? "->" : "<>"),
1668            info->num_msg_pending,
1669            info->num_bytes_pending,
1670            GNUNET_STRINGS_absolute_time_to_string (info->receive_delay),
1671            GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (info->session_timeout),
1672                                                 GNUNET_YES),
1673            state);
1674   if (GNUNET_TRANSPORT_SS_DONE == info->state)
1675   {
1676     if (NULL != addr->asc)
1677     {
1678       GNUNET_TRANSPORT_address_to_string_cancel (addr->asc);
1679       addr->asc = NULL;
1680     }
1681     GNUNET_free_non_null (addr->str);
1682     GNUNET_free (addr);
1683     *session_ctx = NULL;
1684   }
1685 }
1686
1687
1688 /**
1689  * Function called with information about a peers
1690  *
1691  * @param cls closure
1692  * @param peer identity of the peer, NULL for final callback when operation done
1693  * @param address binary address used to communicate with this peer,
1694  *  NULL on disconnect or when done
1695  * @param state current state this peer is in
1696  * @param state_timeout time out for the current state
1697  *
1698  */
1699 static void
1700 process_peer_monitoring_cb (void *cls,
1701                             const struct GNUNET_PeerIdentity *peer,
1702                             const struct GNUNET_HELLO_Address *address,
1703                             enum GNUNET_TRANSPORT_PeerState state,
1704                             struct GNUNET_TIME_Absolute state_timeout)
1705 {
1706   struct MonitoredPeer *m;
1707
1708   if (NULL == peer)
1709   {
1710     FPRINTF (stdout,
1711              "%s",
1712              _("Monitor disconnected from transport service. Reconnecting.\n"));
1713     return;
1714   }
1715
1716   if (NULL != op_timeout)
1717     GNUNET_SCHEDULER_cancel (op_timeout);
1718   op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1719                                              &operation_timeout,
1720                                              NULL);
1721
1722   if (NULL == (m = GNUNET_CONTAINER_multipeermap_get (monitored_peers, peer)))
1723   {
1724     m = GNUNET_new (struct MonitoredPeer);
1725     GNUNET_CONTAINER_multipeermap_put (monitored_peers, peer,
1726         m, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1727   }
1728   else
1729   {
1730     if ( (m->state == state) &&
1731       (m->state_timeout.abs_value_us == state_timeout.abs_value_us) &&
1732       ((NULL == address) && (NULL == m->address)))
1733     {
1734       return; /* No real change */
1735     }
1736     if ( (m->state == state) && ((NULL != address) && (NULL != m->address)) &&
1737         (0 == GNUNET_HELLO_address_cmp(m->address, address)))
1738       return; /* No real change */
1739   }
1740
1741   if (NULL != m->address)
1742   {
1743     GNUNET_free (m->address);
1744     m->address = NULL;
1745   }
1746   if (NULL != address)
1747     m->address = GNUNET_HELLO_address_copy (address);
1748   m->state = state;
1749   m->state_timeout = state_timeout;
1750
1751   if (NULL != address)
1752     resolve_peer_address (peer,
1753                           m->address,
1754                           numeric,
1755                           m->state,
1756                           m->state_timeout);
1757   else
1758     print_info (peer,
1759                 NULL,
1760                 NULL,
1761                 m->state,
1762                 m->state_timeout);
1763 }
1764
1765
1766 /**
1767  * Function called with our result of trying to connect to a peer
1768  * using the transport service. Will retry 10 times, and if we still
1769  * fail to connect terminate with an error message.
1770  *
1771  * @param cls NULL
1772  * @param result #GNUNET_OK if we connected to the service
1773  */
1774 static void
1775 try_connect_cb (void *cls,
1776                 const int result)
1777 {
1778   static int retries = 0;
1779
1780   tc_handle = NULL;
1781   if (GNUNET_OK == result)
1782     return;
1783   retries++;
1784   if (retries < 10)
1785   {
1786     tc_handle = GNUNET_TRANSPORT_try_connect (handle,
1787                                               &pid,
1788                                               &try_connect_cb,
1789                                               NULL);
1790     return;
1791   }
1792   FPRINTF (stderr,
1793            "%s",
1794            _("Failed to send connect request to transport service\n"));
1795   if (NULL != end)
1796     GNUNET_SCHEDULER_cancel (end);
1797   ret = 1;
1798   end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1799 }
1800
1801
1802 /**
1803  * Function called with our result of trying to disconnect a peer
1804  * using the transport service. Will retry 10 times, and if we still
1805  * fail to disconnect, terminate with an error message.
1806  *
1807  * @param cls NULL
1808  * @param result #GNUNET_OK if we connected to the service
1809  */
1810 static void
1811 try_disconnect_cb (void *cls,
1812                    const int result)
1813 {
1814   static int retries = 0;
1815
1816   td_handle = NULL;
1817   if (GNUNET_OK == result)
1818     return;
1819   retries++;
1820   if (retries < 10)
1821   {
1822     td_handle = GNUNET_TRANSPORT_try_disconnect (handle,
1823                                                  &pid,
1824                                                  &try_disconnect_cb,
1825                                                  NULL);
1826     return;
1827   }
1828   FPRINTF (stderr, "%s",
1829            _("Failed to send disconnect request to transport service\n"));
1830   if (NULL != end)
1831     GNUNET_SCHEDULER_cancel (end);
1832   ret = 1;
1833   end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1834 }
1835
1836
1837 /**
1838  * Function called with the result of the check if the 'transport'
1839  * service is running.
1840  *
1841  * @param cls closure with our configuration
1842  * @param result #GNUNET_YES if transport is running
1843  */
1844 static void
1845 testservice_task (void *cls,
1846                   int result)
1847 {
1848   int counter = 0;
1849   ret = 1;
1850
1851   if (GNUNET_YES != result)
1852   {
1853     FPRINTF (stderr, _("Service `%s' is not running\n"), "transport");
1854     return;
1855   }
1856
1857   if ((NULL != cpid)
1858       && (GNUNET_OK
1859           != GNUNET_CRYPTO_eddsa_public_key_from_string (cpid, strlen (cpid),
1860               &pid.public_key)))
1861   {
1862     FPRINTF (stderr, _("Failed to parse peer identity `%s'\n"), cpid);
1863     return;
1864   }
1865
1866   counter = benchmark_send + benchmark_receive + iterate_connections
1867       + monitor_connections + monitor_connects + try_connect + try_disconnect +
1868       + iterate_validation + monitor_validation + monitor_plugins;
1869
1870   if (1 < counter)
1871   {
1872     FPRINTF (stderr,
1873         _("Multiple operations given. Please choose only one operation: %s, %s, %s, %s, %s, %s %s\n"),
1874         "connect", "benchmark send", "benchmark receive", "information",
1875              "monitor", "events", "plugins");
1876     return;
1877   }
1878   if (0 == counter)
1879   {
1880     FPRINTF (stderr,
1881         _("No operation given. Please choose one operation: %s, %s, %s, %s, %s, %s, %s\n"),
1882         "connect", "benchmark send", "benchmark receive", "information",
1883              "monitor", "events", "plugins");
1884     return;
1885   }
1886
1887   if (try_connect) /* -C: Connect to peer */
1888   {
1889     if (NULL == cpid)
1890     {
1891       FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
1892           "-C", "-p");
1893       ret = 1;
1894       return;
1895     }
1896     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, &notify_receive,
1897         &notify_connect, &notify_disconnect);
1898     if (NULL == handle)
1899     {
1900       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n"));
1901       ret = 1;
1902       return;
1903     }
1904     tc_handle = GNUNET_TRANSPORT_try_connect (handle, &pid, try_connect_cb,
1905         NULL);
1906     if (NULL == tc_handle)
1907     {
1908       FPRINTF (stderr, "%s",
1909           _("Failed to send request to transport service\n"));
1910       ret = 1;
1911       return;
1912     }
1913     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1914         NULL);
1915
1916   }
1917   else if (try_disconnect) /* -D: Disconnect from peer */
1918   {
1919     if (NULL == cpid)
1920     {
1921       FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
1922           "-D", "-p");
1923       ret = 1;
1924       return;
1925     }
1926     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, &notify_receive,
1927         &notify_connect, &notify_disconnect);
1928     if (NULL == handle)
1929     {
1930       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n"));
1931       ret = 1;
1932       return;
1933     }
1934     td_handle = GNUNET_TRANSPORT_try_disconnect (handle, &pid,
1935                                                  &try_disconnect_cb,
1936                                                  NULL);
1937     if (NULL == td_handle)
1938     {
1939       FPRINTF (stderr, "%s",
1940           _("Failed to send request to transport service\n"));
1941       ret = 1;
1942       return;
1943     }
1944     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1945         NULL);
1946
1947   }
1948   else if (benchmark_send) /* -s: Benchmark sending */
1949   {
1950     if (NULL == cpid)
1951     {
1952       FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
1953           "-s", "-p");
1954       ret = 1;
1955       return;
1956     }
1957     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL,
1958                                        &notify_receive,
1959                                        &notify_connect,
1960                                        &notify_disconnect);
1961     if (NULL == handle)
1962     {
1963       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n"));
1964       ret = 1;
1965       return;
1966     }
1967     tc_handle = GNUNET_TRANSPORT_try_connect (handle,
1968                                               &pid,
1969                                               &try_connect_cb,
1970                                               NULL);
1971     if (NULL == tc_handle)
1972     {
1973       FPRINTF (stderr, "%s",
1974           _("Failed to send request to transport service\n"));
1975       ret = 1;
1976       return;
1977     }
1978     start_time = GNUNET_TIME_absolute_get ();
1979     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1980                                                &operation_timeout,
1981                                                NULL);
1982   }
1983   else if (benchmark_receive) /* -b: Benchmark receiving */
1984   {
1985     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, &notify_receive, NULL,
1986         NULL);
1987     if (NULL == handle)
1988     {
1989       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n"));
1990       ret = 1;
1991       return;
1992     }
1993     if (verbosity > 0)
1994       FPRINTF (stdout, "%s", _("Starting to receive benchmark data\n"));
1995     start_time = GNUNET_TIME_absolute_get ();
1996
1997   }
1998   else if (iterate_connections) /* -i: List information about peers once */
1999   {
2000     address_resolution_in_progress = GNUNET_YES;
2001     pic = GNUNET_TRANSPORT_monitor_peers (cfg, (NULL == cpid) ? NULL : &pid,
2002         GNUNET_YES, TIMEOUT, &process_peer_iteration_cb, (void *) cfg);
2003     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
2004         NULL);
2005   }
2006   else if (monitor_connections) /* -m: List information about peers continuously */
2007   {
2008     monitored_peers = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
2009     address_resolution_in_progress = GNUNET_YES;
2010     pic = GNUNET_TRANSPORT_monitor_peers (cfg, (NULL == cpid) ? NULL : &pid,
2011                                           GNUNET_NO, TIMEOUT,
2012                                           &process_peer_monitoring_cb, (void *) cfg);
2013   }
2014   else if (monitor_plugins) /* -P: List information about plugins continuously */
2015   {
2016     monitored_plugins = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
2017     pm = GNUNET_TRANSPORT_monitor_plugins (cfg,
2018                                            &plugin_monitoring_cb,
2019                                            NULL);
2020   }
2021   else if (iterate_validation) /* -d: Print information about validations */
2022   {
2023     vic = GNUNET_TRANSPORT_monitor_validation_entries (cfg,
2024                                                        (NULL == cpid) ? NULL : &pid,
2025                                                        GNUNET_YES, TIMEOUT,
2026                                                        &process_validation_cb, (void *) cfg);
2027   }
2028   else if (monitor_validation) /* -f: Print information about validations continuously */
2029   {
2030     vic = GNUNET_TRANSPORT_monitor_validation_entries (cfg,
2031                                                        (NULL == cpid) ? NULL : &pid,
2032                                                        GNUNET_NO, TIMEOUT,
2033                                                        &process_validation_cb, (void *) cfg);
2034   }
2035   else if (monitor_connects) /* -e : Monitor (dis)connect events continuously */
2036   {
2037     monitor_connect_counter = 0;
2038     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, NULL,
2039                                        &monitor_notify_connect,
2040                                        &monitor_notify_disconnect);
2041     if (NULL == handle)
2042     {
2043       FPRINTF (stderr,
2044                "%s",
2045                _("Failed to connect to transport service\n"));
2046       ret = 1;
2047       return;
2048     }
2049     ret = 0;
2050   }
2051   else
2052   {
2053     GNUNET_break(0);
2054     return;
2055   }
2056
2057   end = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2058                                       &shutdown_task,
2059                                       NULL);
2060 }
2061
2062
2063 /**
2064  * Main function that will be run by the scheduler.
2065  *
2066  * @param cls closure
2067  * @param args remaining command-line arguments
2068  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
2069  * @param mycfg configuration
2070  */
2071 static void
2072 run (void *cls,
2073      char * const *args,
2074      const char *cfgfile,
2075      const struct GNUNET_CONFIGURATION_Handle *mycfg)
2076 {
2077   cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
2078   if (test_configuration)
2079   {
2080     do_test_configuration (cfg);
2081     return;
2082   }
2083   GNUNET_CLIENT_service_test ("transport", cfg, GNUNET_TIME_UNIT_SECONDS,
2084       &testservice_task, (void *) cfg);
2085 }
2086
2087 int
2088 main (int argc, char * const *argv)
2089 {
2090   int res;
2091   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
2092     { 'a', "all", NULL,
2093       gettext_noop ("print information for all peers (instead of only connected peers)"),
2094       0, &GNUNET_GETOPT_set_one, &iterate_all },
2095     { 'b', "benchmark", NULL,
2096       gettext_noop ("measure how fast we are receiving data from all peers (until CTRL-C)"),
2097       0, &GNUNET_GETOPT_set_one, &benchmark_receive },
2098     { 'C', "connect",
2099       NULL, gettext_noop ("connect to a peer"), 0,
2100       &GNUNET_GETOPT_set_one, &try_connect },
2101     { 'D', "disconnect",
2102       NULL, gettext_noop ("disconnect to a peer"), 0,
2103       &GNUNET_GETOPT_set_one, &try_disconnect },
2104     { 'd', "validation", NULL,
2105       gettext_noop ("print information for all pending validations "),
2106       0, &GNUNET_GETOPT_set_one, &iterate_validation },
2107     { 'f', "monitorvalidation", NULL,
2108       gettext_noop ("print information for all pending validations continuously"),
2109       0, &GNUNET_GETOPT_set_one, &monitor_validation },
2110     { 'i', "information", NULL,
2111       gettext_noop ("provide information about all current connections (once)"),
2112       0, &GNUNET_GETOPT_set_one, &iterate_connections },
2113     { 'm', "monitor", NULL,
2114       gettext_noop ("provide information about all current connections (continuously)"),
2115       0, &GNUNET_GETOPT_set_one, &monitor_connections },
2116     { 'e', "events", NULL,
2117       gettext_noop ("provide information about all connects and disconnect events (continuously)"),
2118       0, &GNUNET_GETOPT_set_one, &monitor_connects },
2119     { 'n', "numeric",
2120       NULL, gettext_noop ("do not resolve hostnames"), 0,
2121       &GNUNET_GETOPT_set_one, &numeric },
2122     { 'p', "peer", "PEER",
2123       gettext_noop ("peer identity"), 1, &GNUNET_GETOPT_set_string,
2124       &cpid },
2125     { 'P', "plugins", NULL,
2126       gettext_noop ("monitor plugin sessions"), 0, &GNUNET_GETOPT_set_one,
2127       &monitor_plugins },
2128     { 's', "send", NULL, gettext_noop
2129       ("send data for benchmarking to the other peer (until CTRL-C)"), 0,
2130       &GNUNET_GETOPT_set_one, &benchmark_send },
2131     { 't', "test", NULL,
2132       gettext_noop ("test transport configuration (involves external server)"),
2133       0, &GNUNET_GETOPT_set_one, &test_configuration },
2134     GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
2135     GNUNET_GETOPT_OPTION_END
2136   };
2137
2138   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
2139     return 2;
2140
2141   res = GNUNET_PROGRAM_run (argc, argv,
2142                             "gnunet-transport",
2143                             gettext_noop ("Direct access to transport service."),
2144                             options,
2145                             &run, NULL);
2146   GNUNET_free((void *) argv);
2147   if (GNUNET_OK == res)
2148     return ret;
2149   return 1;
2150 }
2151
2152 /* end of gnunet-transport.c */