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