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