-fix compiler warning
[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  * @return #GNUNET_OK
942  */
943 static int
944 check_dummy (void *cls,
945              const struct GNUNET_MessageHeader *message)
946 {
947   return GNUNET_OK; /* all messages are fine */
948 }
949
950
951 /**
952  * Function called by the transport for each received message.
953  *
954  * @param cls closure
955  * @param message the message
956  */
957 static void
958 handle_dummy (void *cls,
959               const struct GNUNET_MessageHeader *message)
960 {
961   if (! benchmark_receive)
962     return;
963   if (verbosity > 0)
964     FPRINTF (stdout,
965              _("Received %u bytes\n"),
966              (unsigned int) ntohs (message->size));
967   if (0 == traffic_received)
968     start_time = GNUNET_TIME_absolute_get ();
969   traffic_received += ntohs (message->size);
970 }
971
972
973 /**
974  * Convert address to a printable format.
975  *
976  * @param address the address
977  * @param numeric #GNUNET_YES to convert to numeric format, #GNUNET_NO
978  *                to try to use reverse DNS
979  * @param state state the peer is in
980  * @param state_timeout when will the peer's state expire
981  */
982 static void
983 resolve_peer_address (const struct GNUNET_HELLO_Address *address,
984                       int numeric,
985                       enum GNUNET_TRANSPORT_PeerState state,
986                       struct GNUNET_TIME_Absolute state_timeout);
987
988
989 static void
990 print_info (const struct GNUNET_PeerIdentity *id,
991             const char *transport,
992             const char *addr,
993             enum GNUNET_TRANSPORT_PeerState state,
994             struct GNUNET_TIME_Absolute state_timeout)
995 {
996
997   if ( ((GNUNET_YES == iterate_connections) &&
998         (GNUNET_YES == iterate_all)) ||
999        (GNUNET_YES == monitor_connections))
1000   {
1001     FPRINTF (stdout,
1002              _("Peer `%s': %s %s in state `%s' until %s\n"),
1003              GNUNET_i2s (id),
1004              (NULL == transport) ? "<none>" : transport,
1005              (NULL == transport) ? "<none>" : addr,
1006              GNUNET_TRANSPORT_ps2s (state),
1007              GNUNET_STRINGS_absolute_time_to_string (state_timeout));
1008   }
1009   else if ( (GNUNET_YES == iterate_connections) &&
1010             (GNUNET_TRANSPORT_is_connected(state)) ) 
1011   {
1012     /* Only connected peers, skip state */
1013     FPRINTF (stdout,
1014              _("Peer `%s': %s %s\n"),
1015              GNUNET_i2s (id),
1016              transport,
1017              addr);
1018   }
1019 }
1020
1021
1022 /**
1023  * Function called with a textual representation of an address.  This
1024  * function will be called several times with different possible
1025  * textual representations, and a last time with @a address being NULL
1026  * to signal the end of the iteration.  Note that @a address NULL
1027  * always is the last call, regardless of the value in @a res.
1028  *
1029  * @param cls closure
1030  * @param address NULL on end of iteration,
1031  *        otherwise 0-terminated printable UTF-8 string,
1032  *        in particular an empty string if @a res is #GNUNET_NO
1033  * @param res result of the address to string conversion:
1034  *        if #GNUNET_OK: conversion successful
1035  *        if #GNUNET_NO: address was invalid (or not supported)
1036  *        if #GNUNET_SYSERR: communication error (IPC error)
1037  */
1038 static void
1039 process_peer_string (void *cls,
1040                      const char *address,
1041                      int res)
1042 {
1043   struct PeerResolutionContext *rc = cls;
1044
1045   if (NULL != address)
1046   {
1047     if (GNUNET_SYSERR == res)
1048     {
1049       FPRINTF (stderr,
1050                "Failed to convert address for peer `%s' plugin `%s' length %u to string \n",
1051                GNUNET_i2s (&rc->addrcp->peer),
1052                rc->addrcp->transport_name,
1053                (unsigned int) rc->addrcp->address_length);
1054       print_info (&rc->addrcp->peer,
1055                   rc->transport,
1056                   NULL,
1057                   rc->state,
1058                   rc->state_timeout);
1059       rc->printed = GNUNET_YES;
1060       return;
1061     }
1062     if (GNUNET_OK == res)
1063     {
1064       print_info (&rc->addrcp->peer,
1065                   rc->transport,
1066                   address,
1067                   rc->state,
1068                   rc->state_timeout);
1069       rc->printed = GNUNET_YES;
1070       return; /* Wait for done call */
1071     }
1072     /* GNUNET_NO == res: ignore, was simply not supported */
1073     return;
1074   }
1075   /* NULL == address, last call, we are done */
1076
1077   rc->asc = NULL;
1078   GNUNET_assert (address_resolutions > 0);
1079   address_resolutions--;
1080   if (GNUNET_NO == rc->printed)
1081   {
1082     if (numeric == GNUNET_NO)
1083     {
1084       /* Failed to resolve address, try numeric lookup
1085          (note: this should not be needed, as transport
1086          should fallback to numeric conversion if DNS takes
1087          too long) */
1088       resolve_peer_address (rc->addrcp,
1089                             GNUNET_YES,
1090                             rc->state,
1091                             rc->state_timeout);
1092     }
1093     else
1094     {
1095       print_info (&rc->addrcp->peer,
1096                   rc->transport,
1097                   NULL,
1098                   rc->state,
1099                   rc->state_timeout);
1100     }
1101   }
1102   GNUNET_free (rc->transport);
1103   GNUNET_free (rc->addrcp);
1104   GNUNET_CONTAINER_DLL_remove (rc_head, rc_tail, rc);
1105   GNUNET_free (rc);
1106   if ((0 == address_resolutions) && (iterate_connections))
1107   {
1108     if (NULL != op_timeout)
1109     {
1110       GNUNET_SCHEDULER_cancel (op_timeout);
1111       op_timeout = NULL;
1112     }
1113     ret = 0;
1114     GNUNET_SCHEDULER_shutdown ();
1115   }
1116 }
1117
1118
1119 /**
1120  * Convert address to a printable format and print it
1121  * together with the given state data.
1122  *
1123  * @param address the address
1124  * @param numeric #GNUNET_YES to convert to numeric format, #GNUNET_NO
1125  *                to try to use reverse DNS
1126  * @param state state the peer is in
1127  * @param state_timeout when will the peer's state expire
1128  */
1129 static void
1130 resolve_peer_address (const struct GNUNET_HELLO_Address *address,
1131                       int numeric,
1132                       enum GNUNET_TRANSPORT_PeerState state,
1133                       struct GNUNET_TIME_Absolute state_timeout)
1134 {
1135   struct PeerResolutionContext *rc;
1136
1137   rc = GNUNET_new (struct PeerResolutionContext);
1138   GNUNET_CONTAINER_DLL_insert (rc_head,
1139                                rc_tail,
1140                                rc);
1141   address_resolutions++;
1142   rc->transport = GNUNET_strdup (address->transport_name);
1143   rc->addrcp = GNUNET_HELLO_address_copy (address);
1144   rc->printed = GNUNET_NO;
1145   rc->state = state;
1146   rc->state_timeout = state_timeout;
1147   /* Resolve address to string */
1148   rc->asc = GNUNET_TRANSPORT_address_to_string (cfg,
1149                                                 address,
1150                                                 numeric,
1151                                                 RESOLUTION_TIMEOUT,
1152                                                 &process_peer_string,
1153                                                 rc);
1154 }
1155
1156
1157 /**
1158  * Function called with information about a peers during a one shot iteration
1159  *
1160  * @param cls closure
1161  * @param peer identity of the peer, NULL for final callback when operation done
1162  * @param address binary address used to communicate with this peer,
1163  *  NULL on disconnect or when done
1164  * @param state current state this peer is in
1165  * @param state_timeout time out for the current state
1166  */
1167 static void
1168 process_peer_iteration_cb (void *cls,
1169                            const struct GNUNET_PeerIdentity *peer,
1170                            const struct GNUNET_HELLO_Address *address,
1171                            enum GNUNET_TRANSPORT_PeerState state,
1172                            struct GNUNET_TIME_Absolute state_timeout)
1173 {
1174   if (NULL == peer)
1175   {
1176     /* done */
1177     pic = NULL;
1178     return;
1179   }
1180
1181   if ( (GNUNET_NO == iterate_all) &&
1182        (GNUNET_NO == GNUNET_TRANSPORT_is_connected(state)))
1183       return; /* Display only connected peers */
1184
1185   if (NULL != op_timeout)
1186     GNUNET_SCHEDULER_cancel (op_timeout);
1187   op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1188                                              &operation_timeout,
1189                                              NULL);
1190
1191   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1192               "Received address for peer `%s': %s\n",
1193               GNUNET_i2s (peer),
1194               address ? address->transport_name : "");
1195
1196   if (NULL != address)
1197     resolve_peer_address (address,
1198                           numeric,
1199                           state,
1200                           state_timeout);
1201   else
1202     print_info (peer,
1203                 NULL,
1204                 NULL,
1205                 state,
1206                 state_timeout);
1207 }
1208
1209
1210 /**
1211  * Context for address resolution by #plugin_monitoring_cb().
1212  */
1213 struct PluginMonitorAddress
1214 {
1215
1216   /**
1217    * Ongoing resolution request.
1218    */
1219   struct GNUNET_TRANSPORT_AddressToStringContext *asc;
1220
1221   /**
1222    * Resolved address as string.
1223    */
1224   char *str;
1225
1226   /**
1227    * Last event we got and did not yet print because
1228    * @e str was NULL (address not yet resolved).
1229    */
1230   struct GNUNET_TRANSPORT_SessionInfo si;
1231 };
1232
1233
1234 /**
1235  * Print information about a plugin monitoring event.
1236  *
1237  * @param addr out internal context
1238  * @param info the monitoring information
1239  */
1240 static void
1241 print_plugin_event_info (struct PluginMonitorAddress *addr,
1242                          const struct GNUNET_TRANSPORT_SessionInfo *info)
1243 {
1244   const char *state;
1245
1246   switch (info->state)
1247   {
1248   case GNUNET_TRANSPORT_SS_INIT:
1249     state = "INIT";
1250     break;
1251   case GNUNET_TRANSPORT_SS_HANDSHAKE:
1252     state = "HANDSHAKE";
1253     break;
1254   case GNUNET_TRANSPORT_SS_UP:
1255     state = "UP";
1256     break;
1257   case GNUNET_TRANSPORT_SS_UPDATE:
1258     state = "UPDATE";
1259     break;
1260   case GNUNET_TRANSPORT_SS_DONE:
1261     state = "DONE";
1262     break;
1263   default:
1264     state = "UNKNOWN";
1265     break;
1266   }
1267   fprintf (stdout,
1268            "%s: state %s timeout in %s @ %s%s\n",
1269            GNUNET_i2s (&info->address->peer),
1270            state,
1271            GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (info->session_timeout),
1272                                                    GNUNET_YES),
1273            addr->str,
1274            (info->is_inbound == GNUNET_YES) ? " (INBOUND)" : "");
1275   fprintf (stdout,
1276            "%s: queue has %3u messages and %6u bytes\n",
1277            GNUNET_i2s (&info->address->peer),
1278            info->num_msg_pending,
1279            info->num_bytes_pending);
1280   if (0 != GNUNET_TIME_absolute_get_remaining (info->receive_delay).rel_value_us)
1281     fprintf (stdout,
1282              "%s: receiving blocked until %s\n",
1283              GNUNET_i2s (&info->address->peer),
1284              GNUNET_STRINGS_absolute_time_to_string (info->receive_delay));
1285 }
1286
1287
1288 /**
1289  * Function called with a textual representation of an address.  This
1290  * function will be called several times with different possible
1291  * textual representations, and a last time with @a address being NULL
1292  * to signal the end of the iteration.  Note that @a address NULL
1293  * always is the last call, regardless of the value in @a res.
1294  *
1295  * @param cls closure
1296  * @param address NULL on end of iteration,
1297  *        otherwise 0-terminated printable UTF-8 string,
1298  *        in particular an empty string if @a res is #GNUNET_NO
1299  * @param res result of the address to string conversion:
1300  *        if #GNUNET_OK: conversion successful
1301  *        if #GNUNET_NO: address was invalid (or not supported)
1302  *        if #GNUNET_SYSERR: communication error (IPC error)
1303  */
1304 static void
1305 address_cb (void *cls,
1306             const char *address,
1307             int res)
1308 {
1309   struct PluginMonitorAddress *addr = cls;
1310
1311   if (NULL == address)
1312   {
1313     addr->asc = NULL;
1314     return;
1315   }
1316   if (NULL != addr->str)
1317     return;
1318   addr->str = GNUNET_strdup (address);
1319   print_plugin_event_info (addr,
1320                            &addr->si);
1321 }
1322
1323
1324 /**
1325  * Function called by the plugin with information about the
1326  * current sessions managed by the plugin (for monitoring).
1327  *
1328  * @param cls closure (NULL)
1329  * @param session session handle this information is about,
1330  *        NULL to indicate that we are "in sync" (initial
1331  *        iteration complete)
1332  * @param session_ctx storage location where the application
1333  *        can store data; will point to NULL on #GNUNET_TRANSPORT_SS_INIT,
1334  *        and must be reset to NULL on #GNUNET_TRANSPORT_SS_DONE
1335  * @param info information about the state of the session,
1336  *        NULL if @a session is also NULL and we are
1337  *        merely signalling that the initial iteration is over;
1338  *        NULL with @a session being non-NULL if the monitor
1339  *        was being cancelled while sessions were active
1340  */
1341 static void
1342 plugin_monitoring_cb (void *cls,
1343                       struct GNUNET_TRANSPORT_PluginSession *session,
1344                       void **session_ctx,
1345                       const struct GNUNET_TRANSPORT_SessionInfo *info)
1346 {
1347   struct PluginMonitorAddress *addr;
1348
1349   if ( (NULL == info) &&
1350        (NULL == session) )
1351     return; /* in sync with transport service */
1352   addr = *session_ctx;
1353   if (NULL == info)
1354   {
1355     if (NULL != addr)
1356     {
1357       if (NULL != addr->asc)
1358       {
1359         GNUNET_TRANSPORT_address_to_string_cancel (addr->asc);
1360         addr->asc = NULL;
1361       }
1362       GNUNET_free_non_null (addr->str);
1363       GNUNET_free (addr);
1364       *session_ctx = NULL;
1365     }
1366     return; /* shutdown */
1367   }
1368   if ( (NULL != cpid) &&
1369        (0 != memcmp (&info->address->peer,
1370                      cpid,
1371                      sizeof (struct GNUNET_PeerIdentity))) )
1372     return; /* filtered */
1373   if (NULL == addr)
1374   {
1375     addr = GNUNET_new (struct PluginMonitorAddress);
1376     addr->asc = GNUNET_TRANSPORT_address_to_string (cfg,
1377                                                     info->address,
1378                                                     numeric,
1379                                                     GNUNET_TIME_UNIT_FOREVER_REL,
1380                                                     &address_cb,
1381                                                     addr);
1382     *session_ctx = addr;
1383   }
1384   if (NULL == addr->str)
1385     addr->si = *info;
1386   else
1387     print_plugin_event_info (addr,
1388                              info);
1389   if (GNUNET_TRANSPORT_SS_DONE == info->state)
1390   {
1391     if (NULL != addr->asc)
1392     {
1393       GNUNET_TRANSPORT_address_to_string_cancel (addr->asc);
1394       addr->asc = NULL;
1395     }
1396     GNUNET_free_non_null (addr->str);
1397     GNUNET_free (addr);
1398     *session_ctx = NULL;
1399   }
1400 }
1401
1402
1403 /**
1404  * Function called with information about a peers
1405  *
1406  * @param cls closure, NULL
1407  * @param peer identity of the peer, NULL for final callback when operation done
1408  * @param address binary address used to communicate with this peer,
1409  *  NULL on disconnect or when done
1410  * @param state current state this peer is in
1411  * @param state_timeout time out for the current state
1412  */
1413 static void
1414 process_peer_monitoring_cb (void *cls,
1415                             const struct GNUNET_PeerIdentity *peer,
1416                             const struct GNUNET_HELLO_Address *address,
1417                             enum GNUNET_TRANSPORT_PeerState state,
1418                             struct GNUNET_TIME_Absolute state_timeout)
1419 {
1420   struct MonitoredPeer *m;
1421
1422   if (NULL == peer)
1423   {
1424     FPRINTF (stdout,
1425              "%s",
1426              _("Monitor disconnected from transport service. Reconnecting.\n"));
1427     return;
1428   }
1429
1430   if (NULL != op_timeout)
1431     GNUNET_SCHEDULER_cancel (op_timeout);
1432   op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1433                                              &operation_timeout,
1434                                              NULL);
1435
1436   if (NULL == (m = GNUNET_CONTAINER_multipeermap_get (monitored_peers,
1437                                                       peer)))
1438   {
1439     m = GNUNET_new (struct MonitoredPeer);
1440     GNUNET_CONTAINER_multipeermap_put (monitored_peers,
1441                                        peer,
1442                                        m,
1443                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1444   }
1445   else
1446   {
1447     if ( (m->state == state) &&
1448          (m->state_timeout.abs_value_us == state_timeout.abs_value_us) &&
1449          (NULL == address) &&
1450          (NULL == m->address) )
1451     {
1452       return; /* No real change */
1453     }
1454     if ( (m->state == state) &&
1455          (NULL != address) &&
1456          (NULL != m->address) &&
1457          (0 == GNUNET_HELLO_address_cmp(m->address, address)) )
1458       return; /* No real change */
1459   }
1460
1461   if (NULL != m->address)
1462   {
1463     GNUNET_free (m->address);
1464     m->address = NULL;
1465   }
1466   if (NULL != address)
1467     m->address = GNUNET_HELLO_address_copy (address);
1468   m->state = state;
1469   m->state_timeout = state_timeout;
1470
1471   if (NULL != address)
1472     resolve_peer_address (m->address,
1473                           numeric,
1474                           m->state,
1475                           m->state_timeout);
1476   else
1477     print_info (peer,
1478                 NULL,
1479                 NULL,
1480                 m->state,
1481                 m->state_timeout);
1482 }
1483
1484
1485 /**
1486  * Function called with the transport service checking if we
1487  * want to blacklist a peer. Return #GNUNET_SYSERR for the
1488  * peer that we should disconnect from.
1489  *
1490  * @param cls NULL
1491  * @param cpid peer to check blacklisting for
1492  * @return #GNUNET_OK if the connection is allowed, #GNUNET_SYSERR if not
1493  */
1494 static int
1495 blacklist_cb (void *cls,
1496               const struct GNUNET_PeerIdentity *cpid)
1497 {
1498   if (0 == memcmp (cpid,
1499                    &pid,
1500                    sizeof (struct GNUNET_PeerIdentity)))
1501     return GNUNET_SYSERR;
1502   return GNUNET_OK;
1503 }
1504
1505
1506 /**
1507  * Main function that will be run by the scheduler.
1508  *
1509  * @param cls closure
1510  * @param args remaining command-line arguments
1511  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1512  * @param mycfg configuration
1513  */
1514 static void
1515 run (void *cls,
1516      char * const *args,
1517      const char *cfgfile,
1518      const struct GNUNET_CONFIGURATION_Handle *mycfg)
1519 {
1520   int counter = 0;
1521   ret = 1;
1522
1523   cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
1524   if (test_configuration)
1525   {
1526     do_test_configuration (cfg);
1527     return;
1528   }
1529   if ( (NULL != cpid) &&
1530        (GNUNET_OK !=
1531         GNUNET_CRYPTO_eddsa_public_key_from_string (cpid,
1532                                                     strlen (cpid),
1533                                                     &pid.public_key)))
1534   {
1535     FPRINTF (stderr,
1536              _("Failed to parse peer identity `%s'\n"),
1537              cpid);
1538     return;
1539   }
1540
1541   counter = benchmark_send + benchmark_receive + iterate_connections
1542       + monitor_connections + monitor_connects + do_disconnect +
1543       monitor_plugins;
1544
1545   if (1 < counter)
1546   {
1547     FPRINTF (stderr,
1548              _("Multiple operations given. Please choose only one operation: %s, %s, %s, %s, %s, %s %s\n"),
1549              "disconnect",
1550              "benchmark send",
1551              "benchmark receive",
1552              "information",
1553              "monitor",
1554              "events",
1555              "plugins");
1556     return;
1557   }
1558   if (0 == counter)
1559   {
1560     FPRINTF (stderr,
1561              _("No operation given. Please choose one operation: %s, %s, %s, %s, %s, %s, %s\n"),
1562              "disconnect",
1563              "benchmark send",
1564              "benchmark receive",
1565              "information",
1566              "monitor",
1567              "events",
1568              "plugins");
1569     return;
1570   }
1571
1572   if (do_disconnect) /* -D: Disconnect from peer */
1573   {
1574     if (NULL == cpid)
1575     {
1576       FPRINTF (stderr,
1577                _("Option `%s' makes no sense without option `%s'.\n"),
1578                "-D", "-p");
1579       ret = 1;
1580       return;
1581     }
1582     blacklist = GNUNET_TRANSPORT_blacklist (cfg,
1583                                             &blacklist_cb,
1584                                             NULL);
1585     if (NULL == blacklist)
1586     {
1587       FPRINTF (stderr,
1588                "%s",
1589                _("Failed to connect to transport service for disconnection\n"));
1590       ret = 1;
1591       return;
1592     }
1593     FPRINTF (stdout,
1594              "%s",
1595              _("Blacklisting request in place, stop with CTRL-C\n"));
1596   }
1597   else if (benchmark_send) /* -s: Benchmark sending */
1598   {
1599     if (NULL == cpid)
1600     {
1601       FPRINTF (stderr,
1602                _("Option `%s' makes no sense without option `%s'.\n"),
1603                "-s", "-p");
1604       ret = 1;
1605       return;
1606     }
1607     handle = GNUNET_TRANSPORT_core_connect (cfg,
1608                                             NULL,
1609                                             NULL,
1610                                             NULL,
1611                                             &notify_connect,
1612                                             &notify_disconnect,
1613                                             NULL);
1614     if (NULL == handle)
1615     {
1616       FPRINTF (stderr,
1617                "%s",
1618                _("Failed to connect to transport service\n"));
1619       ret = 1;
1620       return;
1621     }
1622     start_time = GNUNET_TIME_absolute_get ();
1623     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1624                                                &operation_timeout,
1625                                                NULL);
1626   }
1627   else if (benchmark_receive) /* -b: Benchmark receiving */
1628   {
1629     struct GNUNET_MQ_MessageHandler handlers[] = {
1630       GNUNET_MQ_hd_var_size (dummy,
1631                              GNUNET_MESSAGE_TYPE_DUMMY,
1632                              struct GNUNET_MessageHeader,
1633                              NULL),
1634       GNUNET_MQ_handler_end ()
1635     };
1636     
1637     handle = GNUNET_TRANSPORT_core_connect (cfg,
1638                                             NULL,
1639                                             handlers,
1640                                             NULL,
1641                                             NULL,
1642                                             NULL,
1643                                             NULL);
1644     if (NULL == handle)
1645     {
1646       FPRINTF (stderr,
1647                "%s",
1648                _("Failed to connect to transport service\n"));
1649       ret = 1;
1650       return;
1651     }
1652     if (verbosity > 0)
1653       FPRINTF (stdout,
1654                "%s",
1655                _("Starting to receive benchmark data\n"));
1656     start_time = GNUNET_TIME_absolute_get ();
1657
1658   }
1659   else if (iterate_connections) /* -i: List information about peers once */
1660   {
1661     pic = GNUNET_TRANSPORT_monitor_peers (cfg,
1662                                           (NULL == cpid) ? NULL : &pid,
1663                                           GNUNET_YES,
1664                                           &process_peer_iteration_cb,
1665                                           (void *) cfg);
1666     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1667                                                &operation_timeout,
1668                                                NULL);
1669   }
1670   else if (monitor_connections) /* -m: List information about peers continuously */
1671   {
1672     monitored_peers = GNUNET_CONTAINER_multipeermap_create (10,
1673                                                             GNUNET_NO);
1674     pic = GNUNET_TRANSPORT_monitor_peers (cfg,
1675                                           (NULL == cpid) ? NULL : &pid,
1676                                           GNUNET_NO,
1677                                           &process_peer_monitoring_cb,
1678                                           NULL);
1679   }
1680   else if (monitor_plugins) /* -P: List information about plugins continuously */
1681   {
1682     monitored_plugins = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1683     pm = GNUNET_TRANSPORT_monitor_plugins (cfg,
1684                                            &plugin_monitoring_cb,
1685                                            NULL);
1686   }
1687   else if (monitor_connects) /* -e : Monitor (dis)connect events continuously */
1688   {
1689     monitor_connect_counter = 0;
1690     handle = GNUNET_TRANSPORT_core_connect (cfg,
1691                                             NULL,
1692                                             NULL,
1693                                             NULL,
1694                                             &monitor_notify_connect,
1695                                             &monitor_notify_disconnect,
1696                                             NULL);
1697     if (NULL == handle)
1698     {
1699       FPRINTF (stderr,
1700                "%s",
1701                _("Failed to connect to transport service\n"));
1702       ret = 1;
1703       return;
1704     }
1705     ret = 0;
1706   }
1707   else
1708   {
1709     GNUNET_break(0);
1710     return;
1711   }
1712
1713   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1714                                  NULL);
1715 }
1716
1717
1718 int
1719 main (int argc,
1720       char * const *argv)
1721 {
1722   int res;
1723   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1724     { 'a', "all", NULL,
1725       gettext_noop ("print information for all peers (instead of only connected peers)"),
1726       0, &GNUNET_GETOPT_set_one, &iterate_all },
1727     { 'b', "benchmark", NULL,
1728       gettext_noop ("measure how fast we are receiving data from all peers (until CTRL-C)"),
1729       0, &GNUNET_GETOPT_set_one, &benchmark_receive },
1730     { 'D', "disconnect",
1731       NULL, gettext_noop ("disconnect from a peer"), 0,
1732       &GNUNET_GETOPT_set_one, &do_disconnect },
1733     { 'i', "information", NULL,
1734       gettext_noop ("provide information about all current connections (once)"),
1735       0, &GNUNET_GETOPT_set_one, &iterate_connections },
1736     { 'm', "monitor", NULL,
1737       gettext_noop ("provide information about all current connections (continuously)"),
1738       0, &GNUNET_GETOPT_set_one, &monitor_connections },
1739     { 'e', "events", NULL,
1740       gettext_noop ("provide information about all connects and disconnect events (continuously)"),
1741       0, &GNUNET_GETOPT_set_one, &monitor_connects },
1742     { 'n', "numeric",
1743       NULL, gettext_noop ("do not resolve hostnames"), 0,
1744       &GNUNET_GETOPT_set_one, &numeric },
1745     { 'p', "peer", "PEER",
1746       gettext_noop ("peer identity"), 1, &GNUNET_GETOPT_set_string,
1747       &cpid },
1748     { 'P', "plugins", NULL,
1749       gettext_noop ("monitor plugin sessions"), 0, &GNUNET_GETOPT_set_one,
1750       &monitor_plugins },
1751     { 's', "send", NULL, gettext_noop
1752       ("send data for benchmarking to the other peer (until CTRL-C)"), 0,
1753       &GNUNET_GETOPT_set_one, &benchmark_send },
1754     { 't', "test", NULL,
1755       gettext_noop ("test transport configuration (involves external server)"),
1756       0, &GNUNET_GETOPT_set_one, &test_configuration },
1757     GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
1758     GNUNET_GETOPT_OPTION_END
1759   };
1760
1761   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1762     return 2;
1763
1764   res = GNUNET_PROGRAM_run (argc, argv,
1765                             "gnunet-transport",
1766                             gettext_noop ("Direct access to transport service."),
1767                             options,
1768                             &run, NULL);
1769   GNUNET_free((void *) argv);
1770   if (GNUNET_OK == res)
1771     return ret;
1772   return 1;
1773 }
1774
1775 /* end of gnunet-transport.c */