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