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