49c31663bd19e524edcab37e42a2bf2924076eb7
[oweals/gnunet.git] / src / transport / gnunet-transport.c
1 /*
2  This file is part of GNUnet.
3  (C) 2011 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
31 #include "platform.h"
32 #include "gnunet_util_lib.h"
33 #include "gnunet_resolver_service.h"
34 #include "gnunet_protocols.h"
35 #include "gnunet_transport_service.h"
36 #include "gnunet_nat_lib.h"
37
38 /**
39  * How long do we wait for the NAT test to report success?
40  * Should match NAT_SERVER_TIMEOUT in 'nat_test.c'.
41  */
42 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
43 #define RESOLUTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
44 #define OP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
45
46 /**
47  * Benchmarking block size in KB
48  */
49 #define BLOCKSIZE 4
50
51 /**
52  * Which peer should we connect to?
53  */
54 static char *cpid;
55
56 /**
57  * Handle to transport service.
58  */
59 static struct GNUNET_TRANSPORT_Handle *handle;
60
61 /**
62  * Configuration handle
63  */
64 static struct GNUNET_CONFIGURATION_Handle *cfg;
65
66 /**
67  * Try_connect handle
68  */
69 struct GNUNET_TRANSPORT_TryConnectHandle * tc_handle;
70
71 /**
72  * Option -s.
73  */
74 static int benchmark_send;
75
76 /**
77  * Option -b.
78  */
79 static int benchmark_receive;
80
81 /**
82  * Option -l.
83  */
84 static int benchmark_receive;
85
86 /**
87  * Option -i.
88  */
89 static int iterate_connections;
90
91 /**
92  * Option -d.
93  */
94 static int iterate_validation;
95
96 /**
97  * Option -a.
98  */
99 static int iterate_all;
100
101 /**
102  * Option -t.
103  */
104 static int test_configuration;
105
106 /**
107  * Option -c.
108  */
109 static int monitor_connects;
110
111 /**
112  * Option -m.
113  */
114 static int monitor_connections;
115
116 /**
117  * Option -f.
118  */
119 static int monitor_validation;
120
121 /**
122  * Option -C.
123  */
124 static int try_connect;
125
126 /**
127  * Option -n.
128  */
129 static int numeric;
130
131 /**
132  * Global return value (0 success).
133  */
134 static int ret;
135
136 /**
137  * Current number of connections in monitor mode
138  */
139 static int monitor_connect_counter;
140
141 /**
142  * Number of bytes of traffic we received so far.
143  */
144 static unsigned long long traffic_received;
145
146 /**
147  * Number of bytes of traffic we sent so far.
148  */
149 static unsigned long long traffic_sent;
150
151 /**
152  * Starting time of transmitting/receiving data.
153  */
154 static struct GNUNET_TIME_Absolute start_time;
155
156 /**
157  * Handle for current transmission request.
158  */
159 static struct GNUNET_TRANSPORT_TransmitHandle *th;
160
161 /**
162  * Map storing information about monitored peers
163  */
164 static struct GNUNET_CONTAINER_MultiPeerMap *monitored_peers;
165
166 /**
167  *
168  */
169 static struct GNUNET_TRANSPORT_PeerMonitoringContext *pic;
170
171 static struct GNUNET_TRANSPORT_ValidationMonitoringContext *vic;
172
173 /**
174  * Identity of the peer we transmit to / connect to.
175  * (equivalent to 'cpid' string).
176  */
177 static struct GNUNET_PeerIdentity pid;
178
179 /**
180  * Task scheduled for cleanup / termination of the process.
181  */
182 static GNUNET_SCHEDULER_TaskIdentifier end;
183
184 /**
185  * Task for operation timeout
186  */
187 static GNUNET_SCHEDULER_TaskIdentifier op_timeout;
188
189 /**
190  * Selected level of verbosity.
191  */
192 static int verbosity;
193
194 /**
195  * Resolver process handle.
196  */
197 struct GNUNET_OS_Process *resolver;
198
199 /**
200  * Number of tasks running that still need the resolver.
201  */
202 static unsigned int resolver_users;
203
204 /**
205  * Number of address resolutions pending
206  */
207 static unsigned int address_resolutions;
208
209 /**
210  * Address resolutions pending in progress
211  */
212 static unsigned int address_resolution_in_progress;
213
214
215 /**
216  * Context for a plugin test.
217  */
218 struct TestContext
219 {
220
221   /**
222    * Handle to the active NAT test.
223    */
224   struct GNUNET_NAT_Test *tst;
225
226   /**
227    * Task identifier for the timeout.
228    */
229   GNUNET_SCHEDULER_TaskIdentifier tsk;
230
231   /**
232    * Name of plugin under test.
233    */
234   const char *name;
235
236 };
237
238 struct MonitoredPeer
239 {
240   enum GNUNET_TRANSPORT_PeerState state;
241   struct GNUNET_TIME_Absolute state_timeout;
242   struct GNUNET_HELLO_Address *address;
243 };
244
245
246  int destroy_it (void *cls,
247     const struct GNUNET_PeerIdentity *key,
248     void *value)
249 {
250    struct MonitoredPeer *m = value;
251    GNUNET_CONTAINER_multipeermap_remove (monitored_peers, key, value);
252    GNUNET_free_non_null (m->address);
253    GNUNET_free (value);
254    return GNUNET_OK;
255 }
256
257 /**
258  * Task run in monitor mode when the user presses CTRL-C to abort.
259  * Stops monitoring activity.
260  *
261  * @param cls the 'struct GNUNET_TRANSPORT_PeerIterateContext *'
262  * @param tc scheduler context
263  */
264 static void
265 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
266 {
267   struct GNUNET_TIME_Relative duration;
268   end = GNUNET_SCHEDULER_NO_TASK;
269   if (GNUNET_SCHEDULER_NO_TASK != op_timeout)
270   {
271     GNUNET_SCHEDULER_cancel (op_timeout);
272     op_timeout = GNUNET_SCHEDULER_NO_TASK;
273   }
274   if (NULL != tc_handle)
275   {
276     GNUNET_TRANSPORT_try_connect_cancel (tc_handle);
277     tc_handle = NULL;
278   }
279   if (NULL != pic)
280   {
281     GNUNET_TRANSPORT_monitor_peers_cancel (pic);
282     pic = NULL;
283   }
284   if (NULL != vic)
285   {
286     GNUNET_TRANSPORT_monitor_validation_entries_cancel (vic);
287     vic = NULL;
288   }
289   if (NULL != th)
290   {
291     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
292     th = NULL;
293   }
294   if (NULL != handle)
295   {
296     GNUNET_TRANSPORT_disconnect (handle);
297     handle = NULL;
298   }
299   if (benchmark_send)
300   {
301     duration = GNUNET_TIME_absolute_get_duration (start_time);
302     FPRINTF (stdout, _("Transmitted %llu bytes/s (%llu bytes in %s)\n"),
303         1000LL * 1000LL * traffic_sent / (1 + duration.rel_value_us),
304         traffic_sent,
305         GNUNET_STRINGS_relative_time_to_string (duration, GNUNET_YES));
306   }
307   if (benchmark_receive)
308   {
309     duration = GNUNET_TIME_absolute_get_duration (start_time);
310     FPRINTF (stdout, _("Received %llu bytes/s (%llu bytes in %s)\n"),
311         1000LL * 1000LL * traffic_received / (1 + duration.rel_value_us),
312         traffic_received,
313         GNUNET_STRINGS_relative_time_to_string (duration, GNUNET_YES));
314   }
315
316   if (NULL != monitored_peers)
317   {
318     GNUNET_CONTAINER_multipeermap_iterate (monitored_peers, &destroy_it, NULL);
319     GNUNET_CONTAINER_multipeermap_destroy (monitored_peers);
320     monitored_peers = NULL;
321   }
322 }
323
324 static struct PeerResolutionContext *rc_head;
325 static struct PeerResolutionContext *rc_tail;
326
327 struct PeerResolutionContext
328 {
329   struct PeerResolutionContext *next;
330   struct PeerResolutionContext *prev;
331   struct GNUNET_PeerIdentity id;
332   struct GNUNET_HELLO_Address *addrcp;
333   struct GNUNET_TRANSPORT_AddressToStringContext *asc;
334   enum GNUNET_TRANSPORT_PeerState state;
335   struct GNUNET_TIME_Absolute state_timeout;
336   char *transport;
337   int printed;
338 };
339
340 static struct ValidationResolutionContext *vc_head;
341 static struct ValidationResolutionContext *vc_tail;
342
343 struct ValidationResolutionContext
344 {
345   struct ValidationResolutionContext *next;
346   struct ValidationResolutionContext *prev;
347
348   struct GNUNET_PeerIdentity id;
349   struct GNUNET_HELLO_Address *addrcp;
350   struct GNUNET_TIME_Absolute last_validation;
351   struct GNUNET_TIME_Absolute valid_until;
352   struct GNUNET_TIME_Absolute next_validation;
353   enum GNUNET_TRANSPORT_ValidationState state;
354
355   struct GNUNET_TRANSPORT_AddressToStringContext *asc;
356
357   char *transport;
358   int printed;
359 };
360
361 static void
362 operation_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
363 {
364   struct PeerResolutionContext *cur;
365   struct PeerResolutionContext *next;
366   op_timeout = GNUNET_SCHEDULER_NO_TASK;
367   if ((try_connect) || (benchmark_send) || (benchmark_receive))
368   {
369     FPRINTF (stdout, _("Failed to connect to `%s'\n"), GNUNET_i2s_full (&pid));
370     if (GNUNET_SCHEDULER_NO_TASK != end)
371       GNUNET_SCHEDULER_cancel (end);
372     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
373     ret = 1;
374     return;
375   }
376   if (iterate_connections)
377   {
378     next = rc_head;
379     while (NULL != (cur = next))
380     {
381       next = cur->next;
382       FPRINTF (stdout, _("Failed to resolve address for peer `%s'\n"),
383           GNUNET_i2s (&cur->addrcp->peer));
384
385       GNUNET_CONTAINER_DLL_remove(rc_head, rc_tail, cur);
386       GNUNET_TRANSPORT_address_to_string_cancel (cur->asc);
387       GNUNET_free(cur->transport);
388       GNUNET_free(cur->addrcp);
389       GNUNET_free(cur);
390
391     }
392     FPRINTF (stdout, "%s", _("Failed to list connections, timeout occured\n") );
393     if (GNUNET_SCHEDULER_NO_TASK != end)
394       GNUNET_SCHEDULER_cancel (end);
395     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
396     ret = 1;
397     return;
398   }
399
400 }
401
402 /**
403  * Display the result of the test.
404  *
405  * @param tc test context
406  * @param result #GNUNET_YES on success
407  */
408 static void
409 display_test_result (struct TestContext *tc, int result)
410 {
411   if (GNUNET_YES != result)
412   {
413     FPRINTF (stderr, "Configuration for plugin `%s' did not work!\n", tc->name);
414   }
415   else
416   {
417     FPRINTF (stderr, "Configuration for plugin `%s' is working!\n", tc->name);
418   }
419   if (GNUNET_SCHEDULER_NO_TASK != tc->tsk)
420   {
421     GNUNET_SCHEDULER_cancel (tc->tsk);
422     tc->tsk = GNUNET_SCHEDULER_NO_TASK;
423   }
424   if (NULL != tc->tst)
425   {
426     GNUNET_NAT_test_stop (tc->tst);
427     tc->tst = NULL;
428   }
429   GNUNET_free(tc);
430   resolver_users--;
431   if ((0 == resolver_users) && (NULL != resolver))
432   {
433     GNUNET_break(0 == GNUNET_OS_process_kill (resolver, GNUNET_TERM_SIG));
434     GNUNET_OS_process_destroy (resolver);
435     resolver = NULL;
436   }
437 }
438
439 /**
440  * Function called by NAT on success.
441  * Clean up and update GUI (with success).
442  *
443  * @param cls test context
444  * @param success currently always #GNUNET_OK
445  * @param emsg error message, NULL on success
446  */
447 static void
448 result_callback (void *cls, int success, const char *emsg)
449 {
450   struct TestContext *tc = cls;
451
452   display_test_result (tc, success);
453 }
454
455 /**
456  * Function called if NAT failed to confirm success.
457  * Clean up and update GUI (with failure).
458  *
459  * @param cls test context
460  * @param tc scheduler callback
461  */
462 static void
463 fail_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
464 {
465   struct TestContext *tstc = cls;
466
467   tstc->tsk = GNUNET_SCHEDULER_NO_TASK;
468   display_test_result (tstc, GNUNET_NO);
469 }
470
471
472 static void
473 resolve_validation_address (const struct GNUNET_PeerIdentity *id,
474     const struct GNUNET_HELLO_Address *address, int numeric,
475     struct GNUNET_TIME_Absolute last_validation,
476     struct GNUNET_TIME_Absolute valid_until,
477     struct GNUNET_TIME_Absolute next_validation,
478     enum GNUNET_TRANSPORT_ValidationState state);
479
480 static void
481 process_validation_string (void *cls, const char *address)
482 {
483   struct ValidationResolutionContext *vc = cls;
484   char *s_valid;
485   char *s_last;
486   char *s_next;
487
488   if (address != NULL )
489   {
490     if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == vc->valid_until.abs_value_us)
491       s_valid = GNUNET_strdup("never");
492     else
493       s_valid = GNUNET_strdup(GNUNET_STRINGS_absolute_time_to_string (vc->valid_until));
494
495     if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == vc->last_validation.abs_value_us)
496       s_last = GNUNET_strdup("never");
497     else
498       s_last = GNUNET_strdup(GNUNET_STRINGS_absolute_time_to_string (vc->last_validation));
499
500     if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == vc->next_validation.abs_value_us)
501       s_next = GNUNET_strdup("never");
502     else
503       s_next = GNUNET_strdup(GNUNET_STRINGS_absolute_time_to_string (vc->next_validation));
504
505     FPRINTF (stdout,
506         _("Peer `%s' %s %s\n\t%s%s\n\t%s%s\n\t%s%s\n"),
507         GNUNET_i2s (&vc->id), address,
508         (monitor_validation) ? GNUNET_TRANSPORT_vs2s (vc->state) : "",
509         "Valid until    : ", s_valid,
510         "Last validation: ",s_last,
511         "Next validation: ", s_next);
512     GNUNET_free (s_valid);
513     GNUNET_free (s_last);
514     GNUNET_free (s_next);
515     vc->printed = GNUNET_YES;
516   }
517   else
518   {
519     /* done */
520     GNUNET_assert(address_resolutions > 0);
521     address_resolutions--;
522     if (GNUNET_NO == vc->printed)
523     {
524       if (numeric == GNUNET_NO)
525       {
526         /* Failed to resolve address, try numeric lookup */
527         resolve_validation_address (&vc->id, vc->addrcp, GNUNET_NO,
528            vc->last_validation, vc->valid_until, vc->next_validation,
529            vc->state);
530       }
531       else
532       {
533         FPRINTF (stdout, _("Peer `%s' %s `%s' \n"),
534             GNUNET_i2s (&vc->id), "<unable to resolve address>",
535             GNUNET_TRANSPORT_vs2s (vc->state));
536       }
537     }
538     GNUNET_free (vc->transport);
539     GNUNET_free (vc->addrcp);
540     GNUNET_CONTAINER_DLL_remove(vc_head, vc_tail, vc);
541     GNUNET_free(vc);
542     if ((0 == address_resolutions) && (iterate_validation))
543     {
544       if (GNUNET_SCHEDULER_NO_TASK != end)
545       {
546         GNUNET_SCHEDULER_cancel (end);
547         end = GNUNET_SCHEDULER_NO_TASK;
548       }
549       if (GNUNET_SCHEDULER_NO_TASK != op_timeout)
550       {
551         GNUNET_SCHEDULER_cancel (op_timeout);
552         op_timeout = GNUNET_SCHEDULER_NO_TASK;
553       }
554       ret = 0;
555       end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
556     }
557   }
558 }
559
560
561
562 static void
563 resolve_validation_address (const struct GNUNET_PeerIdentity *id,
564     const struct GNUNET_HELLO_Address *address, int numeric,
565     struct GNUNET_TIME_Absolute last_validation,
566     struct GNUNET_TIME_Absolute valid_until,
567     struct GNUNET_TIME_Absolute next_validation,
568     enum GNUNET_TRANSPORT_ValidationState state)
569 {
570   struct ValidationResolutionContext *vc;
571
572   vc = GNUNET_new (struct ValidationResolutionContext);
573   GNUNET_assert(NULL != vc);
574   GNUNET_CONTAINER_DLL_insert(vc_head, vc_tail, vc);
575   address_resolutions++;
576
577   vc->id = (*id);
578   vc->transport = GNUNET_strdup(address->transport_name);
579   vc->addrcp = GNUNET_HELLO_address_copy (address);
580   vc->printed = GNUNET_NO;
581   vc->state = state;
582   vc->last_validation = last_validation;
583   vc->valid_until = valid_until;
584   vc->next_validation = next_validation;
585
586   /* Resolve address to string */
587   vc->asc = GNUNET_TRANSPORT_address_to_string (cfg, address, numeric,
588       RESOLUTION_TIMEOUT, &process_validation_string, vc);
589 }
590
591
592 void process_validation_cb (void *cls,
593     const struct GNUNET_PeerIdentity *peer,
594     const struct GNUNET_HELLO_Address *address,
595     struct GNUNET_TIME_Absolute last_validation,
596     struct GNUNET_TIME_Absolute valid_until,
597     struct GNUNET_TIME_Absolute next_validation,
598     enum GNUNET_TRANSPORT_ValidationState state)
599 {
600   if ((NULL == peer) && (NULL == address))
601   {
602     /* done */
603     vic = NULL;
604     if (GNUNET_SCHEDULER_NO_TASK != end)
605       GNUNET_SCHEDULER_cancel (end);
606     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
607     return;
608   }
609   if ((NULL == peer) || (NULL == address))
610   {
611     /* invalid response */
612     vic = NULL;
613     if (GNUNET_SCHEDULER_NO_TASK != end)
614       GNUNET_SCHEDULER_cancel (end);
615     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
616     return;
617   }
618   resolve_validation_address (peer, address,
619      numeric, last_validation,
620      valid_until, next_validation, state);
621 }
622
623 /**
624  * Test our plugin's configuration (NAT traversal, etc.).
625  *
626  * @param cfg configuration to test
627  */
628 static void
629 do_test_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
630 {
631   char *plugins;
632   char *tok;
633   unsigned long long bnd_port;
634   unsigned long long adv_port;
635   struct TestContext *tc;
636   char *binary;
637
638   if (GNUNET_OK
639       != GNUNET_CONFIGURATION_get_value_string (cfg, "transport", "plugins",
640           &plugins))
641   {
642     FPRINTF (stderr, "%s", _
643     ("No transport plugins configured, peer will never communicate\n") );
644     ret = 4;
645     return;
646   }
647   for (tok = strtok (plugins, " "); tok != NULL ; tok = strtok (NULL, " "))
648   {
649     char section[12 + strlen (tok)];
650
651     GNUNET_snprintf (section, sizeof(section), "transport-%s", tok);
652     if (GNUNET_OK
653         != GNUNET_CONFIGURATION_get_value_number (cfg, section, "PORT",
654             &bnd_port))
655     {
656       FPRINTF (stderr,
657           _("No port configured for plugin `%s', cannot test it\n"), tok);
658       continue;
659     }
660     if (GNUNET_OK
661         != GNUNET_CONFIGURATION_get_value_number (cfg, section,
662             "ADVERTISED_PORT", &adv_port))
663       adv_port = bnd_port;
664     if (NULL == resolver)
665     {
666       binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
667       resolver = GNUNET_OS_start_process (GNUNET_YES,
668           GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, binary,
669           "gnunet-service-resolver", NULL );
670       GNUNET_free(binary);
671     }
672     resolver_users++;
673     GNUNET_RESOLVER_connect (cfg);
674     tc = GNUNET_new (struct TestContext);
675     tc->name = GNUNET_strdup (tok);
676     tc->tst = GNUNET_NAT_test_start (cfg,
677         (0 == strcasecmp (tok, "udp")) ? GNUNET_NO : GNUNET_YES,
678         (uint16_t) bnd_port, (uint16_t) adv_port, &result_callback, tc);
679     if (NULL == tc->tst)
680     {
681       display_test_result (tc, GNUNET_SYSERR);
682       continue;
683     }
684     tc->tsk = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &fail_timeout, tc);
685   }
686   GNUNET_free(plugins);
687 }
688
689 /**
690  * Function called to notify a client about the socket
691  * begin ready to queue more data.  @a buf will be
692  * NULL and @a size zero if the socket was closed for
693  * writing in the meantime.
694  *
695  * @param cls closure
696  * @param size number of bytes available in @a buf
697  * @param buf where the callee should write the message
698  * @return number of bytes written to @a buf
699  */
700 static size_t
701 transmit_data (void *cls, size_t size, void *buf)
702 {
703   struct GNUNET_MessageHeader *m = buf;
704
705   if ((NULL == buf) || (0 == size))
706   {
707     th = NULL;
708     return 0;
709   }
710
711   GNUNET_assert(size >= sizeof(struct GNUNET_MessageHeader));
712   GNUNET_assert(size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
713   m->size = ntohs (size);
714   m->type = ntohs (GNUNET_MESSAGE_TYPE_DUMMY);
715   memset (&m[1], 52, size - sizeof(struct GNUNET_MessageHeader));
716   traffic_sent += size;
717   th = GNUNET_TRANSPORT_notify_transmit_ready (handle, &pid,
718                                                BLOCKSIZE * 1024,
719                                                GNUNET_TIME_UNIT_FOREVER_REL,
720                                                &transmit_data, NULL );
721   if (verbosity > 0)
722     FPRINTF (stdout, _("Transmitting %u bytes to %s\n"), (unsigned int) size,
723         GNUNET_i2s (&pid));
724   return size;
725 }
726
727 /**
728  * Function called to notify transport users that another
729  * peer connected to us.
730  *
731  * @param cls closure
732  * @param peer the peer that connected
733  */
734 static void
735 notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
736 {
737   if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
738     return;
739   ret = 0;
740   if (try_connect)
741   {
742     /* all done, terminate instantly */
743     FPRINTF (stdout, _("Successfully connected to `%s'\n"),
744         GNUNET_i2s_full (peer));
745     ret = 0;
746
747     if (GNUNET_SCHEDULER_NO_TASK != op_timeout)
748     {
749       GNUNET_SCHEDULER_cancel (op_timeout);
750       op_timeout = GNUNET_SCHEDULER_NO_TASK;
751     }
752
753     if (GNUNET_SCHEDULER_NO_TASK != end)
754       GNUNET_SCHEDULER_cancel (end);
755     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
756     return;
757   }
758   if (benchmark_send)
759   {
760     if (GNUNET_SCHEDULER_NO_TASK != op_timeout)
761     {
762       GNUNET_SCHEDULER_cancel (op_timeout);
763       op_timeout = GNUNET_SCHEDULER_NO_TASK;
764     }
765     if (verbosity > 0)
766       FPRINTF (stdout,
767           _("Successfully connected to `%s', starting to send benchmark data in %u Kb blocks\n"),
768           GNUNET_i2s (&pid), BLOCKSIZE);
769     start_time = GNUNET_TIME_absolute_get ();
770     if (NULL == th)
771       th = GNUNET_TRANSPORT_notify_transmit_ready (handle, peer,
772                                                    BLOCKSIZE * 1024,
773                                                    GNUNET_TIME_UNIT_FOREVER_REL,
774                                                    &transmit_data,
775                                                    NULL);
776     else
777       GNUNET_break(0);
778     return;
779   }
780 }
781
782 /**
783  * Function called to notify transport users that another
784  * peer disconnected from us.
785  *
786  * @param cls closure
787  * @param peer the peer that disconnected
788  */
789 static void
790 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
791 {
792   if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
793     return;
794
795   if (NULL != th)
796   {
797     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
798     th = NULL;
799   }
800   if (benchmark_send)
801   {
802     FPRINTF (stdout, _("Disconnected from peer `%s' while benchmarking\n"),
803         GNUNET_i2s (&pid));
804     if (GNUNET_SCHEDULER_NO_TASK != end)
805       GNUNET_SCHEDULER_cancel (end);
806     return;
807   }
808 }
809
810 /**
811  * Function called to notify transport users that another
812  * peer connected to us.
813  *
814  * @param cls closure
815  * @param peer the peer that connected
816  */
817 static void
818 monitor_notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
819 {
820   monitor_connect_counter++;
821   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
822   const char *now_str = GNUNET_STRINGS_absolute_time_to_string (now);
823
824   FPRINTF (stdout, _("%24s: %-17s %4s   (%u connections in total)\n"), now_str,
825       _("Connected to"), GNUNET_i2s (peer), monitor_connect_counter);
826 }
827
828 /**
829  * Function called to notify transport users that another
830  * peer disconnected from us.
831  *
832  * @param cls closure
833  * @param peer the peer that disconnected
834  */
835 static void
836 monitor_notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
837 {
838   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
839   const char *now_str = GNUNET_STRINGS_absolute_time_to_string (now);
840
841   GNUNET_assert(monitor_connect_counter > 0);
842   monitor_connect_counter--;
843
844   FPRINTF (stdout, _("%24s: %-17s %4s   (%u connections in total)\n"), now_str,
845       _("Disconnected from"), GNUNET_i2s (peer), monitor_connect_counter);
846 }
847
848 /**
849  * Function called by the transport for each received message.
850  *
851  * @param cls closure
852  * @param peer (claimed) identity of the other peer
853  * @param message the message
854  */
855 static void
856 notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
857     const struct GNUNET_MessageHeader *message)
858 {
859   if (benchmark_receive)
860   {
861     if (GNUNET_MESSAGE_TYPE_DUMMY != ntohs (message->type))
862       return;
863     if (verbosity > 0)
864       FPRINTF (stdout, _("Received %u bytes from %s\n"),
865           (unsigned int) ntohs (message->size), GNUNET_i2s (peer));
866
867     if (traffic_received == 0)
868       start_time = GNUNET_TIME_absolute_get ();
869     traffic_received += ntohs (message->size);
870     return;
871   }
872 }
873
874 static void
875 resolve_peer_address (const struct GNUNET_PeerIdentity *id,
876     const struct GNUNET_HELLO_Address *address, int numeric,
877     enum GNUNET_TRANSPORT_PeerState state,
878     struct GNUNET_TIME_Absolute state_timeout);
879
880 static void
881 print_info (const struct GNUNET_PeerIdentity *id, const char *transport,
882     const char *addr, enum GNUNET_TRANSPORT_PeerState state,
883     struct GNUNET_TIME_Absolute state_timeout)
884 {
885   if ((GNUNET_YES == iterate_all) || (GNUNET_YES == monitor_connections) )
886   {
887     FPRINTF (stdout, _("Peer `%s': %s %s in state `%s' until %s\n"),
888         GNUNET_i2s (id),
889         (NULL == transport) ? "<none>" : transport,
890         (NULL == transport) ? "<none>" : addr,
891         GNUNET_TRANSPORT_ps2s (state),
892         GNUNET_STRINGS_absolute_time_to_string (state_timeout));
893   }
894   else
895   {
896     /* Only connected peers, skip state */
897     FPRINTF (stdout, _("Peer `%s': %s %s\n"), GNUNET_i2s (id), transport, addr);
898   }
899
900 }
901
902 static void
903 process_peer_string (void *cls, const char *address)
904 {
905   struct PeerResolutionContext *rc = cls;
906
907   if (address != NULL )
908   {
909     print_info (&rc->id, rc->transport, address, rc->state, rc->state_timeout);
910     rc->printed = GNUNET_YES;
911   }
912   else
913   {
914     /* done */
915     GNUNET_assert(address_resolutions > 0);
916     address_resolutions--;
917     if (GNUNET_NO == rc->printed)
918     {
919       if (numeric == GNUNET_NO)
920       {
921         /* Failed to resolve address, try numeric lookup */
922         resolve_peer_address (&rc->id, rc->addrcp, GNUNET_YES,
923             rc->state, rc->state_timeout);
924       }
925       else
926       {
927         print_info (&rc->id, rc->transport, "<unable to resolve address>",
928             rc->state, rc->state_timeout);
929       }
930     }
931     GNUNET_free (rc->transport);
932     GNUNET_free (rc->addrcp);
933     GNUNET_CONTAINER_DLL_remove(rc_head, rc_tail, rc);
934     GNUNET_free(rc);
935     if ((0 == address_resolutions) && (iterate_connections))
936     {
937       if (GNUNET_SCHEDULER_NO_TASK != end)
938       {
939         GNUNET_SCHEDULER_cancel (end);
940         end = GNUNET_SCHEDULER_NO_TASK;
941       }
942       if (GNUNET_SCHEDULER_NO_TASK != op_timeout)
943       {
944         GNUNET_SCHEDULER_cancel (op_timeout);
945         op_timeout = GNUNET_SCHEDULER_NO_TASK;
946       }
947       ret = 0;
948       end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
949     }
950   }
951 }
952
953 static void
954 resolve_peer_address (const struct GNUNET_PeerIdentity *id,
955     const struct GNUNET_HELLO_Address *address, int numeric,
956     enum GNUNET_TRANSPORT_PeerState state,
957     struct GNUNET_TIME_Absolute state_timeout)
958 {
959   struct PeerResolutionContext *rc;
960
961   rc = GNUNET_new (struct PeerResolutionContext);
962   GNUNET_assert(NULL != rc);
963   GNUNET_CONTAINER_DLL_insert(rc_head, rc_tail, rc);
964   address_resolutions++;
965
966   rc->id = (*id);
967   rc->transport = GNUNET_strdup(address->transport_name);
968   rc->addrcp = GNUNET_HELLO_address_copy (address);
969   rc->printed = GNUNET_NO;
970   rc->state = state;
971   rc->state_timeout = state_timeout;
972   /* Resolve address to string */
973   rc->asc = GNUNET_TRANSPORT_address_to_string (cfg, address, numeric,
974       RESOLUTION_TIMEOUT, &process_peer_string, rc);
975 }
976
977 /**
978  * Function called with information about a peers during a one shot iteration
979  *
980  * @param cls closure
981  * @param peer identity of the peer, NULL for final callback when operation done
982  * @param address binary address used to communicate with this peer,
983  *  NULL on disconnect or when done
984  * @param state current state this peer is in
985  * @param state_timeout time out for the current state
986  *
987  */
988 static void
989 process_peer_iteration_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
990     const struct GNUNET_HELLO_Address *address,
991     enum GNUNET_TRANSPORT_PeerState state,
992     struct GNUNET_TIME_Absolute state_timeout)
993 {
994   if (peer == NULL )
995   {
996     /* done */
997     address_resolution_in_progress = GNUNET_NO;
998     pic = NULL;
999     if (GNUNET_SCHEDULER_NO_TASK != end)
1000       GNUNET_SCHEDULER_cancel (end);
1001     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
1002     return;
1003   }
1004
1005   if ((GNUNET_NO == iterate_all) && (GNUNET_NO == GNUNET_TRANSPORT_is_connected(state)) )
1006       return; /* Display only connected peers */
1007
1008   if (GNUNET_SCHEDULER_NO_TASK != op_timeout)
1009     GNUNET_SCHEDULER_cancel (op_timeout);
1010   op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1011       NULL );
1012
1013   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received address for peer `%s': %s\n",
1014       GNUNET_i2s (peer), address->transport_name);
1015
1016   if (NULL != address)
1017     resolve_peer_address (peer, address, numeric, state, state_timeout);
1018   else
1019     print_info (peer, NULL, NULL, state, state_timeout);
1020 }
1021
1022
1023 /**
1024  * Function called with information about a peers
1025  *
1026  * @param cls closure
1027  * @param peer identity of the peer, NULL for final callback when operation done
1028  * @param address binary address used to communicate with this peer,
1029  *  NULL on disconnect or when done
1030  * @param state current state this peer is in
1031  * @param state_timeout time out for the current state
1032  *
1033  */
1034 static void
1035 process_peer_monitoring_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
1036     const struct GNUNET_HELLO_Address *address,
1037     enum GNUNET_TRANSPORT_PeerState state,
1038     struct GNUNET_TIME_Absolute state_timeout)
1039 {
1040   struct MonitoredPeer *m;
1041
1042   if (peer == NULL )
1043   {
1044     /* done */
1045     address_resolution_in_progress = GNUNET_NO;
1046     pic = NULL;
1047     if (GNUNET_SCHEDULER_NO_TASK != end)
1048       GNUNET_SCHEDULER_cancel (end);
1049     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
1050     return;
1051   }
1052
1053   if (GNUNET_SCHEDULER_NO_TASK != op_timeout)
1054     GNUNET_SCHEDULER_cancel (op_timeout);
1055   op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1056       NULL );
1057
1058   if (NULL == (m = GNUNET_CONTAINER_multipeermap_get (monitored_peers, peer)))
1059   {
1060     m = GNUNET_new (struct MonitoredPeer);
1061     GNUNET_CONTAINER_multipeermap_put (monitored_peers, peer,
1062         m, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1063   }
1064   else
1065   {
1066     if ( (m->state == state) &&
1067       (m->state_timeout.abs_value_us == state_timeout.abs_value_us) &&
1068       ((NULL == address) && (NULL == m->address)) )
1069     {
1070       return; /* No real change */
1071     }
1072     if ( ((NULL != address) && (NULL != m->address)) &&
1073         (0 == GNUNET_HELLO_address_cmp(m->address, address)) )
1074       return; /* No real change */
1075   }
1076
1077
1078   if (NULL != m->address)
1079   {
1080     GNUNET_free (m->address);
1081     m->address = NULL;
1082   }
1083   if (NULL != address)
1084     m->address = GNUNET_HELLO_address_copy (address);
1085   m->state = state;
1086   m->state_timeout = state_timeout;
1087
1088   if (NULL != address)
1089     resolve_peer_address (peer, m->address, numeric, m->state, m->state_timeout);
1090   else
1091     print_info (peer, NULL, NULL, m->state, m->state_timeout);
1092 }
1093
1094 static void
1095 try_connect_cb (void *cls, const int result)
1096 {
1097   static int retries = 0;
1098   if (GNUNET_OK == result)
1099   {
1100     tc_handle = NULL;
1101     return;
1102   }
1103   retries++;
1104   if (retries < 10)
1105     tc_handle = GNUNET_TRANSPORT_try_connect (handle, &pid, try_connect_cb,
1106         NULL );
1107   else
1108   {
1109     FPRINTF (stderr, "%s",
1110         _("Failed to send connect request to transport service\n") );
1111     if (GNUNET_SCHEDULER_NO_TASK != end)
1112       GNUNET_SCHEDULER_cancel (end);
1113     ret = 1;
1114     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
1115     return;
1116   }
1117 }
1118
1119 /**
1120  * Function called with the result of the check if the 'transport'
1121  * service is running.
1122  *
1123  * @param cls closure with our configuration
1124  * @param result #GNUNET_YES if transport is running
1125  */
1126 static void
1127 testservice_task (void *cls, int result)
1128 {
1129   int counter = 0;
1130   ret = 1;
1131
1132   if (GNUNET_YES != result)
1133   {
1134     FPRINTF (stderr, _("Service `%s' is not running\n"), "transport");
1135     return;
1136   }
1137
1138   if ((NULL != cpid)
1139       && (GNUNET_OK
1140           != GNUNET_CRYPTO_eddsa_public_key_from_string (cpid, strlen (cpid),
1141               &pid.public_key)))
1142   {
1143     FPRINTF (stderr, _("Failed to parse peer identity `%s'\n"), cpid);
1144     return;
1145   }
1146
1147   counter = benchmark_send + benchmark_receive + iterate_connections
1148       + monitor_connections + monitor_connects + try_connect
1149       + iterate_validation + monitor_validation;
1150
1151   if (1 < counter)
1152   {
1153     FPRINTF (stderr,
1154         _("Multiple operations given. Please choose only one operation: %s, %s, %s, %s, %s, %s\n"),
1155         "connect", "benchmark send", "benchmark receive", "information",
1156         "monitor", "events");
1157     return;
1158   }
1159   if (0 == counter)
1160   {
1161     FPRINTF (stderr,
1162         _("No operation given. Please choose one operation: %s, %s, %s, %s, %s, %s\n"),
1163         "connect", "benchmark send", "benchmark receive", "information",
1164         "monitor", "events");
1165     return;
1166   }
1167
1168   if (try_connect) /* -C: Connect to peer */
1169   {
1170     if (NULL == cpid)
1171     {
1172       FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
1173           "-C", "-p");
1174       ret = 1;
1175       return;
1176     }
1177     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, &notify_receive,
1178         &notify_connect, &notify_disconnect);
1179     if (NULL == handle)
1180     {
1181       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n") );
1182       ret = 1;
1183       return;
1184     }
1185     tc_handle = GNUNET_TRANSPORT_try_connect (handle, &pid, try_connect_cb,
1186         NULL );
1187     if (NULL == tc_handle)
1188     {
1189       FPRINTF (stderr, "%s",
1190           _("Failed to send request to transport service\n") );
1191       ret = 1;
1192       return;
1193     }
1194     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1195         NULL );
1196
1197   }
1198   else if (benchmark_send) /* -s: Benchmark sending */
1199   {
1200     if (NULL == cpid)
1201     {
1202       FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
1203           "-s", "-p");
1204       ret = 1;
1205       return;
1206     }
1207     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, &notify_receive,
1208         &notify_connect, &notify_disconnect);
1209     if (NULL == handle)
1210     {
1211       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n") );
1212       ret = 1;
1213       return;
1214     }
1215     tc_handle = GNUNET_TRANSPORT_try_connect (handle, &pid, try_connect_cb,
1216         NULL );
1217     if (NULL == tc_handle)
1218     {
1219       FPRINTF (stderr, "%s",
1220           _("Failed to send request to transport service\n") );
1221       ret = 1;
1222       return;
1223     }
1224     start_time = GNUNET_TIME_absolute_get ();
1225     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1226         NULL );
1227   }
1228   else if (benchmark_receive) /* -b: Benchmark receiving */
1229   {
1230     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, &notify_receive, NULL,
1231         NULL );
1232     if (NULL == handle)
1233     {
1234       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n") );
1235       ret = 1;
1236       return;
1237     }
1238     if (verbosity > 0)
1239       FPRINTF (stdout, "%s", _("Starting to receive benchmark data\n") );
1240     start_time = GNUNET_TIME_absolute_get ();
1241
1242   }
1243   else if (iterate_connections) /* -i: List information about peers once */
1244   {
1245     address_resolution_in_progress = GNUNET_YES;
1246     pic = GNUNET_TRANSPORT_monitor_peers (cfg, (NULL == cpid) ? NULL : &pid,
1247         GNUNET_YES, TIMEOUT, &process_peer_iteration_cb, (void *) cfg);
1248     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1249         NULL );
1250   }
1251   else if (monitor_connections) /* -m: List information about peers continuously */
1252   {
1253     monitored_peers = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1254     address_resolution_in_progress = GNUNET_YES;
1255     pic = GNUNET_TRANSPORT_monitor_peers (cfg, (NULL == cpid) ? NULL : &pid,
1256         GNUNET_NO, TIMEOUT, &process_peer_monitoring_cb, (void *) cfg);
1257   }
1258   else if (iterate_validation) /* -d: Print information about validations */
1259   {
1260     vic = GNUNET_TRANSPORT_monitor_validation_entries (cfg,
1261         (NULL == cpid) ? NULL : &pid,
1262         GNUNET_YES, TIMEOUT, &process_validation_cb, (void *) cfg);
1263   }
1264   else if (monitor_validation) /* -f: Print information about validations continuously */
1265   {
1266     vic = GNUNET_TRANSPORT_monitor_validation_entries (cfg,
1267         (NULL == cpid) ? NULL : &pid,
1268         GNUNET_NO, TIMEOUT, &process_validation_cb, (void *) cfg);
1269   }
1270   else if (monitor_connects) /* -e : Monitor (dis)connect events continuously */
1271   {
1272     monitor_connect_counter = 0;
1273     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, NULL,
1274         &monitor_notify_connect, &monitor_notify_disconnect);
1275     if (NULL == handle)
1276     {
1277       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n") );
1278       ret = 1;
1279       return;
1280     }
1281     ret = 0;
1282   }
1283   else
1284   {
1285     GNUNET_break(0);
1286     return;
1287   }
1288
1289   end = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1290       &shutdown_task, NULL );
1291
1292 }
1293
1294 /**
1295  * Main function that will be run by the scheduler.
1296  *
1297  * @param cls closure
1298  * @param args remaining command-line arguments
1299  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1300  * @param mycfg configuration
1301  */
1302 static void
1303 run (void *cls, char * const *args, const char *cfgfile,
1304     const struct GNUNET_CONFIGURATION_Handle *mycfg)
1305 {
1306   cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
1307   if (test_configuration)
1308   {
1309     do_test_configuration (cfg);
1310     return;
1311   }
1312   GNUNET_CLIENT_service_test ("transport", cfg, GNUNET_TIME_UNIT_SECONDS,
1313       &testservice_task, (void *) cfg);
1314 }
1315
1316 int
1317 main (int argc, char * const *argv)
1318 {
1319   int res;
1320   static const struct GNUNET_GETOPT_CommandLineOption options[] =
1321       {
1322           { 'a', "all", NULL,
1323               gettext_noop ("print information for all peers (instead of only connected peers )"),
1324               0, &GNUNET_GETOPT_set_one, &iterate_all },
1325           { 'b', "benchmark", NULL,
1326               gettext_noop ("measure how fast we are receiving data from all peers (until CTRL-C)"),
1327               0, &GNUNET_GETOPT_set_one, &benchmark_receive }, { 'C', "connect",
1328               NULL, gettext_noop ("connect to a peer"), 0,
1329               &GNUNET_GETOPT_set_one, &try_connect },
1330           { 'd', "validation", NULL,
1331               gettext_noop ("print information for all pending validations "),
1332               0, &GNUNET_GETOPT_set_one, &iterate_validation },
1333           { 'f', "monitorvalidation", NULL,
1334               gettext_noop ("print information for all pending validations continously"),
1335               0, &GNUNET_GETOPT_set_one, &monitor_validation },
1336           { 'i', "information", NULL,
1337               gettext_noop ("provide information about all current connections (once)"),
1338               0, &GNUNET_GETOPT_set_one, &iterate_connections },
1339           { 'm', "monitor", NULL,
1340               gettext_noop ("provide information about all current connections (continuously)"),
1341               0, &GNUNET_GETOPT_set_one, &monitor_connections },
1342           { 'e', "events", NULL,
1343               gettext_noop ("provide information about all connects and disconnect events (continuously)"),
1344               0, &GNUNET_GETOPT_set_one, &monitor_connects }, { 'n', "numeric",
1345               NULL, gettext_noop ("do not resolve hostnames"), 0,
1346               &GNUNET_GETOPT_set_one, &numeric }, { 'p', "peer", "PEER",
1347               gettext_noop ("peer identity"), 1, &GNUNET_GETOPT_set_string,
1348               &cpid }, { 's', "send", NULL, gettext_noop
1349           ("send data for benchmarking to the other peer (until CTRL-C)"), 0,
1350               &GNUNET_GETOPT_set_one, &benchmark_send },
1351           { 't', "test", NULL,
1352               gettext_noop ("test transport configuration (involves external server)"),
1353               0, &GNUNET_GETOPT_set_one, &test_configuration },
1354               GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
1355               GNUNET_GETOPT_OPTION_END };
1356
1357   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1358     return 2;
1359
1360   res = GNUNET_PROGRAM_run (argc, argv, "gnunet-transport", gettext_noop
1361   ("Direct access to transport service."), options, &run, NULL );
1362   GNUNET_free((void * ) argv);
1363   if (GNUNET_OK == res)
1364     return ret;
1365   return 1;
1366 }
1367
1368 /* end of gnunet-transport.c */