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