f90ce90056eed053f4c370b5f7ee8702ba2ced4d
[oweals/gnunet.git] / src / transport / gnunet-transport.c
1 /*
2  This file is part of GNUnet.
3  (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
944     /* done */
945     vic = NULL;
946     if (NULL != end)
947       GNUNET_SCHEDULER_cancel (end);
948     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
949     return;
950   }
951   if (NULL == address)
952   {
953     /* invalid response */
954     vic = NULL;
955     if (NULL != end)
956       GNUNET_SCHEDULER_cancel (end);
957     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
958     return;
959   }
960   resolve_validation_address (address,
961                               numeric,
962                               last_validation,
963                               valid_until,
964                               next_validation,
965                               state);
966 }
967
968
969 static void
970 run_nat_test ()
971 {
972   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
973               "Running test for plugin `%s' using bind port %u and advertised port %u \n",
974               head->name,
975               (uint16_t) head->bnd_port,
976               (uint16_t) head->adv_port);
977
978   head->tst = GNUNET_NAT_test_start (cfg,
979       (0 == strcasecmp (head->name, "udp")) ? GNUNET_NO : GNUNET_YES,
980       (uint16_t) head->bnd_port,
981       (uint16_t) head->adv_port,
982       TIMEOUT,
983       &result_callback, head);
984 }
985
986
987 /**
988  * Test our plugin's configuration (NAT traversal, etc.).
989  *
990  * @param cfg configuration to test
991  */
992 static void
993 do_test_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
994 {
995   char *plugins;
996   char *tok;
997   unsigned long long bnd_port;
998   unsigned long long adv_port;
999   struct TestContext *tc;
1000   char *binary;
1001
1002   if (GNUNET_OK
1003       != GNUNET_CONFIGURATION_get_value_string (cfg, "transport", "plugins",
1004           &plugins))
1005   {
1006     FPRINTF (stderr, "%s", _
1007     ("No transport plugins configured, peer will never communicate\n"));
1008     ret = 4;
1009     return;
1010   }
1011
1012   for (tok = strtok (plugins, " "); tok != NULL ; tok = strtok (NULL, " "))
1013   {
1014     char section[12 + strlen (tok)];
1015     GNUNET_snprintf (section, sizeof(section), "transport-%s", tok);
1016     if (GNUNET_OK
1017         != GNUNET_CONFIGURATION_get_value_number (cfg, section, "PORT",
1018             &bnd_port))
1019     {
1020       FPRINTF (stderr,
1021           _("No port configured for plugin `%s', cannot test it\n"), tok);
1022       continue;
1023     }
1024     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, section,
1025             "ADVERTISED_PORT", &adv_port))
1026       adv_port = bnd_port;
1027
1028     tc = GNUNET_new (struct TestContext);
1029     tc->name = GNUNET_strdup (tok);
1030     tc->adv_port = adv_port;
1031     tc->bnd_port = bnd_port;
1032     GNUNET_CONTAINER_DLL_insert_tail (head, tail, tc);
1033   }
1034   GNUNET_free(plugins);
1035
1036   if ((NULL != head) && (NULL == resolver))
1037   {
1038     binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
1039     resolver = GNUNET_OS_start_process (GNUNET_YES,
1040                                         GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
1041                                         NULL, NULL, NULL,
1042                                         binary,
1043                                         "gnunet-service-resolver", NULL);
1044     if (NULL == resolver)
1045     {
1046       FPRINTF (stderr, _("Failed to start resolver!\n"));
1047       return;
1048     }
1049
1050     GNUNET_free(binary);
1051     GNUNET_RESOLVER_connect (cfg);
1052     run_nat_test ();
1053   }
1054 }
1055
1056
1057 /**
1058  * Function called to notify a client about the socket
1059  * begin ready to queue more data.  @a buf will be
1060  * NULL and @a size zero if the socket was closed for
1061  * writing in the meantime.
1062  *
1063  * @param cls closure
1064  * @param size number of bytes available in @a buf
1065  * @param buf where the callee should write the message
1066  * @return number of bytes written to @a buf
1067  */
1068 static size_t
1069 transmit_data (void *cls,
1070                size_t size,
1071                void *buf)
1072 {
1073   struct GNUNET_MessageHeader *m = buf;
1074
1075   if ((NULL == buf) || (0 == size))
1076   {
1077     th = NULL;
1078     return 0;
1079   }
1080
1081   GNUNET_assert(size >= sizeof(struct GNUNET_MessageHeader));
1082   GNUNET_assert(size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
1083   m->size = ntohs (size);
1084   m->type = ntohs (GNUNET_MESSAGE_TYPE_DUMMY);
1085   memset (&m[1], 52, size - sizeof(struct GNUNET_MessageHeader));
1086   traffic_sent += size;
1087   th = GNUNET_TRANSPORT_notify_transmit_ready (handle, &pid,
1088                                                BLOCKSIZE * 1024,
1089                                                GNUNET_TIME_UNIT_FOREVER_REL,
1090                                                &transmit_data, NULL);
1091   if (verbosity > 0)
1092     FPRINTF (stdout, _("Transmitting %u bytes to %s\n"), (unsigned int) size,
1093         GNUNET_i2s (&pid));
1094   return size;
1095 }
1096
1097
1098 /**
1099  * Function called to notify transport users that another
1100  * peer connected to us.
1101  *
1102  * @param cls closure
1103  * @param peer the peer that connected
1104  */
1105 static void
1106 notify_connect (void *cls,
1107                 const struct GNUNET_PeerIdentity *peer)
1108 {
1109   if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
1110     return;
1111   ret = 0;
1112   if (try_connect)
1113   {
1114     /* all done, terminate instantly */
1115     FPRINTF (stdout, _("Successfully connected to `%s'\n"),
1116         GNUNET_i2s_full (peer));
1117     ret = 0;
1118
1119     if (NULL != op_timeout)
1120     {
1121       GNUNET_SCHEDULER_cancel (op_timeout);
1122       op_timeout = NULL;
1123     }
1124
1125     if (NULL != end)
1126       GNUNET_SCHEDULER_cancel (end);
1127     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1128     return;
1129   }
1130   if (benchmark_send)
1131   {
1132     if (NULL != op_timeout)
1133     {
1134       GNUNET_SCHEDULER_cancel (op_timeout);
1135       op_timeout = NULL;
1136     }
1137     if (verbosity > 0)
1138       FPRINTF (stdout,
1139           _("Successfully connected to `%s', starting to send benchmark data in %u Kb blocks\n"),
1140           GNUNET_i2s (&pid), BLOCKSIZE);
1141     start_time = GNUNET_TIME_absolute_get ();
1142     if (NULL == th)
1143       th = GNUNET_TRANSPORT_notify_transmit_ready (handle, peer,
1144                                                    BLOCKSIZE * 1024,
1145                                                    GNUNET_TIME_UNIT_FOREVER_REL,
1146                                                    &transmit_data,
1147                                                    NULL);
1148     else
1149       GNUNET_break(0);
1150     return;
1151   }
1152 }
1153
1154
1155 /**
1156  * Function called to notify transport users that another
1157  * peer disconnected from us.
1158  *
1159  * @param cls closure
1160  * @param peer the peer that disconnected
1161  */
1162 static void
1163 notify_disconnect (void *cls,
1164                    const struct GNUNET_PeerIdentity *peer)
1165 {
1166   if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
1167     return;
1168
1169   if (try_disconnect)
1170   {
1171     /* all done, terminate instantly */
1172     FPRINTF (stdout, _("Successfully disconnected from `%s'\n"),
1173         GNUNET_i2s_full (peer));
1174     ret = 0;
1175
1176     if (NULL != op_timeout)
1177     {
1178       GNUNET_SCHEDULER_cancel (op_timeout);
1179       op_timeout = NULL;
1180     }
1181
1182     if (NULL != end)
1183       GNUNET_SCHEDULER_cancel (end);
1184     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1185     return;
1186   }
1187
1188   if (NULL != th)
1189   {
1190     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
1191     th = NULL;
1192   }
1193   if (benchmark_send)
1194   {
1195     FPRINTF (stdout, _("Disconnected from peer `%s' while benchmarking\n"),
1196         GNUNET_i2s (&pid));
1197     if (NULL != end)
1198       GNUNET_SCHEDULER_cancel (end);
1199     return;
1200   }
1201 }
1202
1203
1204 /**
1205  * Function called to notify transport users that another
1206  * peer connected to us.
1207  *
1208  * @param cls closure
1209  * @param peer the peer that connected
1210  */
1211 static void
1212 monitor_notify_connect (void *cls,
1213                         const struct GNUNET_PeerIdentity *peer)
1214 {
1215   monitor_connect_counter++;
1216   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1217   const char *now_str = GNUNET_STRINGS_absolute_time_to_string (now);
1218
1219   FPRINTF (stdout,
1220            _("%24s: %-17s %4s   (%u connections in total)\n"),
1221            now_str,
1222            _("Connected to"),
1223            GNUNET_i2s (peer),
1224            monitor_connect_counter);
1225 }
1226
1227
1228 /**
1229  * Function called to notify transport users that another
1230  * peer disconnected from us.
1231  *
1232  * @param cls closure
1233  * @param peer the peer that disconnected
1234  */
1235 static void
1236 monitor_notify_disconnect (void *cls,
1237                            const struct GNUNET_PeerIdentity *peer)
1238 {
1239   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1240   const char *now_str = GNUNET_STRINGS_absolute_time_to_string (now);
1241
1242   GNUNET_assert(monitor_connect_counter > 0);
1243   monitor_connect_counter--;
1244
1245   FPRINTF (stdout,
1246            _("%24s: %-17s %4s   (%u connections in total)\n"),
1247            now_str,
1248            _("Disconnected from"),
1249            GNUNET_i2s (peer),
1250            monitor_connect_counter);
1251 }
1252
1253
1254 /**
1255  * Function called by the transport for each received message.
1256  *
1257  * @param cls closure
1258  * @param peer (claimed) identity of the other peer
1259  * @param message the message
1260  */
1261 static void
1262 notify_receive (void *cls,
1263                 const struct GNUNET_PeerIdentity *peer,
1264                 const struct GNUNET_MessageHeader *message)
1265 {
1266   if (benchmark_receive)
1267   {
1268     if (GNUNET_MESSAGE_TYPE_DUMMY != ntohs (message->type))
1269       return;
1270     if (verbosity > 0)
1271       FPRINTF (stdout,
1272                _("Received %u bytes from %s\n"),
1273                (unsigned int) ntohs (message->size),
1274                GNUNET_i2s (peer));
1275
1276     if (traffic_received == 0)
1277       start_time = GNUNET_TIME_absolute_get ();
1278     traffic_received += ntohs (message->size);
1279     return;
1280   }
1281 }
1282
1283
1284 static void
1285 resolve_peer_address (const struct GNUNET_PeerIdentity *id,
1286                       const struct GNUNET_HELLO_Address *address,
1287                       int numeric,
1288                       enum GNUNET_TRANSPORT_PeerState state,
1289                       struct GNUNET_TIME_Absolute state_timeout);
1290
1291
1292 static void
1293 print_info (const struct GNUNET_PeerIdentity *id,
1294             const char *transport,
1295             const char *addr,
1296             enum GNUNET_TRANSPORT_PeerState state,
1297             struct GNUNET_TIME_Absolute state_timeout)
1298 {
1299
1300   if ( ((GNUNET_YES == iterate_connections) && (GNUNET_YES == iterate_all)) ||
1301        (GNUNET_YES == monitor_connections))
1302   {
1303     FPRINTF (stdout,
1304              _("Peer `%s': %s %s in state `%s' until %s\n"),
1305              GNUNET_i2s (id),
1306              (NULL == transport) ? "<none>" : transport,
1307              (NULL == transport) ? "<none>" : addr,
1308              GNUNET_TRANSPORT_ps2s (state),
1309              GNUNET_STRINGS_absolute_time_to_string (state_timeout));
1310   }
1311   else if ( (GNUNET_YES == iterate_connections) &&
1312              (GNUNET_TRANSPORT_is_connected(state)))
1313   {
1314     /* Only connected peers, skip state */
1315     FPRINTF (stdout,
1316              _("Peer `%s': %s %s\n"),
1317              GNUNET_i2s (id),
1318              transport,
1319              addr);
1320   }
1321 }
1322
1323
1324 /**
1325  * Function called with a textual representation of an address.  This
1326  * function will be called several times with different possible
1327  * textual representations, and a last time with @a address being NULL
1328  * to signal the end of the iteration.  Note that @a address NULL
1329  * always is the last call, regardless of the value in @a res.
1330  *
1331  * @param cls closure
1332  * @param address NULL on end of iteration,
1333  *        otherwise 0-terminated printable UTF-8 string,
1334  *        in particular an empty string if @a res is #GNUNET_NO
1335  * @param res result of the address to string conversion:
1336  *        if #GNUNET_OK: conversion successful
1337  *        if #GNUNET_NO: address was invalid (or not supported)
1338  *        if #GNUNET_SYSERR: communication error (IPC error)
1339  */
1340 static void
1341 process_peer_string (void *cls,
1342                      const char *address,
1343                      int res)
1344 {
1345   struct PeerResolutionContext *rc = cls;
1346
1347   if (NULL != address)
1348   {
1349     if (GNUNET_SYSERR == res)
1350     {
1351       FPRINTF (stderr,
1352                "Failed to convert address for peer `%s' plugin `%s' length %u to string \n",
1353                GNUNET_i2s (&rc->id),
1354                rc->addrcp->transport_name,
1355                (unsigned int) rc->addrcp->address_length);
1356       print_info (&rc->id,
1357                   rc->transport,
1358                   NULL,
1359                   rc->state,
1360                   rc->state_timeout);
1361       rc->printed = GNUNET_YES;
1362       return;
1363     }
1364     if (GNUNET_OK == res)
1365     {
1366       print_info (&rc->id,
1367                   rc->transport,
1368                   address,
1369                   rc->state,
1370                   rc->state_timeout);
1371       rc->printed = GNUNET_YES;
1372       return; /* Wait for done call */
1373     }
1374     /* GNUNET_NO == res: ignore, was simply not supported */
1375     return;
1376   }
1377   /* NULL == address, last call, we are done */
1378
1379   GNUNET_assert (address_resolutions > 0);
1380   address_resolutions--;
1381   if (GNUNET_NO == rc->printed)
1382   {
1383     if (numeric == GNUNET_NO)
1384     {
1385       /* Failed to resolve address, try numeric lookup
1386          (note: this should not be needed, as transport
1387          should fallback to numeric conversion if DNS takes
1388          too long) */
1389       resolve_peer_address (&rc->id,
1390                             rc->addrcp,
1391                             GNUNET_YES,
1392                             rc->state,
1393                             rc->state_timeout);
1394     }
1395     else
1396     {
1397       print_info (&rc->id,
1398                   rc->transport,
1399                   NULL,
1400                   rc->state,
1401                   rc->state_timeout);
1402     }
1403   }
1404   GNUNET_free (rc->transport);
1405   GNUNET_free (rc->addrcp);
1406   GNUNET_CONTAINER_DLL_remove (rc_head, rc_tail, rc);
1407   GNUNET_free (rc);
1408   if ((0 == address_resolutions) && (iterate_connections))
1409   {
1410     if (NULL != end)
1411     {
1412       GNUNET_SCHEDULER_cancel (end);
1413       end = NULL;
1414     }
1415     if (NULL != op_timeout)
1416     {
1417       GNUNET_SCHEDULER_cancel (op_timeout);
1418       op_timeout = NULL;
1419     }
1420     ret = 0;
1421     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1422   }
1423 }
1424
1425
1426 static void
1427 resolve_peer_address (const struct GNUNET_PeerIdentity *id,
1428                       const struct GNUNET_HELLO_Address *address,
1429                       int numeric,
1430                       enum GNUNET_TRANSPORT_PeerState state,
1431                       struct GNUNET_TIME_Absolute state_timeout)
1432 {
1433   struct PeerResolutionContext *rc;
1434
1435   rc = GNUNET_new (struct PeerResolutionContext);
1436   GNUNET_assert(NULL != rc);
1437   GNUNET_CONTAINER_DLL_insert(rc_head, rc_tail, rc);
1438   address_resolutions++;
1439
1440   rc->id = *id;
1441   rc->transport = GNUNET_strdup(address->transport_name);
1442   rc->addrcp = GNUNET_HELLO_address_copy (address);
1443   rc->printed = GNUNET_NO;
1444   rc->state = state;
1445   rc->state_timeout = state_timeout;
1446   /* Resolve address to string */
1447   rc->asc = GNUNET_TRANSPORT_address_to_string (cfg,
1448                                                 address,
1449                                                 numeric,
1450                                                 RESOLUTION_TIMEOUT,
1451                                                 &process_peer_string, rc);
1452 }
1453
1454
1455 /**
1456  * Function called with information about a peers during a one shot iteration
1457  *
1458  * @param cls closure
1459  * @param peer identity of the peer, NULL for final callback when operation done
1460  * @param address binary address used to communicate with this peer,
1461  *  NULL on disconnect or when done
1462  * @param state current state this peer is in
1463  * @param state_timeout time out for the current state
1464  */
1465 static void
1466 process_peer_iteration_cb (void *cls,
1467                            const struct GNUNET_PeerIdentity *peer,
1468                            const struct GNUNET_HELLO_Address *address,
1469                            enum GNUNET_TRANSPORT_PeerState state,
1470                            struct GNUNET_TIME_Absolute state_timeout)
1471 {
1472   if (NULL == peer)
1473   {
1474     /* done */
1475     address_resolution_in_progress = GNUNET_NO;
1476     pic = NULL;
1477     if (NULL != end)
1478       GNUNET_SCHEDULER_cancel (end);
1479     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1480     return;
1481   }
1482
1483   if ( (GNUNET_NO == iterate_all) &&
1484        (GNUNET_NO == GNUNET_TRANSPORT_is_connected(state)))
1485       return; /* Display only connected peers */
1486
1487   if (NULL != op_timeout)
1488     GNUNET_SCHEDULER_cancel (op_timeout);
1489   op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1490                                              &operation_timeout,
1491                                              NULL);
1492
1493   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1494               "Received address for peer `%s': %s\n",
1495               GNUNET_i2s (peer),
1496               address->transport_name);
1497
1498   if (NULL != address)
1499     resolve_peer_address (peer, address, numeric, state, state_timeout);
1500   else
1501     print_info (peer, NULL, NULL, state, state_timeout);
1502 }
1503
1504
1505 /**
1506  * Context for address resolution by #plugin_monitoring_cb().
1507  */
1508 struct PluginMonitorAddress
1509 {
1510
1511   /**
1512    * Ongoing resolution request.
1513    */
1514   struct GNUNET_TRANSPORT_AddressToStringContext *asc;
1515
1516   /**
1517    * Resolved address as string.
1518    */
1519   char *str;
1520 };
1521
1522
1523 /**
1524  * Function called with a textual representation of an address.  This
1525  * function will be called several times with different possible
1526  * textual representations, and a last time with @a address being NULL
1527  * to signal the end of the iteration.  Note that @a address NULL
1528  * always is the last call, regardless of the value in @a res.
1529  *
1530  * @param cls closure
1531  * @param address NULL on end of iteration,
1532  *        otherwise 0-terminated printable UTF-8 string,
1533  *        in particular an empty string if @a res is #GNUNET_NO
1534  * @param res result of the address to string conversion:
1535  *        if #GNUNET_OK: conversion successful
1536  *        if #GNUNET_NO: address was invalid (or not supported)
1537  *        if #GNUNET_SYSERR: communication error (IPC error)
1538  */
1539 static void
1540 address_cb (void *cls,
1541             const char *address,
1542             int res)
1543 {
1544   struct PluginMonitorAddress *addr = cls;
1545
1546   if (NULL == address)
1547   {
1548     addr->asc = NULL;
1549     return;
1550   }
1551   if (NULL != addr->str)
1552     return;
1553   addr->str = GNUNET_strdup (address);
1554 }
1555
1556
1557 /**
1558  * Function called by the plugin with information about the
1559  * current sessions managed by the plugin (for monitoring).
1560  *
1561  * @param cls closure (NULL)
1562  * @param session session handle this information is about,
1563  *        NULL to indicate that we are "in sync" (initial
1564  *        iteration complete)
1565  * @param session_ctx storage location where the application
1566  *        can store data; will point to NULL on #GNUNET_TRANSPORT_SS_INIT,
1567  *        and must be reset to NULL on #GNUNET_TRANSPORT_SS_DONE
1568  * @param info information about the state of the session,
1569  *        NULL if @a session is also NULL and we are
1570  *        merely signalling that the initial iteration is over;
1571  *        NULL with @a session being non-NULL if the monitor
1572  *        was being cancelled while sessions were active
1573  */
1574 static void
1575 plugin_monitoring_cb (void *cls,
1576                       struct GNUNET_TRANSPORT_PluginSession *session,
1577                       void **session_ctx,
1578                       const struct GNUNET_TRANSPORT_SessionInfo *info)
1579 {
1580   const char *state;
1581   struct PluginMonitorAddress *addr;
1582
1583   if ( (NULL == info) &&
1584        (NULL == session) )
1585     return; /* in sync with transport service */
1586   addr = *session_ctx;
1587   if (NULL == info)
1588   {
1589     if (NULL != addr)
1590     {
1591       if (NULL != addr->asc)
1592       {
1593         GNUNET_TRANSPORT_address_to_string_cancel (addr->asc);
1594         addr->asc = NULL;
1595       }
1596       GNUNET_free_non_null (addr->str);
1597       GNUNET_free (addr);
1598       *session_ctx = NULL;
1599     }
1600     return; /* shutdown */
1601   }
1602   if ( (NULL != cpid) &&
1603        (0 != memcmp (&info->address->peer,
1604                      cpid,
1605                      sizeof (struct GNUNET_PeerIdentity))) )
1606     return; /* filtered */
1607   if (NULL == addr)
1608   {
1609     addr = GNUNET_new (struct PluginMonitorAddress);
1610     addr->asc = GNUNET_TRANSPORT_address_to_string (cfg,
1611                                                     info->address,
1612                                                     GNUNET_NO,
1613                                                     GNUNET_TIME_UNIT_FOREVER_REL,
1614                                                     &address_cb,
1615                                                     addr);
1616     *session_ctx = addr;
1617   }
1618   switch (info->state)
1619   {
1620   case GNUNET_TRANSPORT_SS_INIT:
1621     state = "INIT";
1622     break;
1623   case GNUNET_TRANSPORT_SS_HANDSHAKE:
1624     state = "HANDSHAKE";
1625     break;
1626   case GNUNET_TRANSPORT_SS_UP:
1627     state = "UP";
1628     break;
1629   case GNUNET_TRANSPORT_SS_UPDATE:
1630     state = "UPDATE";
1631     break;
1632   case GNUNET_TRANSPORT_SS_DONE:
1633     state = "DONE";
1634     break;
1635   default:
1636     state = "UNKNOWN";
1637     break;
1638   }
1639   fprintf (stdout,
1640            "%s: %s %s (# %u/%u b) blocked until %s timeout in %s [%s]\n",
1641            GNUNET_i2s (&info->address->peer),
1642            addr->str,
1643            (info->is_inbound == GNUNET_YES) ? "<-" : ((info->is_inbound == GNUNET_NO) ? "->" : "<>"),
1644            info->num_msg_pending,
1645            info->num_bytes_pending,
1646            GNUNET_STRINGS_absolute_time_to_string (info->receive_delay),
1647            GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (info->session_timeout),
1648                                                 GNUNET_YES),
1649            state);
1650   if (GNUNET_TRANSPORT_SS_DONE == info->state)
1651   {
1652     if (NULL != addr->asc)
1653     {
1654       GNUNET_TRANSPORT_address_to_string_cancel (addr->asc);
1655       addr->asc = NULL;
1656     }
1657     GNUNET_free_non_null (addr->str);
1658     GNUNET_free (addr);
1659     *session_ctx = NULL;
1660   }
1661 }
1662
1663
1664 /**
1665  * Function called with information about a peers
1666  *
1667  * @param cls closure
1668  * @param peer identity of the peer, NULL for final callback when operation done
1669  * @param address binary address used to communicate with this peer,
1670  *  NULL on disconnect or when done
1671  * @param state current state this peer is in
1672  * @param state_timeout time out for the current state
1673  *
1674  */
1675 static void
1676 process_peer_monitoring_cb (void *cls,
1677                             const struct GNUNET_PeerIdentity *peer,
1678                             const struct GNUNET_HELLO_Address *address,
1679                             enum GNUNET_TRANSPORT_PeerState state,
1680                             struct GNUNET_TIME_Absolute state_timeout)
1681 {
1682   struct MonitoredPeer *m;
1683
1684   if (NULL == peer)
1685   {
1686     FPRINTF (stdout,
1687              "%s",
1688              _("Monitor disconnected from transport service. Reconnecting.\n"));
1689     return;
1690   }
1691
1692   if (NULL != op_timeout)
1693     GNUNET_SCHEDULER_cancel (op_timeout);
1694   op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1695                                              &operation_timeout,
1696                                              NULL);
1697
1698   if (NULL == (m = GNUNET_CONTAINER_multipeermap_get (monitored_peers, peer)))
1699   {
1700     m = GNUNET_new (struct MonitoredPeer);
1701     GNUNET_CONTAINER_multipeermap_put (monitored_peers, peer,
1702         m, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1703   }
1704   else
1705   {
1706     if ( (m->state == state) &&
1707       (m->state_timeout.abs_value_us == state_timeout.abs_value_us) &&
1708       ((NULL == address) && (NULL == m->address)))
1709     {
1710       return; /* No real change */
1711     }
1712     if ( (m->state == state) && ((NULL != address) && (NULL != m->address)) &&
1713         (0 == GNUNET_HELLO_address_cmp(m->address, address)))
1714       return; /* No real change */
1715   }
1716
1717   if (NULL != m->address)
1718   {
1719     GNUNET_free (m->address);
1720     m->address = NULL;
1721   }
1722   if (NULL != address)
1723     m->address = GNUNET_HELLO_address_copy (address);
1724   m->state = state;
1725   m->state_timeout = state_timeout;
1726
1727   if (NULL != address)
1728     resolve_peer_address (peer,
1729                           m->address,
1730                           numeric,
1731                           m->state,
1732                           m->state_timeout);
1733   else
1734     print_info (peer,
1735                 NULL,
1736                 NULL,
1737                 m->state,
1738                 m->state_timeout);
1739 }
1740
1741
1742 /**
1743  * Function called with our result of trying to connect to a peer
1744  * using the transport service. Will retry 10 times, and if we still
1745  * fail to connect terminate with an error message.
1746  *
1747  * @param cls NULL
1748  * @param result #GNUNET_OK if we connected to the service
1749  */
1750 static void
1751 try_connect_cb (void *cls,
1752                 const int result)
1753 {
1754   static int retries = 0;
1755
1756   tc_handle = NULL;
1757   if (GNUNET_OK == result)
1758     return;
1759   retries++;
1760   if (retries < 10)
1761   {
1762     tc_handle = GNUNET_TRANSPORT_try_connect (handle,
1763                                               &pid,
1764                                               &try_connect_cb,
1765                                               NULL);
1766     return;
1767   }
1768   FPRINTF (stderr,
1769            "%s",
1770            _("Failed to send connect request to transport service\n"));
1771   if (NULL != end)
1772     GNUNET_SCHEDULER_cancel (end);
1773   ret = 1;
1774   end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1775 }
1776
1777
1778 /**
1779  * Function called with our result of trying to disconnect a peer
1780  * using the transport service. Will retry 10 times, and if we still
1781  * fail to disconnect, terminate with an error message.
1782  *
1783  * @param cls NULL
1784  * @param result #GNUNET_OK if we connected to the service
1785  */
1786 static void
1787 try_disconnect_cb (void *cls,
1788                    const int result)
1789 {
1790   static int retries = 0;
1791
1792   td_handle = NULL;
1793   if (GNUNET_OK == result)
1794     return;
1795   retries++;
1796   if (retries < 10)
1797   {
1798     td_handle = GNUNET_TRANSPORT_try_disconnect (handle,
1799                                                  &pid,
1800                                                  &try_disconnect_cb,
1801                                                  NULL);
1802     return;
1803   }
1804   FPRINTF (stderr, "%s",
1805            _("Failed to send disconnect request to transport service\n"));
1806   if (NULL != end)
1807     GNUNET_SCHEDULER_cancel (end);
1808   ret = 1;
1809   end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1810 }
1811
1812
1813 /**
1814  * Function called with the result of the check if the 'transport'
1815  * service is running.
1816  *
1817  * @param cls closure with our configuration
1818  * @param result #GNUNET_YES if transport is running
1819  */
1820 static void
1821 testservice_task (void *cls,
1822                   int result)
1823 {
1824   int counter = 0;
1825   ret = 1;
1826
1827   if (GNUNET_YES != result)
1828   {
1829     FPRINTF (stderr, _("Service `%s' is not running\n"), "transport");
1830     return;
1831   }
1832
1833   if ((NULL != cpid)
1834       && (GNUNET_OK
1835           != GNUNET_CRYPTO_eddsa_public_key_from_string (cpid, strlen (cpid),
1836               &pid.public_key)))
1837   {
1838     FPRINTF (stderr, _("Failed to parse peer identity `%s'\n"), cpid);
1839     return;
1840   }
1841
1842   counter = benchmark_send + benchmark_receive + iterate_connections
1843       + monitor_connections + monitor_connects + try_connect + try_disconnect +
1844       + iterate_validation + monitor_validation + monitor_plugins;
1845
1846   if (1 < counter)
1847   {
1848     FPRINTF (stderr,
1849         _("Multiple operations given. Please choose only one operation: %s, %s, %s, %s, %s, %s %s\n"),
1850         "connect", "benchmark send", "benchmark receive", "information",
1851              "monitor", "events", "plugins");
1852     return;
1853   }
1854   if (0 == counter)
1855   {
1856     FPRINTF (stderr,
1857         _("No operation given. Please choose one operation: %s, %s, %s, %s, %s, %s, %s\n"),
1858         "connect", "benchmark send", "benchmark receive", "information",
1859              "monitor", "events", "plugins");
1860     return;
1861   }
1862
1863   if (try_connect) /* -C: Connect to peer */
1864   {
1865     if (NULL == cpid)
1866     {
1867       FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
1868           "-C", "-p");
1869       ret = 1;
1870       return;
1871     }
1872     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, &notify_receive,
1873         &notify_connect, &notify_disconnect);
1874     if (NULL == handle)
1875     {
1876       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n"));
1877       ret = 1;
1878       return;
1879     }
1880     tc_handle = GNUNET_TRANSPORT_try_connect (handle, &pid, try_connect_cb,
1881         NULL);
1882     if (NULL == tc_handle)
1883     {
1884       FPRINTF (stderr, "%s",
1885           _("Failed to send request to transport service\n"));
1886       ret = 1;
1887       return;
1888     }
1889     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1890         NULL);
1891
1892   }
1893   else if (try_disconnect) /* -D: Disconnect from peer */
1894   {
1895     if (NULL == cpid)
1896     {
1897       FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
1898           "-D", "-p");
1899       ret = 1;
1900       return;
1901     }
1902     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, &notify_receive,
1903         &notify_connect, &notify_disconnect);
1904     if (NULL == handle)
1905     {
1906       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n"));
1907       ret = 1;
1908       return;
1909     }
1910     td_handle = GNUNET_TRANSPORT_try_disconnect (handle, &pid,
1911                                                  &try_disconnect_cb,
1912                                                  NULL);
1913     if (NULL == td_handle)
1914     {
1915       FPRINTF (stderr, "%s",
1916           _("Failed to send request to transport service\n"));
1917       ret = 1;
1918       return;
1919     }
1920     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1921         NULL);
1922
1923   }
1924   else if (benchmark_send) /* -s: Benchmark sending */
1925   {
1926     if (NULL == cpid)
1927     {
1928       FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
1929           "-s", "-p");
1930       ret = 1;
1931       return;
1932     }
1933     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL,
1934                                        &notify_receive,
1935                                        &notify_connect,
1936                                        &notify_disconnect);
1937     if (NULL == handle)
1938     {
1939       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n"));
1940       ret = 1;
1941       return;
1942     }
1943     tc_handle = GNUNET_TRANSPORT_try_connect (handle,
1944                                               &pid,
1945                                               &try_connect_cb,
1946                                               NULL);
1947     if (NULL == tc_handle)
1948     {
1949       FPRINTF (stderr, "%s",
1950           _("Failed to send request to transport service\n"));
1951       ret = 1;
1952       return;
1953     }
1954     start_time = GNUNET_TIME_absolute_get ();
1955     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT,
1956                                                &operation_timeout,
1957                                                NULL);
1958   }
1959   else if (benchmark_receive) /* -b: Benchmark receiving */
1960   {
1961     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, &notify_receive, NULL,
1962         NULL);
1963     if (NULL == handle)
1964     {
1965       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n"));
1966       ret = 1;
1967       return;
1968     }
1969     if (verbosity > 0)
1970       FPRINTF (stdout, "%s", _("Starting to receive benchmark data\n"));
1971     start_time = GNUNET_TIME_absolute_get ();
1972
1973   }
1974   else if (iterate_connections) /* -i: List information about peers once */
1975   {
1976     address_resolution_in_progress = GNUNET_YES;
1977     pic = GNUNET_TRANSPORT_monitor_peers (cfg, (NULL == cpid) ? NULL : &pid,
1978         GNUNET_YES, TIMEOUT, &process_peer_iteration_cb, (void *) cfg);
1979     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1980         NULL);
1981   }
1982   else if (monitor_connections) /* -m: List information about peers continuously */
1983   {
1984     monitored_peers = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1985     address_resolution_in_progress = GNUNET_YES;
1986     pic = GNUNET_TRANSPORT_monitor_peers (cfg, (NULL == cpid) ? NULL : &pid,
1987                                           GNUNET_NO, TIMEOUT,
1988                                           &process_peer_monitoring_cb, (void *) cfg);
1989   }
1990   else if (monitor_plugins) /* -P: List information about plugins continuously */
1991   {
1992     monitored_plugins = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1993     pm = GNUNET_TRANSPORT_monitor_plugins (cfg,
1994                                            &plugin_monitoring_cb,
1995                                            NULL);
1996   }
1997   else if (iterate_validation) /* -d: Print information about validations */
1998   {
1999     vic = GNUNET_TRANSPORT_monitor_validation_entries (cfg,
2000                                                        (NULL == cpid) ? NULL : &pid,
2001                                                        GNUNET_YES, TIMEOUT,
2002                                                        &process_validation_cb, (void *) cfg);
2003   }
2004   else if (monitor_validation) /* -f: Print information about validations continuously */
2005   {
2006     vic = GNUNET_TRANSPORT_monitor_validation_entries (cfg,
2007                                                        (NULL == cpid) ? NULL : &pid,
2008                                                        GNUNET_NO, TIMEOUT,
2009                                                        &process_validation_cb, (void *) cfg);
2010   }
2011   else if (monitor_connects) /* -e : Monitor (dis)connect events continuously */
2012   {
2013     monitor_connect_counter = 0;
2014     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, NULL,
2015                                        &monitor_notify_connect,
2016                                        &monitor_notify_disconnect);
2017     if (NULL == handle)
2018     {
2019       FPRINTF (stderr,
2020                "%s",
2021                _("Failed to connect to transport service\n"));
2022       ret = 1;
2023       return;
2024     }
2025     ret = 0;
2026   }
2027   else
2028   {
2029     GNUNET_break(0);
2030     return;
2031   }
2032
2033   end = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2034                                       &shutdown_task,
2035                                       NULL);
2036 }
2037
2038
2039 /**
2040  * Main function that will be run by the scheduler.
2041  *
2042  * @param cls closure
2043  * @param args remaining command-line arguments
2044  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
2045  * @param mycfg configuration
2046  */
2047 static void
2048 run (void *cls,
2049      char * const *args,
2050      const char *cfgfile,
2051      const struct GNUNET_CONFIGURATION_Handle *mycfg)
2052 {
2053   cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
2054   if (test_configuration)
2055   {
2056     do_test_configuration (cfg);
2057     return;
2058   }
2059   GNUNET_CLIENT_service_test ("transport", cfg, GNUNET_TIME_UNIT_SECONDS,
2060       &testservice_task, (void *) cfg);
2061 }
2062
2063 int
2064 main (int argc, char * const *argv)
2065 {
2066   int res;
2067   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
2068     { 'a', "all", NULL,
2069       gettext_noop ("print information for all peers (instead of only connected peers)"),
2070       0, &GNUNET_GETOPT_set_one, &iterate_all },
2071     { 'b', "benchmark", NULL,
2072       gettext_noop ("measure how fast we are receiving data from all peers (until CTRL-C)"),
2073       0, &GNUNET_GETOPT_set_one, &benchmark_receive },
2074     { 'C', "connect",
2075       NULL, gettext_noop ("connect to a peer"), 0,
2076       &GNUNET_GETOPT_set_one, &try_connect },
2077     { 'D', "disconnect",
2078       NULL, gettext_noop ("disconnect to a peer"), 0,
2079       &GNUNET_GETOPT_set_one, &try_disconnect },
2080     { 'd', "validation", NULL,
2081       gettext_noop ("print information for all pending validations "),
2082       0, &GNUNET_GETOPT_set_one, &iterate_validation },
2083     { 'f', "monitorvalidation", NULL,
2084       gettext_noop ("print information for all pending validations continuously"),
2085       0, &GNUNET_GETOPT_set_one, &monitor_validation },
2086     { 'i', "information", NULL,
2087       gettext_noop ("provide information about all current connections (once)"),
2088       0, &GNUNET_GETOPT_set_one, &iterate_connections },
2089     { 'm', "monitor", NULL,
2090       gettext_noop ("provide information about all current connections (continuously)"),
2091       0, &GNUNET_GETOPT_set_one, &monitor_connections },
2092     { 'e', "events", NULL,
2093       gettext_noop ("provide information about all connects and disconnect events (continuously)"),
2094       0, &GNUNET_GETOPT_set_one, &monitor_connects },
2095     { 'n', "numeric",
2096       NULL, gettext_noop ("do not resolve hostnames"), 0,
2097       &GNUNET_GETOPT_set_one, &numeric },
2098     { 'p', "peer", "PEER",
2099       gettext_noop ("peer identity"), 1, &GNUNET_GETOPT_set_string,
2100       &cpid },
2101     { 'P', "plugins", NULL,
2102       gettext_noop ("monitor plugin sessions"), 0, &GNUNET_GETOPT_set_one,
2103       &monitor_plugins },
2104     { 's', "send", NULL, gettext_noop
2105       ("send data for benchmarking to the other peer (until CTRL-C)"), 0,
2106       &GNUNET_GETOPT_set_one, &benchmark_send },
2107     { 't', "test", NULL,
2108       gettext_noop ("test transport configuration (involves external server)"),
2109       0, &GNUNET_GETOPT_set_one, &test_configuration },
2110     GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
2111     GNUNET_GETOPT_OPTION_END
2112   };
2113
2114   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
2115     return 2;
2116
2117   res = GNUNET_PROGRAM_run (argc, argv,
2118                             "gnunet-transport",
2119                             gettext_noop ("Direct access to transport service."),
2120                             options,
2121                             &run, NULL);
2122   GNUNET_free((void *) argv);
2123   if (GNUNET_OK == res)
2124     return ret;
2125   return 1;
2126 }
2127
2128 /* end of gnunet-transport.c */