plugin datastore mysql
[oweals/gnunet.git] / src / transport / gnunet-transport.c
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2011-2014 GNUnet e.V.
4
5  GNUnet is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published
7  by the Free Software Foundation; either version 3, or (at your
8  option) any later version.
9
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  General Public License for more details.
14
15  You should have received a copy of the GNU General Public License
16  along with GNUnet; see the file COPYING.  If not, write to the
17  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * @file src/transport/gnunet-transport.c
23  * @brief Tool to help configure, measure and control the transport subsystem.
24  * @author Christian Grothoff
25  * @author Nathan Evans
26  *
27  * This utility can be used to test if a transport mechanism for
28  * GNUnet is properly configured.
29  */
30 #include "platform.h"
31 #include "gnunet_util_lib.h"
32 #include "gnunet_resolver_service.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_nat_lib.h"
36
37 /**
38  * How long do we wait for the NAT test to report success?
39  * Should match NAT_SERVER_TIMEOUT in 'nat_test.c'.
40  */
41 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
42
43 /**
44  * Timeout for a name resolution
45  */
46 #define RESOLUTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
47
48 /**
49  * Timeout for an operation
50  */
51 #define OP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
52
53
54 /**
55  * Context to store name resolutions for valiation
56  */
57 struct ValidationResolutionContext
58 {
59   /**
60    * Next in DLL
61    */
62   struct ValidationResolutionContext *next;
63
64   /**
65    * Previous in DLL
66    */
67   struct ValidationResolutionContext *prev;
68
69   /**
70    * Address to resolve
71    */
72   struct GNUNET_HELLO_Address *addrcp;
73
74   /**
75    * Time of last validation
76    */
77   struct GNUNET_TIME_Absolute last_validation;
78
79   /**
80    * Address is valid until
81    */
82   struct GNUNET_TIME_Absolute valid_until;
83
84   /**
85    * Time of next validation
86    */
87   struct GNUNET_TIME_Absolute next_validation;
88
89   /**
90    * 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  */
491 static void
492 shutdown_task (void *cls)
493 {
494   struct GNUNET_TIME_Relative duration;
495   struct ValidationResolutionContext *cur;
496   struct ValidationResolutionContext *next;
497   struct PeerResolutionContext *rc;
498
499   end = NULL;
500   if (NULL != op_timeout)
501   {
502     GNUNET_SCHEDULER_cancel (op_timeout);
503     op_timeout = NULL;
504   }
505   if (NULL != pic)
506   {
507     GNUNET_TRANSPORT_monitor_peers_cancel (pic);
508     pic = NULL;
509   }
510   if (NULL != vic)
511   {
512     GNUNET_TRANSPORT_monitor_validation_entries_cancel (vic);
513     vic = NULL;
514   }
515   if (NULL != pm)
516   {
517     GNUNET_TRANSPORT_monitor_plugins_cancel (pm);
518     pm = NULL;
519   }
520
521   next = vc_head;
522   for (cur = next; NULL != cur; cur = next)
523   {
524     next = cur->next;
525
526     GNUNET_TRANSPORT_address_to_string_cancel (cur->asc);
527     GNUNET_CONTAINER_DLL_remove (vc_head,
528                                  vc_tail,
529                                  cur);
530     GNUNET_free (cur->transport);
531     GNUNET_HELLO_address_free (cur->addrcp);
532     GNUNET_free (cur);
533   }
534   while (NULL != (rc = rc_head))
535   {
536     GNUNET_CONTAINER_DLL_remove (rc_head,
537                                  rc_tail,
538                                  rc);
539     GNUNET_TRANSPORT_address_to_string_cancel (rc->asc);
540     GNUNET_free (rc->transport);
541     GNUNET_free (rc->addrcp);
542     GNUNET_free (rc);
543   }
544   if (NULL != th)
545   {
546     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
547     th = NULL;
548   }
549   if (NULL != handle)
550   {
551     GNUNET_TRANSPORT_disconnect (handle);
552     handle = NULL;
553   }
554   if (benchmark_send)
555   {
556     duration = GNUNET_TIME_absolute_get_duration (start_time);
557     FPRINTF (stdout,
558              _("Transmitted %llu bytes/s (%llu bytes in %s)\n"),
559              1000LL * 1000LL * traffic_sent / (1 + duration.rel_value_us),
560              traffic_sent,
561              GNUNET_STRINGS_relative_time_to_string (duration, GNUNET_YES));
562   }
563   if (benchmark_receive)
564   {
565     duration = GNUNET_TIME_absolute_get_duration (start_time);
566     FPRINTF (stdout,
567              _("Received %llu bytes/s (%llu bytes in %s)\n"),
568              1000LL * 1000LL * traffic_received / (1 + duration.rel_value_us),
569              traffic_received,
570              GNUNET_STRINGS_relative_time_to_string (duration, GNUNET_YES));
571   }
572
573   if (NULL != monitored_peers)
574   {
575     GNUNET_CONTAINER_multipeermap_iterate (monitored_peers, &destroy_it, NULL);
576     GNUNET_CONTAINER_multipeermap_destroy (monitored_peers);
577     monitored_peers = NULL;
578   }
579   if (NULL != monitored_plugins)
580   {
581     GNUNET_break (0 ==
582                   GNUNET_CONTAINER_multipeermap_size (monitored_plugins));
583     GNUNET_CONTAINER_multipeermap_destroy (monitored_plugins);
584     monitored_plugins = NULL;
585   }
586   if (NULL != blacklist)
587   {
588     GNUNET_TRANSPORT_blacklist_cancel (blacklist);
589     blacklist = NULL;
590     ret = 0;
591   }
592 }
593
594
595 /**
596  * We are done, shut down.
597  */
598 static void
599 operation_timeout (void *cls)
600 {
601   struct PeerResolutionContext *cur;
602   struct PeerResolutionContext *next;
603
604   op_timeout = NULL;
605   if ((benchmark_send) || (benchmark_receive))
606   {
607     FPRINTF (stdout,
608              _("Failed to connect to `%s'\n"),
609              GNUNET_i2s_full (&pid));
610     GNUNET_SCHEDULER_shutdown ();
611     ret = 1;
612     return;
613   }
614   if (iterate_connections)
615   {
616     next = rc_head;
617     while (NULL != (cur = next))
618     {
619       next = cur->next;
620       FPRINTF (stdout,
621                _("Failed to resolve address for peer `%s'\n"),
622                GNUNET_i2s (&cur->addrcp->peer));
623
624       GNUNET_CONTAINER_DLL_remove(rc_head, rc_tail, cur);
625       GNUNET_TRANSPORT_address_to_string_cancel (cur->asc);
626       GNUNET_free(cur->transport);
627       GNUNET_free(cur->addrcp);
628       GNUNET_free(cur);
629
630     }
631     FPRINTF (stdout,
632              "%s",
633              _("Failed to list connections, timeout occured\n"));
634     GNUNET_SCHEDULER_shutdown ();
635     ret = 1;
636     return;
637   }
638 }
639
640
641 static void
642 run_nat_test (void);
643
644
645 /**
646  * Display the result of the test.
647  *
648  * @param tc test context
649  * @param result #GNUNET_YES on success
650  */
651 static void
652 display_test_result (struct TestContext *tc,
653                      enum TestResult result)
654 {
655   switch (result) {
656     case NAT_TEST_FAIL:
657       FPRINTF (stderr,
658                _("Configuration for plugin `%s' did not work!\n"),
659                tc->name);
660       break;
661     case NAT_TEST_SUCCESS:
662       FPRINTF (stderr,
663                _("Configuration for plugin `%s' did work!\n"),
664                tc->name);
665       break;
666     case NAT_TEST_INTERNAL_FAIL:
667       FPRINTF (stderr,
668                _("Internal NAT error while running test for plugin `%s'\n"),
669                tc->name);
670       break;
671     case NAT_TEST_FAILED_TO_START:
672       FPRINTF (stderr,
673                _("Failed to start NAT test for plugin `%s'\n"),
674                tc->name);
675       break;
676     case NAT_TEST_TIMEOUT:
677       FPRINTF (stderr,
678                _("Timeout while waiting for result of NAT test for plugin `%s'\n"),
679                tc->name);
680       break;
681     default:
682       FPRINTF (stderr,
683                _("Configuration for plugin `%s' did not work!\n"),
684                tc->name);
685       break;
686   }
687   if (NULL != tc->tsk)
688   {
689     GNUNET_SCHEDULER_cancel (tc->tsk);
690     tc->tsk = NULL;
691   }
692   if (NULL != tc->tst)
693   {
694     GNUNET_NAT_test_stop (tc->tst);
695     tc->tst = NULL;
696   }
697
698   GNUNET_CONTAINER_DLL_remove (head, tail, tc);
699   GNUNET_free (tc->name);
700   GNUNET_free (tc);
701
702   if ((NULL == head) && (NULL != resolver))
703   {
704     GNUNET_break (0 == GNUNET_OS_process_kill (resolver,
705                                                GNUNET_TERM_SIG));
706     GNUNET_OS_process_destroy (resolver);
707     resolver = NULL;
708   }
709   if (NULL != head)
710     run_nat_test ();
711 }
712
713
714 /**
715  * Function called by NAT to report the outcome of the nat-test.
716  * Clean up and update GUI.
717  *
718  * @param cls test context
719  * @param result status code
720  */
721 static void
722 result_callback (void *cls,
723                  enum GNUNET_NAT_StatusCode result)
724 {
725   struct TestContext *tc = cls;
726
727   display_test_result (tc,
728                        result);
729 }
730
731
732 /**
733  * Resolve address we got a validation state for to a string.
734  *
735  * @param address the address itself
736  * @param numeric #GNUNET_YES to disable DNS, #GNUNET_NO to try reverse lookup
737  * @param last_validation when was the address validated last
738  * @param valid_until until when is the address valid
739  * @param next_validation when will we try to revalidate the address next
740  * @param state where are we in the validation state machine
741  */
742 static void
743 resolve_validation_address (const struct GNUNET_HELLO_Address *address,
744                             int numeric,
745                             struct GNUNET_TIME_Absolute last_validation,
746                             struct GNUNET_TIME_Absolute valid_until,
747                             struct GNUNET_TIME_Absolute next_validation,
748                             enum GNUNET_TRANSPORT_ValidationState state);
749
750
751 /**
752  * Function to call with a textual representation of an address.  This
753  * function will be called several times with different possible
754  * textual representations, and a last time with @a address being NULL
755  * to signal the end of the iteration.  Note that @a address NULL
756  * always is the last call, regardless of the value in @a res.
757  *
758  * @param cls closure
759  * @param address NULL on end of iteration,
760  *        otherwise 0-terminated printable UTF-8 string,
761  *        in particular an empty string if @a res is #GNUNET_NO
762  * @param res result of the address to string conversion:
763  *        if #GNUNET_OK: conversion successful
764  *        if #GNUNET_NO: address was invalid (or not supported)
765  *        if #GNUNET_SYSERR: communication error (IPC error)
766  */
767 static void
768 process_validation_string (void *cls,
769                            const char *address,
770                            int res)
771 {
772   struct ValidationResolutionContext *vc = cls;
773   char *s_valid;
774   char *s_last;
775   char *s_next;
776
777   if (NULL != address)
778   {
779     if (GNUNET_SYSERR == res)
780     {
781       FPRINTF (stderr,
782                "Failed to convert address for peer `%s' plugin `%s' length %u to string \n",
783                GNUNET_i2s (&vc->addrcp->peer),
784                vc->addrcp->transport_name,
785                (unsigned int) vc->addrcp->address_length);
786     }
787     if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == vc->valid_until.abs_value_us)
788       s_valid = GNUNET_strdup ("never");
789     else
790       s_valid = GNUNET_strdup (GNUNET_STRINGS_absolute_time_to_string (vc->valid_until));
791
792     if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == vc->last_validation.abs_value_us)
793       s_last = GNUNET_strdup ("never");
794     else
795       s_last = GNUNET_strdup (GNUNET_STRINGS_absolute_time_to_string (vc->last_validation));
796
797     if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == vc->next_validation.abs_value_us)
798       s_next = GNUNET_strdup ("never");
799     else
800       s_next = GNUNET_strdup (GNUNET_STRINGS_absolute_time_to_string (vc->next_validation));
801
802     FPRINTF (stdout,
803              _("Peer `%s' %s %s\n\t%s%s\n\t%s%s\n\t%s%s\n"),
804              GNUNET_i2s (&vc->addrcp->peer),
805              (GNUNET_OK == res) ? address : "<invalid address>",
806              (monitor_validation) ? GNUNET_TRANSPORT_vs2s (vc->state) : "",
807              "Valid until    : ", s_valid,
808              "Last validation: ",s_last,
809              "Next validation: ", s_next);
810     GNUNET_free (s_valid);
811     GNUNET_free (s_last);
812     GNUNET_free (s_next);
813     vc->printed = GNUNET_YES;
814     return;
815   }
816   /* last call, we are done */
817   GNUNET_assert (address_resolutions > 0);
818   address_resolutions--;
819   if ( (GNUNET_SYSERR == res) &&
820        (GNUNET_NO == vc->printed))
821   {
822     if (numeric == GNUNET_NO)
823     {
824       /* Failed to resolve address, try numeric lookup
825          (note: this should be unnecessary, as
826          transport should fallback to numeric lookup
827          internally if DNS takes too long anyway) */
828       resolve_validation_address (vc->addrcp,
829                                   GNUNET_NO,
830                                   vc->last_validation,
831                                   vc->valid_until,
832                                   vc->next_validation,
833                                   vc->state);
834     }
835     else
836     {
837       FPRINTF (stdout,
838                _("Peer `%s' %s `%s' \n"),
839                GNUNET_i2s (&vc->addrcp->peer),
840                "<unable to resolve address>",
841                GNUNET_TRANSPORT_vs2s (vc->state));
842     }
843   }
844   GNUNET_free (vc->transport);
845   GNUNET_free (vc->addrcp);
846   GNUNET_CONTAINER_DLL_remove (vc_head, vc_tail, vc);
847   GNUNET_free (vc);
848   if ((0 == address_resolutions) && (iterate_validation))
849   {
850     if (NULL != op_timeout)
851     {
852       GNUNET_SCHEDULER_cancel (op_timeout);
853       op_timeout = NULL;
854     }
855     ret = 0;
856     GNUNET_SCHEDULER_shutdown ();
857   }
858 }
859
860
861 /**
862  * Resolve address we got a validation state for to a string.
863  *
864  * @param address the address itself
865  * @param numeric #GNUNET_YES to disable DNS, #GNUNET_NO to try reverse lookup
866  * @param last_validation when was the address validated last
867  * @param valid_until until when is the address valid
868  * @param next_validation when will we try to revalidate the address next
869  * @param state where are we in the validation state machine
870  */
871 static void
872 resolve_validation_address (const struct GNUNET_HELLO_Address *address,
873                             int numeric,
874                             struct GNUNET_TIME_Absolute last_validation,
875                             struct GNUNET_TIME_Absolute valid_until,
876                             struct GNUNET_TIME_Absolute next_validation,
877                             enum GNUNET_TRANSPORT_ValidationState state)
878 {
879   struct ValidationResolutionContext *vc;
880
881   vc = GNUNET_new (struct ValidationResolutionContext);
882   GNUNET_assert(NULL != vc);
883   GNUNET_CONTAINER_DLL_insert(vc_head, vc_tail, vc);
884   address_resolutions++;
885
886   vc->transport = GNUNET_strdup(address->transport_name);
887   vc->addrcp = GNUNET_HELLO_address_copy (address);
888   vc->printed = GNUNET_NO;
889   vc->state = state;
890   vc->last_validation = last_validation;
891   vc->valid_until = valid_until;
892   vc->next_validation = next_validation;
893
894   /* Resolve address to string */
895   vc->asc = GNUNET_TRANSPORT_address_to_string (cfg,
896                                                 address,
897                                                 numeric,
898                                                 RESOLUTION_TIMEOUT,
899                                                 &process_validation_string, vc);
900 }
901
902
903 /**
904  * Resolve address we got a validation state for to a string.
905  *
906  * @param cls NULL
907  * @param address the address itself
908  * @param last_validation when was the address validated last
909  * @param valid_until until when is the address valid
910  * @param next_validation when will we try to revalidate the address next
911  * @param state where are we in the validation state machine
912  */
913 static void
914 process_validation_cb (void *cls,
915                        const struct GNUNET_HELLO_Address *address,
916                        struct GNUNET_TIME_Absolute last_validation,
917                        struct GNUNET_TIME_Absolute valid_until,
918                        struct GNUNET_TIME_Absolute next_validation,
919                        enum GNUNET_TRANSPORT_ValidationState state)
920 {
921   if (NULL == address)
922   {
923     if (monitor_validation)
924     {
925       FPRINTF (stdout,
926                "%s",
927                _("Monitor disconnected from transport service. Reconnecting.\n"));
928       return;
929     }
930     vic = NULL;
931     GNUNET_SCHEDULER_shutdown ();
932     return;
933   }
934   resolve_validation_address (address,
935                               numeric,
936                               last_validation,
937                               valid_until,
938                               next_validation,
939                               state);
940 }
941
942
943 static void
944 run_nat_test ()
945 {
946   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
947               "Running test for plugin `%s' using bind port %u and advertised port %u \n",
948               head->name,
949               (uint16_t) head->bnd_port,
950               (uint16_t) head->adv_port);
951
952   head->tst = GNUNET_NAT_test_start (cfg,
953                                      (0 == strcasecmp (head->name, "udp"))
954                                      ? GNUNET_NO : GNUNET_YES,
955                                      (uint16_t) head->bnd_port,
956                                      (uint16_t) head->adv_port,
957                                      TIMEOUT,
958                                      &result_callback, head);
959 }
960
961
962 /**
963  * Test our plugin's configuration (NAT traversal, etc.).
964  *
965  * @param cfg configuration to test
966  */
967 static void
968 do_test_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
969 {
970   char *plugins;
971   char *tok;
972   unsigned long long bnd_port;
973   unsigned long long adv_port;
974   struct TestContext *tc;
975   char *binary;
976
977   if (GNUNET_OK
978       != GNUNET_CONFIGURATION_get_value_string (cfg, "transport", "plugins",
979           &plugins))
980   {
981     FPRINTF (stderr, "%s", _
982     ("No transport plugins configured, peer will never communicate\n"));
983     ret = 4;
984     return;
985   }
986
987   for (tok = strtok (plugins, " "); tok != NULL ; tok = strtok (NULL, " "))
988   {
989     char section[12 + strlen (tok)];
990     GNUNET_snprintf (section, sizeof(section), "transport-%s", tok);
991     if (GNUNET_OK
992         != GNUNET_CONFIGURATION_get_value_number (cfg, section, "PORT",
993             &bnd_port))
994     {
995       FPRINTF (stderr,
996           _("No port configured for plugin `%s', cannot test it\n"), tok);
997       continue;
998     }
999     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, section,
1000             "ADVERTISED_PORT", &adv_port))
1001       adv_port = bnd_port;
1002
1003     tc = GNUNET_new (struct TestContext);
1004     tc->name = GNUNET_strdup (tok);
1005     tc->adv_port = adv_port;
1006     tc->bnd_port = bnd_port;
1007     GNUNET_CONTAINER_DLL_insert_tail (head, tail, tc);
1008   }
1009   GNUNET_free(plugins);
1010
1011   if ((NULL != head) && (NULL == resolver))
1012   {
1013     binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
1014     resolver = GNUNET_OS_start_process (GNUNET_YES,
1015                                         GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1016                                         NULL, NULL, NULL,
1017                                         binary,
1018                                         "gnunet-service-resolver", NULL);
1019     if (NULL == resolver)
1020     {
1021       FPRINTF (stderr, _("Failed to start resolver!\n"));
1022       return;
1023     }
1024
1025     GNUNET_free(binary);
1026     GNUNET_RESOLVER_connect (cfg);
1027     run_nat_test ();
1028   }
1029 }
1030
1031
1032 /**
1033  * Function called to notify a client about the socket
1034  * begin ready to queue more data.  @a buf will be
1035  * NULL and @a size zero if the socket was closed for
1036  * writing in the meantime.
1037  *
1038  * @param cls closure
1039  * @param size number of bytes available in @a buf
1040  * @param buf where the callee should write the message
1041  * @return number of bytes written to @a buf
1042  */
1043 static size_t
1044 transmit_data (void *cls,
1045                size_t size,
1046                void *buf)
1047 {
1048   struct GNUNET_MessageHeader *m = buf;
1049
1050   if ((NULL == buf) || (0 == size))
1051   {
1052     th = NULL;
1053     return 0;
1054   }
1055
1056   GNUNET_assert(size >= sizeof(struct GNUNET_MessageHeader));
1057   GNUNET_assert(size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
1058   m->size = ntohs (size);
1059   m->type = ntohs (GNUNET_MESSAGE_TYPE_DUMMY);
1060   memset (&m[1], 52, size - sizeof(struct GNUNET_MessageHeader));
1061   traffic_sent += size;
1062   th = GNUNET_TRANSPORT_notify_transmit_ready (handle, &pid,
1063                                                BLOCKSIZE * 1024,
1064                                                GNUNET_TIME_UNIT_FOREVER_REL,
1065                                                &transmit_data, NULL);
1066   if (verbosity > 0)
1067     FPRINTF (stdout, _("Transmitting %u bytes to %s\n"), (unsigned int) size,
1068         GNUNET_i2s (&pid));
1069   return size;
1070 }
1071
1072
1073 /**
1074  * Function called to notify transport users that another
1075  * peer connected to us.
1076  *
1077  * @param cls closure
1078  * @param peer the peer that connected
1079  */
1080 static void
1081 notify_connect (void *cls,
1082                 const struct GNUNET_PeerIdentity *peer)
1083 {
1084   if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
1085     return;
1086   ret = 0;
1087   if (benchmark_send)
1088   {
1089     if (NULL != op_timeout)
1090     {
1091       GNUNET_SCHEDULER_cancel (op_timeout);
1092       op_timeout = NULL;
1093     }
1094     if (verbosity > 0)
1095       FPRINTF (stdout,
1096           _("Successfully connected to `%s', starting to send benchmark data in %u Kb blocks\n"),
1097           GNUNET_i2s (&pid), BLOCKSIZE);
1098     start_time = GNUNET_TIME_absolute_get ();
1099     if (NULL == th)
1100       th = GNUNET_TRANSPORT_notify_transmit_ready (handle, peer,
1101                                                    BLOCKSIZE * 1024,
1102                                                    GNUNET_TIME_UNIT_FOREVER_REL,
1103                                                    &transmit_data,
1104                                                    NULL);
1105     else
1106       GNUNET_break(0);
1107     return;
1108   }
1109 }
1110
1111
1112 /**
1113  * Function called to notify transport users that another
1114  * peer disconnected from us.
1115  *
1116  * @param cls closure
1117  * @param peer the peer that disconnected
1118  */
1119 static void
1120 notify_disconnect (void *cls,
1121                    const struct GNUNET_PeerIdentity *peer)
1122 {
1123   if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
1124     return;
1125
1126   if (NULL != th)
1127   {
1128     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
1129     th = NULL;
1130   }
1131   if (benchmark_send)
1132   {
1133     FPRINTF (stdout, _("Disconnected from peer `%s' while benchmarking\n"),
1134         GNUNET_i2s (&pid));
1135     if (NULL != end)
1136       GNUNET_SCHEDULER_cancel (end);
1137     return;
1138   }
1139 }
1140
1141
1142 /**
1143  * Function called to notify transport users that another
1144  * peer connected to us.
1145  *
1146  * @param cls closure
1147  * @param peer the peer that connected
1148  */
1149 static void
1150 monitor_notify_connect (void *cls,
1151                         const struct GNUNET_PeerIdentity *peer)
1152 {
1153   monitor_connect_counter++;
1154   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1155   const char *now_str = GNUNET_STRINGS_absolute_time_to_string (now);
1156
1157   FPRINTF (stdout,
1158            _("%24s: %-17s %4s   (%u connections in total)\n"),
1159            now_str,
1160            _("Connected to"),
1161            GNUNET_i2s (peer),
1162            monitor_connect_counter);
1163 }
1164
1165
1166 /**
1167  * Function called to notify transport users that another
1168  * peer disconnected from us.
1169  *
1170  * @param cls closure
1171  * @param peer the peer that disconnected
1172  */
1173 static void
1174 monitor_notify_disconnect (void *cls,
1175                            const struct GNUNET_PeerIdentity *peer)
1176 {
1177   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1178   const char *now_str = GNUNET_STRINGS_absolute_time_to_string (now);
1179
1180   GNUNET_assert(monitor_connect_counter > 0);
1181   monitor_connect_counter--;
1182
1183   FPRINTF (stdout,
1184            _("%24s: %-17s %4s   (%u connections in total)\n"),
1185            now_str,
1186            _("Disconnected from"),
1187            GNUNET_i2s (peer),
1188            monitor_connect_counter);
1189 }
1190
1191
1192 /**
1193  * Function called by the transport for each received message.
1194  *
1195  * @param cls closure
1196  * @param peer (claimed) identity of the other peer
1197  * @param message the message
1198  */
1199 static void
1200 notify_receive (void *cls,
1201                 const struct GNUNET_PeerIdentity *peer,
1202                 const struct GNUNET_MessageHeader *message)
1203 {
1204   if (benchmark_receive)
1205   {
1206     if (GNUNET_MESSAGE_TYPE_DUMMY != ntohs (message->type))
1207       return;
1208     if (verbosity > 0)
1209       FPRINTF (stdout,
1210                _("Received %u bytes from %s\n"),
1211                (unsigned int) ntohs (message->size),
1212                GNUNET_i2s (peer));
1213
1214     if (traffic_received == 0)
1215       start_time = GNUNET_TIME_absolute_get ();
1216     traffic_received += ntohs (message->size);
1217     return;
1218   }
1219 }
1220
1221
1222 /**
1223  * Convert address to a printable format.
1224  *
1225  * @param address the address
1226  * @param numeric #GNUNET_YES to convert to numeric format, #GNUNET_NO
1227  *                to try to use reverse DNS
1228  * @param state state the peer is in
1229  * @param state_timeout when will the peer's state expire
1230  */
1231 static void
1232 resolve_peer_address (const struct GNUNET_HELLO_Address *address,
1233                       int numeric,
1234                       enum GNUNET_TRANSPORT_PeerState state,
1235                       struct GNUNET_TIME_Absolute state_timeout);
1236
1237
1238 static void
1239 print_info (const struct GNUNET_PeerIdentity *id,
1240             const char *transport,
1241             const char *addr,
1242             enum GNUNET_TRANSPORT_PeerState state,
1243             struct GNUNET_TIME_Absolute state_timeout)
1244 {
1245
1246   if ( ((GNUNET_YES == iterate_connections) && (GNUNET_YES == iterate_all)) ||
1247        (GNUNET_YES == monitor_connections))
1248   {
1249     FPRINTF (stdout,
1250              _("Peer `%s': %s %s in state `%s' until %s\n"),
1251              GNUNET_i2s (id),
1252              (NULL == transport) ? "<none>" : transport,
1253              (NULL == transport) ? "<none>" : addr,
1254              GNUNET_TRANSPORT_ps2s (state),
1255              GNUNET_STRINGS_absolute_time_to_string (state_timeout));
1256   }
1257   else if ( (GNUNET_YES == iterate_connections) &&
1258              (GNUNET_TRANSPORT_is_connected(state)))
1259   {
1260     /* Only connected peers, skip state */
1261     FPRINTF (stdout,
1262              _("Peer `%s': %s %s\n"),
1263              GNUNET_i2s (id),
1264              transport,
1265              addr);
1266   }
1267 }
1268
1269
1270 /**
1271  * Function called with a textual representation of an address.  This
1272  * function will be called several times with different possible
1273  * textual representations, and a last time with @a address being NULL
1274  * to signal the end of the iteration.  Note that @a address NULL
1275  * always is the last call, regardless of the value in @a res.
1276  *
1277  * @param cls closure
1278  * @param address NULL on end of iteration,
1279  *        otherwise 0-terminated printable UTF-8 string,
1280  *        in particular an empty string if @a res is #GNUNET_NO
1281  * @param res result of the address to string conversion:
1282  *        if #GNUNET_OK: conversion successful
1283  *        if #GNUNET_NO: address was invalid (or not supported)
1284  *        if #GNUNET_SYSERR: communication error (IPC error)
1285  */
1286 static void
1287 process_peer_string (void *cls,
1288                      const char *address,
1289                      int res)
1290 {
1291   struct PeerResolutionContext *rc = cls;
1292
1293   if (NULL != address)
1294   {
1295     if (GNUNET_SYSERR == res)
1296     {
1297       FPRINTF (stderr,
1298                "Failed to convert address for peer `%s' plugin `%s' length %u to string \n",
1299                GNUNET_i2s (&rc->addrcp->peer),
1300                rc->addrcp->transport_name,
1301                (unsigned int) rc->addrcp->address_length);
1302       print_info (&rc->addrcp->peer,
1303                   rc->transport,
1304                   NULL,
1305                   rc->state,
1306                   rc->state_timeout);
1307       rc->printed = GNUNET_YES;
1308       return;
1309     }
1310     if (GNUNET_OK == res)
1311     {
1312       print_info (&rc->addrcp->peer,
1313                   rc->transport,
1314                   address,
1315                   rc->state,
1316                   rc->state_timeout);
1317       rc->printed = GNUNET_YES;
1318       return; /* Wait for done call */
1319     }
1320     /* GNUNET_NO == res: ignore, was simply not supported */
1321     return;
1322   }
1323   /* NULL == address, last call, we are done */
1324
1325   rc->asc = NULL;
1326   GNUNET_assert (address_resolutions > 0);
1327   address_resolutions--;
1328   if (GNUNET_NO == rc->printed)
1329   {
1330     if (numeric == GNUNET_NO)
1331     {
1332       /* Failed to resolve address, try numeric lookup
1333          (note: this should not be needed, as transport
1334          should fallback to numeric conversion if DNS takes
1335          too long) */
1336       resolve_peer_address (rc->addrcp,
1337                             GNUNET_YES,
1338                             rc->state,
1339                             rc->state_timeout);
1340     }
1341     else
1342     {
1343       print_info (&rc->addrcp->peer,
1344                   rc->transport,
1345                   NULL,
1346                   rc->state,
1347                   rc->state_timeout);
1348     }
1349   }
1350   GNUNET_free (rc->transport);
1351   GNUNET_free (rc->addrcp);
1352   GNUNET_CONTAINER_DLL_remove (rc_head, rc_tail, rc);
1353   GNUNET_free (rc);
1354   if ((0 == address_resolutions) && (iterate_connections))
1355   {
1356     if (NULL != op_timeout)
1357     {
1358       GNUNET_SCHEDULER_cancel (op_timeout);
1359       op_timeout = NULL;
1360     }
1361     ret = 0;
1362     GNUNET_SCHEDULER_shutdown ();
1363   }
1364 }
1365
1366
1367 /**
1368  * Convert address to a printable format and print it
1369  * together with the given state data.
1370  *
1371  * @param address the address
1372  * @param numeric #GNUNET_YES to convert to numeric format, #GNUNET_NO
1373  *                to try to use reverse DNS
1374  * @param state state the peer is in
1375  * @param state_timeout when will the peer's state expire
1376  */
1377 static void
1378 resolve_peer_address (const struct GNUNET_HELLO_Address *address,
1379                       int numeric,
1380                       enum GNUNET_TRANSPORT_PeerState state,
1381                       struct GNUNET_TIME_Absolute state_timeout)
1382 {
1383   struct PeerResolutionContext *rc;
1384
1385   rc = GNUNET_new (struct PeerResolutionContext);
1386   GNUNET_CONTAINER_DLL_insert (rc_head,
1387                                rc_tail,
1388                                rc);
1389   address_resolutions++;
1390   rc->transport = GNUNET_strdup (address->transport_name);
1391   rc->addrcp = GNUNET_HELLO_address_copy (address);
1392   rc->printed = GNUNET_NO;
1393   rc->state = state;
1394   rc->state_timeout = state_timeout;
1395   /* Resolve address to string */
1396   rc->asc = GNUNET_TRANSPORT_address_to_string (cfg,
1397                                                 address,
1398                                                 numeric,
1399                                                 RESOLUTION_TIMEOUT,
1400                                                 &process_peer_string, rc);
1401 }
1402
1403
1404 /**
1405  * Function called with information about a peers during a one shot iteration
1406  *
1407  * @param cls closure
1408  * @param peer identity of the peer, NULL for final callback when operation done
1409  * @param address binary address used to communicate with this peer,
1410  *  NULL on disconnect or when done
1411  * @param state current state this peer is in
1412  * @param state_timeout time out for the current state
1413  */
1414 static void
1415 process_peer_iteration_cb (void *cls,
1416                            const struct GNUNET_PeerIdentity *peer,
1417                            const struct GNUNET_HELLO_Address *address,
1418                            enum GNUNET_TRANSPORT_PeerState state,
1419                            struct GNUNET_TIME_Absolute state_timeout)
1420 {
1421   if (NULL == peer)
1422   {
1423     /* done */
1424     pic = NULL;
1425     return;
1426   }
1427
1428   if ( (GNUNET_NO == iterate_all) &&
1429        (GNUNET_NO == GNUNET_TRANSPORT_is_connected(state)))
1430       return; /* Display only connected peers */
1431
1432   if (NULL != op_timeout)
1433     GNUNET_SCHEDULER_cancel (op_timeout);
1434   op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1435                                              &operation_timeout,
1436                                              NULL);
1437
1438   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1439               "Received address for peer `%s': %s\n",
1440               GNUNET_i2s (peer),
1441               address ? address->transport_name : "");
1442
1443   if (NULL != address)
1444     resolve_peer_address (address,
1445                           numeric,
1446                           state,
1447                           state_timeout);
1448   else
1449     print_info (peer,
1450                 NULL,
1451                 NULL,
1452                 state,
1453                 state_timeout);
1454 }
1455
1456
1457 /**
1458  * Context for address resolution by #plugin_monitoring_cb().
1459  */
1460 struct PluginMonitorAddress
1461 {
1462
1463   /**
1464    * Ongoing resolution request.
1465    */
1466   struct GNUNET_TRANSPORT_AddressToStringContext *asc;
1467
1468   /**
1469    * Resolved address as string.
1470    */
1471   char *str;
1472
1473   /**
1474    * Last event we got and did not yet print because
1475    * @e str was NULL (address not yet resolved).
1476    */
1477   struct GNUNET_TRANSPORT_SessionInfo si;
1478 };
1479
1480
1481 /**
1482  * Print information about a plugin monitoring event.
1483  *
1484  * @param addr out internal context
1485  * @param info the monitoring information
1486  */
1487 static void
1488 print_plugin_event_info (struct PluginMonitorAddress *addr,
1489                          const struct GNUNET_TRANSPORT_SessionInfo *info)
1490 {
1491   const char *state;
1492
1493   switch (info->state)
1494   {
1495   case GNUNET_TRANSPORT_SS_INIT:
1496     state = "INIT";
1497     break;
1498   case GNUNET_TRANSPORT_SS_HANDSHAKE:
1499     state = "HANDSHAKE";
1500     break;
1501   case GNUNET_TRANSPORT_SS_UP:
1502     state = "UP";
1503     break;
1504   case GNUNET_TRANSPORT_SS_UPDATE:
1505     state = "UPDATE";
1506     break;
1507   case GNUNET_TRANSPORT_SS_DONE:
1508     state = "DONE";
1509     break;
1510   default:
1511     state = "UNKNOWN";
1512     break;
1513   }
1514   fprintf (stdout,
1515            "%s: state %s timeout in %s @ %s%s\n",
1516            GNUNET_i2s (&info->address->peer),
1517            state,
1518            GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (info->session_timeout),
1519                                                    GNUNET_YES),
1520            addr->str,
1521            (info->is_inbound == GNUNET_YES) ? " (INBOUND)" : "");
1522   fprintf (stdout,
1523            "%s: queue has %3u messages and %6u bytes\n",
1524            GNUNET_i2s (&info->address->peer),
1525            info->num_msg_pending,
1526            info->num_bytes_pending);
1527   if (0 != GNUNET_TIME_absolute_get_remaining (info->receive_delay).rel_value_us)
1528     fprintf (stdout,
1529              "%s: receiving blocked until %s\n",
1530              GNUNET_i2s (&info->address->peer),
1531              GNUNET_STRINGS_absolute_time_to_string (info->receive_delay));
1532 }
1533
1534
1535 /**
1536  * Function called with a textual representation of an address.  This
1537  * function will be called several times with different possible
1538  * textual representations, and a last time with @a address being NULL
1539  * to signal the end of the iteration.  Note that @a address NULL
1540  * always is the last call, regardless of the value in @a res.
1541  *
1542  * @param cls closure
1543  * @param address NULL on end of iteration,
1544  *        otherwise 0-terminated printable UTF-8 string,
1545  *        in particular an empty string if @a res is #GNUNET_NO
1546  * @param res result of the address to string conversion:
1547  *        if #GNUNET_OK: conversion successful
1548  *        if #GNUNET_NO: address was invalid (or not supported)
1549  *        if #GNUNET_SYSERR: communication error (IPC error)
1550  */
1551 static void
1552 address_cb (void *cls,
1553             const char *address,
1554             int res)
1555 {
1556   struct PluginMonitorAddress *addr = cls;
1557
1558   if (NULL == address)
1559   {
1560     addr->asc = NULL;
1561     return;
1562   }
1563   if (NULL != addr->str)
1564     return;
1565   addr->str = GNUNET_strdup (address);
1566   print_plugin_event_info (addr,
1567                            &addr->si);
1568 }
1569
1570
1571 /**
1572  * Function called by the plugin with information about the
1573  * current sessions managed by the plugin (for monitoring).
1574  *
1575  * @param cls closure (NULL)
1576  * @param session session handle this information is about,
1577  *        NULL to indicate that we are "in sync" (initial
1578  *        iteration complete)
1579  * @param session_ctx storage location where the application
1580  *        can store data; will point to NULL on #GNUNET_TRANSPORT_SS_INIT,
1581  *        and must be reset to NULL on #GNUNET_TRANSPORT_SS_DONE
1582  * @param info information about the state of the session,
1583  *        NULL if @a session is also NULL and we are
1584  *        merely signalling that the initial iteration is over;
1585  *        NULL with @a session being non-NULL if the monitor
1586  *        was being cancelled while sessions were active
1587  */
1588 static void
1589 plugin_monitoring_cb (void *cls,
1590                       struct GNUNET_TRANSPORT_PluginSession *session,
1591                       void **session_ctx,
1592                       const struct GNUNET_TRANSPORT_SessionInfo *info)
1593 {
1594   struct PluginMonitorAddress *addr;
1595
1596   if ( (NULL == info) &&
1597        (NULL == session) )
1598     return; /* in sync with transport service */
1599   addr = *session_ctx;
1600   if (NULL == info)
1601   {
1602     if (NULL != addr)
1603     {
1604       if (NULL != addr->asc)
1605       {
1606         GNUNET_TRANSPORT_address_to_string_cancel (addr->asc);
1607         addr->asc = NULL;
1608       }
1609       GNUNET_free_non_null (addr->str);
1610       GNUNET_free (addr);
1611       *session_ctx = NULL;
1612     }
1613     return; /* shutdown */
1614   }
1615   if ( (NULL != cpid) &&
1616        (0 != memcmp (&info->address->peer,
1617                      cpid,
1618                      sizeof (struct GNUNET_PeerIdentity))) )
1619     return; /* filtered */
1620   if (NULL == addr)
1621   {
1622     addr = GNUNET_new (struct PluginMonitorAddress);
1623     addr->asc = GNUNET_TRANSPORT_address_to_string (cfg,
1624                                                     info->address,
1625                                                     numeric,
1626                                                     GNUNET_TIME_UNIT_FOREVER_REL,
1627                                                     &address_cb,
1628                                                     addr);
1629     *session_ctx = addr;
1630   }
1631   if (NULL == addr->str)
1632     addr->si = *info;
1633   else
1634     print_plugin_event_info (addr,
1635                              info);
1636   if (GNUNET_TRANSPORT_SS_DONE == info->state)
1637   {
1638     if (NULL != addr->asc)
1639     {
1640       GNUNET_TRANSPORT_address_to_string_cancel (addr->asc);
1641       addr->asc = NULL;
1642     }
1643     GNUNET_free_non_null (addr->str);
1644     GNUNET_free (addr);
1645     *session_ctx = NULL;
1646   }
1647 }
1648
1649
1650 /**
1651  * Function called with information about a peers
1652  *
1653  * @param cls closure, NULL
1654  * @param peer identity of the peer, NULL for final callback when operation done
1655  * @param address binary address used to communicate with this peer,
1656  *  NULL on disconnect or when done
1657  * @param state current state this peer is in
1658  * @param state_timeout time out for the current state
1659  */
1660 static void
1661 process_peer_monitoring_cb (void *cls,
1662                             const struct GNUNET_PeerIdentity *peer,
1663                             const struct GNUNET_HELLO_Address *address,
1664                             enum GNUNET_TRANSPORT_PeerState state,
1665                             struct GNUNET_TIME_Absolute state_timeout)
1666 {
1667   struct MonitoredPeer *m;
1668
1669   if (NULL == peer)
1670   {
1671     FPRINTF (stdout,
1672              "%s",
1673              _("Monitor disconnected from transport service. Reconnecting.\n"));
1674     return;
1675   }
1676
1677   if (NULL != op_timeout)
1678     GNUNET_SCHEDULER_cancel (op_timeout);
1679   op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1680                                              &operation_timeout,
1681                                              NULL);
1682
1683   if (NULL == (m = GNUNET_CONTAINER_multipeermap_get (monitored_peers,
1684                                                       peer)))
1685   {
1686     m = GNUNET_new (struct MonitoredPeer);
1687     GNUNET_CONTAINER_multipeermap_put (monitored_peers,
1688                                        peer,
1689                                        m,
1690                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1691   }
1692   else
1693   {
1694     if ( (m->state == state) &&
1695          (m->state_timeout.abs_value_us == state_timeout.abs_value_us) &&
1696          (NULL == address) &&
1697          (NULL == m->address) )
1698     {
1699       return; /* No real change */
1700     }
1701     if ( (m->state == state) &&
1702          (NULL != address) &&
1703          (NULL != m->address) &&
1704          (0 == GNUNET_HELLO_address_cmp(m->address, address)) )
1705       return; /* No real change */
1706   }
1707
1708   if (NULL != m->address)
1709   {
1710     GNUNET_free (m->address);
1711     m->address = NULL;
1712   }
1713   if (NULL != address)
1714     m->address = GNUNET_HELLO_address_copy (address);
1715   m->state = state;
1716   m->state_timeout = state_timeout;
1717
1718   if (NULL != address)
1719     resolve_peer_address (m->address,
1720                           numeric,
1721                           m->state,
1722                           m->state_timeout);
1723   else
1724     print_info (peer,
1725                 NULL,
1726                 NULL,
1727                 m->state,
1728                 m->state_timeout);
1729 }
1730
1731
1732 /**
1733  * Function called with the transport service checking if we
1734  * want to blacklist a peer. Return #GNUNET_SYSERR for the
1735  * peer that we should disconnect from.
1736  *
1737  * @param cls NULL
1738  * @param cpid peer to check blacklisting for
1739  * @return #GNUNET_OK if the connection is allowed, #GNUNET_SYSERR if not
1740  */
1741 static int
1742 blacklist_cb (void *cls,
1743               const struct GNUNET_PeerIdentity *cpid)
1744 {
1745   if (0 == memcmp (cpid,
1746                    &pid,
1747                    sizeof (struct GNUNET_PeerIdentity)))
1748     return GNUNET_SYSERR;
1749   return GNUNET_OK;
1750 }
1751
1752
1753 /**
1754  * Function called with the result of the check if the 'transport'
1755  * service is running.
1756  *
1757  * @param cls closure with our configuration
1758  * @param result #GNUNET_YES if transport is running
1759  */
1760 static void
1761 testservice_task (void *cls,
1762                   int result)
1763 {
1764   int counter = 0;
1765   ret = 1;
1766
1767   if (GNUNET_YES != result)
1768   {
1769     FPRINTF (stderr, _("Service `%s' is not running\n"), "transport");
1770     return;
1771   }
1772
1773   if ( (NULL != cpid) &&
1774        (GNUNET_OK !=
1775         GNUNET_CRYPTO_eddsa_public_key_from_string (cpid,
1776                                                     strlen (cpid),
1777                                                     &pid.public_key)))
1778   {
1779     FPRINTF (stderr,
1780              _("Failed to parse peer identity `%s'\n"),
1781              cpid);
1782     return;
1783   }
1784
1785   counter = benchmark_send + benchmark_receive + iterate_connections
1786       + monitor_connections + monitor_connects + do_disconnect +
1787       + iterate_validation + monitor_validation + monitor_plugins;
1788
1789   if (1 < counter)
1790   {
1791     FPRINTF (stderr,
1792              _("Multiple operations given. Please choose only one operation: %s, %s, %s, %s, %s, %s %s\n"),
1793              "disconnect", "benchmark send", "benchmark receive", "information",
1794              "monitor", "events", "plugins");
1795     return;
1796   }
1797   if (0 == counter)
1798   {
1799     FPRINTF (stderr,
1800         _("No operation given. Please choose one operation: %s, %s, %s, %s, %s, %s, %s\n"),
1801              "disconnect", "benchmark send", "benchmark receive", "information",
1802              "monitor", "events", "plugins");
1803     return;
1804   }
1805
1806   if (do_disconnect) /* -D: Disconnect from peer */
1807   {
1808     if (NULL == cpid)
1809     {
1810       FPRINTF (stderr,
1811                _("Option `%s' makes no sense without option `%s'.\n"),
1812                "-D", "-p");
1813       ret = 1;
1814       return;
1815     }
1816     blacklist = GNUNET_TRANSPORT_blacklist (cfg,
1817                                             &blacklist_cb,
1818                                             NULL);
1819     if (NULL == blacklist)
1820     {
1821       FPRINTF (stderr,
1822                "%s",
1823                _("Failed to connect to transport service for disconnection\n"));
1824       ret = 1;
1825       return;
1826     }
1827     FPRINTF (stdout,
1828              "%s",
1829              _("Blacklisting request in place, stop with CTRL-C\n"));
1830   }
1831   else if (benchmark_send) /* -s: Benchmark sending */
1832   {
1833     if (NULL == cpid)
1834     {
1835       FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
1836           "-s", "-p");
1837       ret = 1;
1838       return;
1839     }
1840     handle = GNUNET_TRANSPORT_connect (cfg,
1841                                        NULL,
1842                                        NULL,
1843                                        &notify_receive,
1844                                        &notify_connect,
1845                                        &notify_disconnect);
1846     if (NULL == handle)
1847     {
1848       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n"));
1849       ret = 1;
1850       return;
1851     }
1852     start_time = GNUNET_TIME_absolute_get ();
1853     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1854                                                &operation_timeout,
1855                                                NULL);
1856   }
1857   else if (benchmark_receive) /* -b: Benchmark receiving */
1858   {
1859     handle = GNUNET_TRANSPORT_connect (cfg,
1860                                        NULL,
1861                                        NULL,
1862                                        &notify_receive,
1863                                        NULL,
1864                                        NULL);
1865     if (NULL == handle)
1866     {
1867       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n"));
1868       ret = 1;
1869       return;
1870     }
1871     if (verbosity > 0)
1872       FPRINTF (stdout, "%s", _("Starting to receive benchmark data\n"));
1873     start_time = GNUNET_TIME_absolute_get ();
1874
1875   }
1876   else if (iterate_connections) /* -i: List information about peers once */
1877   {
1878     pic = GNUNET_TRANSPORT_monitor_peers (cfg, (NULL == cpid) ? NULL : &pid,
1879         GNUNET_YES, TIMEOUT, &process_peer_iteration_cb, (void *) cfg);
1880     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1881                                                &operation_timeout,
1882                                                NULL);
1883   }
1884   else if (monitor_connections) /* -m: List information about peers continuously */
1885   {
1886     monitored_peers = GNUNET_CONTAINER_multipeermap_create (10,
1887                                                             GNUNET_NO);
1888     pic = GNUNET_TRANSPORT_monitor_peers (cfg,
1889                                           (NULL == cpid) ? NULL : &pid,
1890                                           GNUNET_NO,
1891                                           TIMEOUT,
1892                                           &process_peer_monitoring_cb, NULL);
1893   }
1894   else if (monitor_plugins) /* -P: List information about plugins continuously */
1895   {
1896     monitored_plugins = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1897     pm = GNUNET_TRANSPORT_monitor_plugins (cfg,
1898                                            &plugin_monitoring_cb,
1899                                            NULL);
1900   }
1901   else if (iterate_validation) /* -d: Print information about validations */
1902   {
1903     vic = GNUNET_TRANSPORT_monitor_validation_entries (cfg,
1904                                                        (NULL == cpid) ? NULL : &pid,
1905                                                        GNUNET_YES, TIMEOUT,
1906                                                        &process_validation_cb, (void *) cfg);
1907   }
1908   else if (monitor_validation) /* -f: Print information about validations continuously */
1909   {
1910     vic = GNUNET_TRANSPORT_monitor_validation_entries (cfg,
1911                                                        (NULL == cpid) ? NULL : &pid,
1912                                                        GNUNET_NO, TIMEOUT,
1913                                                        &process_validation_cb, (void *) cfg);
1914   }
1915   else if (monitor_connects) /* -e : Monitor (dis)connect events continuously */
1916   {
1917     monitor_connect_counter = 0;
1918     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, NULL,
1919                                        &monitor_notify_connect,
1920                                        &monitor_notify_disconnect);
1921     if (NULL == handle)
1922     {
1923       FPRINTF (stderr,
1924                "%s",
1925                _("Failed to connect to transport service\n"));
1926       ret = 1;
1927       return;
1928     }
1929     ret = 0;
1930   }
1931   else
1932   {
1933     GNUNET_break(0);
1934     return;
1935   }
1936   
1937   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1938                                  NULL);
1939 }
1940
1941
1942 /**
1943  * Main function that will be run by the scheduler.
1944  *
1945  * @param cls closure
1946  * @param args remaining command-line arguments
1947  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1948  * @param mycfg configuration
1949  */
1950 static void
1951 run (void *cls,
1952      char * const *args,
1953      const char *cfgfile,
1954      const struct GNUNET_CONFIGURATION_Handle *mycfg)
1955 {
1956   cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
1957   if (test_configuration)
1958   {
1959     do_test_configuration (cfg);
1960     return;
1961   }
1962   GNUNET_CLIENT_service_test ("transport", cfg, GNUNET_TIME_UNIT_SECONDS,
1963       &testservice_task, (void *) cfg);
1964 }
1965
1966 int
1967 main (int argc, char * const *argv)
1968 {
1969   int res;
1970   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1971     { 'a', "all", NULL,
1972       gettext_noop ("print information for all peers (instead of only connected peers)"),
1973       0, &GNUNET_GETOPT_set_one, &iterate_all },
1974     { 'b', "benchmark", NULL,
1975       gettext_noop ("measure how fast we are receiving data from all peers (until CTRL-C)"),
1976       0, &GNUNET_GETOPT_set_one, &benchmark_receive },
1977     { 'D', "disconnect",
1978       NULL, gettext_noop ("disconnect to a peer"), 0,
1979       &GNUNET_GETOPT_set_one, &do_disconnect },
1980     { 'd', "validation", NULL,
1981       gettext_noop ("print information for all pending validations "),
1982       0, &GNUNET_GETOPT_set_one, &iterate_validation },
1983     { 'f', "monitorvalidation", NULL,
1984       gettext_noop ("print information for all pending validations continuously"),
1985       0, &GNUNET_GETOPT_set_one, &monitor_validation },
1986     { 'i', "information", NULL,
1987       gettext_noop ("provide information about all current connections (once)"),
1988       0, &GNUNET_GETOPT_set_one, &iterate_connections },
1989     { 'm', "monitor", NULL,
1990       gettext_noop ("provide information about all current connections (continuously)"),
1991       0, &GNUNET_GETOPT_set_one, &monitor_connections },
1992     { 'e', "events", NULL,
1993       gettext_noop ("provide information about all connects and disconnect events (continuously)"),
1994       0, &GNUNET_GETOPT_set_one, &monitor_connects },
1995     { 'n', "numeric",
1996       NULL, gettext_noop ("do not resolve hostnames"), 0,
1997       &GNUNET_GETOPT_set_one, &numeric },
1998     { 'p', "peer", "PEER",
1999       gettext_noop ("peer identity"), 1, &GNUNET_GETOPT_set_string,
2000       &cpid },
2001     { 'P', "plugins", NULL,
2002       gettext_noop ("monitor plugin sessions"), 0, &GNUNET_GETOPT_set_one,
2003       &monitor_plugins },
2004     { 's', "send", NULL, gettext_noop
2005       ("send data for benchmarking to the other peer (until CTRL-C)"), 0,
2006       &GNUNET_GETOPT_set_one, &benchmark_send },
2007     { 't', "test", NULL,
2008       gettext_noop ("test transport configuration (involves external server)"),
2009       0, &GNUNET_GETOPT_set_one, &test_configuration },
2010     GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
2011     GNUNET_GETOPT_OPTION_END
2012   };
2013
2014   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
2015     return 2;
2016
2017   res = GNUNET_PROGRAM_run (argc, argv,
2018                             "gnunet-transport",
2019                             gettext_noop ("Direct access to transport service."),
2020                             options,
2021                             &run, NULL);
2022   GNUNET_free((void *) argv);
2023   if (GNUNET_OK == res)
2024     return ret;
2025   return 1;
2026 }
2027
2028 /* end of gnunet-transport.c */