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