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