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