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