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