improved messages
[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,
669                                           NULL, NULL, NULL,
670                                           binary,
671                                           "gnunet-service-resolver", NULL );
672       GNUNET_free(binary);
673     }
674     resolver_users++;
675     GNUNET_RESOLVER_connect (cfg);
676     tc = GNUNET_new (struct TestContext);
677     tc->name = GNUNET_strdup (tok);
678     tc->tst = GNUNET_NAT_test_start (cfg,
679         (0 == strcasecmp (tok, "udp")) ? GNUNET_NO : GNUNET_YES,
680         (uint16_t) bnd_port, (uint16_t) adv_port, &result_callback, tc);
681     if (NULL == tc->tst)
682     {
683       display_test_result (tc, GNUNET_SYSERR);
684       continue;
685     }
686     tc->tsk = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &fail_timeout, tc);
687   }
688   GNUNET_free(plugins);
689 }
690
691 /**
692  * Function called to notify a client about the socket
693  * begin ready to queue more data.  @a buf will be
694  * NULL and @a size zero if the socket was closed for
695  * writing in the meantime.
696  *
697  * @param cls closure
698  * @param size number of bytes available in @a buf
699  * @param buf where the callee should write the message
700  * @return number of bytes written to @a buf
701  */
702 static size_t
703 transmit_data (void *cls, size_t size, void *buf)
704 {
705   struct GNUNET_MessageHeader *m = buf;
706
707   if ((NULL == buf) || (0 == size))
708   {
709     th = NULL;
710     return 0;
711   }
712
713   GNUNET_assert(size >= sizeof(struct GNUNET_MessageHeader));
714   GNUNET_assert(size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
715   m->size = ntohs (size);
716   m->type = ntohs (GNUNET_MESSAGE_TYPE_DUMMY);
717   memset (&m[1], 52, size - sizeof(struct GNUNET_MessageHeader));
718   traffic_sent += size;
719   th = GNUNET_TRANSPORT_notify_transmit_ready (handle, &pid,
720                                                BLOCKSIZE * 1024,
721                                                GNUNET_TIME_UNIT_FOREVER_REL,
722                                                &transmit_data, NULL );
723   if (verbosity > 0)
724     FPRINTF (stdout, _("Transmitting %u bytes to %s\n"), (unsigned int) size,
725         GNUNET_i2s (&pid));
726   return size;
727 }
728
729 /**
730  * Function called to notify transport users that another
731  * peer connected to us.
732  *
733  * @param cls closure
734  * @param peer the peer that connected
735  */
736 static void
737 notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
738 {
739   if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
740     return;
741   ret = 0;
742   if (try_connect)
743   {
744     /* all done, terminate instantly */
745     FPRINTF (stdout, _("Successfully connected to `%s'\n"),
746         GNUNET_i2s_full (peer));
747     ret = 0;
748
749     if (GNUNET_SCHEDULER_NO_TASK != op_timeout)
750     {
751       GNUNET_SCHEDULER_cancel (op_timeout);
752       op_timeout = GNUNET_SCHEDULER_NO_TASK;
753     }
754
755     if (GNUNET_SCHEDULER_NO_TASK != end)
756       GNUNET_SCHEDULER_cancel (end);
757     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
758     return;
759   }
760   if (benchmark_send)
761   {
762     if (GNUNET_SCHEDULER_NO_TASK != op_timeout)
763     {
764       GNUNET_SCHEDULER_cancel (op_timeout);
765       op_timeout = GNUNET_SCHEDULER_NO_TASK;
766     }
767     if (verbosity > 0)
768       FPRINTF (stdout,
769           _("Successfully connected to `%s', starting to send benchmark data in %u Kb blocks\n"),
770           GNUNET_i2s (&pid), BLOCKSIZE);
771     start_time = GNUNET_TIME_absolute_get ();
772     if (NULL == th)
773       th = GNUNET_TRANSPORT_notify_transmit_ready (handle, peer,
774                                                    BLOCKSIZE * 1024,
775                                                    GNUNET_TIME_UNIT_FOREVER_REL,
776                                                    &transmit_data,
777                                                    NULL);
778     else
779       GNUNET_break(0);
780     return;
781   }
782 }
783
784 /**
785  * Function called to notify transport users that another
786  * peer disconnected from us.
787  *
788  * @param cls closure
789  * @param peer the peer that disconnected
790  */
791 static void
792 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
793 {
794   if (0 != memcmp (&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
795     return;
796
797   if (NULL != th)
798   {
799     GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
800     th = NULL;
801   }
802   if (benchmark_send)
803   {
804     FPRINTF (stdout, _("Disconnected from peer `%s' while benchmarking\n"),
805         GNUNET_i2s (&pid));
806     if (GNUNET_SCHEDULER_NO_TASK != end)
807       GNUNET_SCHEDULER_cancel (end);
808     return;
809   }
810 }
811
812 /**
813  * Function called to notify transport users that another
814  * peer connected to us.
815  *
816  * @param cls closure
817  * @param peer the peer that connected
818  */
819 static void
820 monitor_notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer)
821 {
822   monitor_connect_counter++;
823   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
824   const char *now_str = GNUNET_STRINGS_absolute_time_to_string (now);
825
826   FPRINTF (stdout, _("%24s: %-17s %4s   (%u connections in total)\n"), now_str,
827       _("Connected to"), GNUNET_i2s (peer), monitor_connect_counter);
828 }
829
830 /**
831  * Function called to notify transport users that another
832  * peer disconnected from us.
833  *
834  * @param cls closure
835  * @param peer the peer that disconnected
836  */
837 static void
838 monitor_notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
839 {
840   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
841   const char *now_str = GNUNET_STRINGS_absolute_time_to_string (now);
842
843   GNUNET_assert(monitor_connect_counter > 0);
844   monitor_connect_counter--;
845
846   FPRINTF (stdout, _("%24s: %-17s %4s   (%u connections in total)\n"), now_str,
847       _("Disconnected from"), GNUNET_i2s (peer), monitor_connect_counter);
848 }
849
850 /**
851  * Function called by the transport for each received message.
852  *
853  * @param cls closure
854  * @param peer (claimed) identity of the other peer
855  * @param message the message
856  */
857 static void
858 notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
859     const struct GNUNET_MessageHeader *message)
860 {
861   if (benchmark_receive)
862   {
863     if (GNUNET_MESSAGE_TYPE_DUMMY != ntohs (message->type))
864       return;
865     if (verbosity > 0)
866       FPRINTF (stdout, _("Received %u bytes from %s\n"),
867           (unsigned int) ntohs (message->size), GNUNET_i2s (peer));
868
869     if (traffic_received == 0)
870       start_time = GNUNET_TIME_absolute_get ();
871     traffic_received += ntohs (message->size);
872     return;
873   }
874 }
875
876 static void
877 resolve_peer_address (const struct GNUNET_PeerIdentity *id,
878     const struct GNUNET_HELLO_Address *address, int numeric,
879     enum GNUNET_TRANSPORT_PeerState state,
880     struct GNUNET_TIME_Absolute state_timeout);
881
882 static void
883 print_info (const struct GNUNET_PeerIdentity *id, const char *transport,
884     const char *addr, enum GNUNET_TRANSPORT_PeerState state,
885     struct GNUNET_TIME_Absolute state_timeout)
886 {
887   if ((GNUNET_YES == iterate_all) || (GNUNET_YES == monitor_connections) )
888   {
889     FPRINTF (stdout, _("Peer `%s': %s %s in state `%s' until %s\n"),
890         GNUNET_i2s (id),
891         (NULL == transport) ? "<none>" : transport,
892         (NULL == transport) ? "<none>" : addr,
893         GNUNET_TRANSPORT_ps2s (state),
894         GNUNET_STRINGS_absolute_time_to_string (state_timeout));
895   }
896   else
897   {
898     /* Only connected peers, skip state */
899     FPRINTF (stdout, _("Peer `%s': %s %s\n"), GNUNET_i2s (id), transport, addr);
900   }
901
902 }
903
904 static void
905 process_peer_string (void *cls, const char *address)
906 {
907   struct PeerResolutionContext *rc = cls;
908
909   if (address != NULL )
910   {
911     print_info (&rc->id, rc->transport, address, rc->state, rc->state_timeout);
912     rc->printed = GNUNET_YES;
913   }
914   else
915   {
916     /* done */
917     GNUNET_assert(address_resolutions > 0);
918     address_resolutions--;
919     if (GNUNET_NO == rc->printed)
920     {
921       if (numeric == GNUNET_NO)
922       {
923         /* Failed to resolve address, try numeric lookup */
924         resolve_peer_address (&rc->id, rc->addrcp, GNUNET_YES,
925             rc->state, rc->state_timeout);
926       }
927       else
928       {
929         print_info (&rc->id, rc->transport, "<unable to resolve address>",
930             rc->state, rc->state_timeout);
931       }
932     }
933     GNUNET_free (rc->transport);
934     GNUNET_free (rc->addrcp);
935     GNUNET_CONTAINER_DLL_remove(rc_head, rc_tail, rc);
936     GNUNET_free(rc);
937     if ((0 == address_resolutions) && (iterate_connections))
938     {
939       if (GNUNET_SCHEDULER_NO_TASK != end)
940       {
941         GNUNET_SCHEDULER_cancel (end);
942         end = GNUNET_SCHEDULER_NO_TASK;
943       }
944       if (GNUNET_SCHEDULER_NO_TASK != op_timeout)
945       {
946         GNUNET_SCHEDULER_cancel (op_timeout);
947         op_timeout = GNUNET_SCHEDULER_NO_TASK;
948       }
949       ret = 0;
950       end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
951     }
952   }
953 }
954
955 static void
956 resolve_peer_address (const struct GNUNET_PeerIdentity *id,
957     const struct GNUNET_HELLO_Address *address, int numeric,
958     enum GNUNET_TRANSPORT_PeerState state,
959     struct GNUNET_TIME_Absolute state_timeout)
960 {
961   struct PeerResolutionContext *rc;
962
963   rc = GNUNET_new (struct PeerResolutionContext);
964   GNUNET_assert(NULL != rc);
965   GNUNET_CONTAINER_DLL_insert(rc_head, rc_tail, rc);
966   address_resolutions++;
967
968   rc->id = (*id);
969   rc->transport = GNUNET_strdup(address->transport_name);
970   rc->addrcp = GNUNET_HELLO_address_copy (address);
971   rc->printed = GNUNET_NO;
972   rc->state = state;
973   rc->state_timeout = state_timeout;
974   /* Resolve address to string */
975   rc->asc = GNUNET_TRANSPORT_address_to_string (cfg, address, numeric,
976       RESOLUTION_TIMEOUT, &process_peer_string, rc);
977 }
978
979 /**
980  * Function called with information about a peers during a one shot iteration
981  *
982  * @param cls closure
983  * @param peer identity of the peer, NULL for final callback when operation done
984  * @param address binary address used to communicate with this peer,
985  *  NULL on disconnect or when done
986  * @param state current state this peer is in
987  * @param state_timeout time out for the current state
988  *
989  */
990 static void
991 process_peer_iteration_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
992     const struct GNUNET_HELLO_Address *address,
993     enum GNUNET_TRANSPORT_PeerState state,
994     struct GNUNET_TIME_Absolute state_timeout)
995 {
996   if (peer == NULL )
997   {
998     /* done */
999     address_resolution_in_progress = GNUNET_NO;
1000     pic = NULL;
1001     if (GNUNET_SCHEDULER_NO_TASK != end)
1002       GNUNET_SCHEDULER_cancel (end);
1003     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
1004     return;
1005   }
1006
1007   if ((GNUNET_NO == iterate_all) && (GNUNET_NO == GNUNET_TRANSPORT_is_connected(state)) )
1008       return; /* Display only connected peers */
1009
1010   if (GNUNET_SCHEDULER_NO_TASK != op_timeout)
1011     GNUNET_SCHEDULER_cancel (op_timeout);
1012   op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1013       NULL );
1014
1015   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received address for peer `%s': %s\n",
1016       GNUNET_i2s (peer), address->transport_name);
1017
1018   if (NULL != address)
1019     resolve_peer_address (peer, address, numeric, state, state_timeout);
1020   else
1021     print_info (peer, NULL, NULL, state, state_timeout);
1022 }
1023
1024
1025 /**
1026  * Function called with information about a peers
1027  *
1028  * @param cls closure
1029  * @param peer identity of the peer, NULL for final callback when operation done
1030  * @param address binary address used to communicate with this peer,
1031  *  NULL on disconnect or when done
1032  * @param state current state this peer is in
1033  * @param state_timeout time out for the current state
1034  *
1035  */
1036 static void
1037 process_peer_monitoring_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
1038     const struct GNUNET_HELLO_Address *address,
1039     enum GNUNET_TRANSPORT_PeerState state,
1040     struct GNUNET_TIME_Absolute state_timeout)
1041 {
1042   struct MonitoredPeer *m;
1043
1044   if (peer == NULL )
1045   {
1046     /* done */
1047     address_resolution_in_progress = GNUNET_NO;
1048     pic = NULL;
1049     if (GNUNET_SCHEDULER_NO_TASK != end)
1050       GNUNET_SCHEDULER_cancel (end);
1051     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
1052     return;
1053   }
1054
1055   if (GNUNET_SCHEDULER_NO_TASK != op_timeout)
1056     GNUNET_SCHEDULER_cancel (op_timeout);
1057   op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1058       NULL );
1059
1060   if (NULL == (m = GNUNET_CONTAINER_multipeermap_get (monitored_peers, peer)))
1061   {
1062     m = GNUNET_new (struct MonitoredPeer);
1063     GNUNET_CONTAINER_multipeermap_put (monitored_peers, peer,
1064         m, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1065   }
1066   else
1067   {
1068     if ( (m->state == state) &&
1069       (m->state_timeout.abs_value_us == state_timeout.abs_value_us) &&
1070       ((NULL == address) && (NULL == m->address)) )
1071     {
1072       return; /* No real change */
1073     }
1074     if ( ((NULL != address) && (NULL != m->address)) &&
1075         (0 == GNUNET_HELLO_address_cmp(m->address, address)) )
1076       return; /* No real change */
1077   }
1078
1079
1080   if (NULL != m->address)
1081   {
1082     GNUNET_free (m->address);
1083     m->address = NULL;
1084   }
1085   if (NULL != address)
1086     m->address = GNUNET_HELLO_address_copy (address);
1087   m->state = state;
1088   m->state_timeout = state_timeout;
1089
1090   if (NULL != address)
1091     resolve_peer_address (peer, m->address, numeric, m->state, m->state_timeout);
1092   else
1093     print_info (peer, NULL, NULL, m->state, m->state_timeout);
1094 }
1095
1096 static void
1097 try_connect_cb (void *cls, const int result)
1098 {
1099   static int retries = 0;
1100   if (GNUNET_OK == result)
1101   {
1102     tc_handle = NULL;
1103     return;
1104   }
1105   retries++;
1106   if (retries < 10)
1107     tc_handle = GNUNET_TRANSPORT_try_connect (handle, &pid, try_connect_cb,
1108         NULL );
1109   else
1110   {
1111     FPRINTF (stderr, "%s",
1112         _("Failed to send connect request to transport service\n") );
1113     if (GNUNET_SCHEDULER_NO_TASK != end)
1114       GNUNET_SCHEDULER_cancel (end);
1115     ret = 1;
1116     end = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL );
1117     return;
1118   }
1119 }
1120
1121 /**
1122  * Function called with the result of the check if the 'transport'
1123  * service is running.
1124  *
1125  * @param cls closure with our configuration
1126  * @param result #GNUNET_YES if transport is running
1127  */
1128 static void
1129 testservice_task (void *cls, int result)
1130 {
1131   int counter = 0;
1132   ret = 1;
1133
1134   if (GNUNET_YES != result)
1135   {
1136     FPRINTF (stderr, _("Service `%s' is not running\n"), "transport");
1137     return;
1138   }
1139
1140   if ((NULL != cpid)
1141       && (GNUNET_OK
1142           != GNUNET_CRYPTO_eddsa_public_key_from_string (cpid, strlen (cpid),
1143               &pid.public_key)))
1144   {
1145     FPRINTF (stderr, _("Failed to parse peer identity `%s'\n"), cpid);
1146     return;
1147   }
1148
1149   counter = benchmark_send + benchmark_receive + iterate_connections
1150       + monitor_connections + monitor_connects + try_connect
1151       + iterate_validation + monitor_validation;
1152
1153   if (1 < counter)
1154   {
1155     FPRINTF (stderr,
1156         _("Multiple operations given. Please choose only one operation: %s, %s, %s, %s, %s, %s\n"),
1157         "connect", "benchmark send", "benchmark receive", "information",
1158         "monitor", "events");
1159     return;
1160   }
1161   if (0 == counter)
1162   {
1163     FPRINTF (stderr,
1164         _("No operation given. Please choose one operation: %s, %s, %s, %s, %s, %s\n"),
1165         "connect", "benchmark send", "benchmark receive", "information",
1166         "monitor", "events");
1167     return;
1168   }
1169
1170   if (try_connect) /* -C: Connect to peer */
1171   {
1172     if (NULL == cpid)
1173     {
1174       FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
1175           "-C", "-p");
1176       ret = 1;
1177       return;
1178     }
1179     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, &notify_receive,
1180         &notify_connect, &notify_disconnect);
1181     if (NULL == handle)
1182     {
1183       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n") );
1184       ret = 1;
1185       return;
1186     }
1187     tc_handle = GNUNET_TRANSPORT_try_connect (handle, &pid, try_connect_cb,
1188         NULL );
1189     if (NULL == tc_handle)
1190     {
1191       FPRINTF (stderr, "%s",
1192           _("Failed to send request to transport service\n") );
1193       ret = 1;
1194       return;
1195     }
1196     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1197         NULL );
1198
1199   }
1200   else if (benchmark_send) /* -s: Benchmark sending */
1201   {
1202     if (NULL == cpid)
1203     {
1204       FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
1205           "-s", "-p");
1206       ret = 1;
1207       return;
1208     }
1209     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, &notify_receive,
1210         &notify_connect, &notify_disconnect);
1211     if (NULL == handle)
1212     {
1213       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n") );
1214       ret = 1;
1215       return;
1216     }
1217     tc_handle = GNUNET_TRANSPORT_try_connect (handle, &pid, try_connect_cb,
1218         NULL );
1219     if (NULL == tc_handle)
1220     {
1221       FPRINTF (stderr, "%s",
1222           _("Failed to send request to transport service\n") );
1223       ret = 1;
1224       return;
1225     }
1226     start_time = GNUNET_TIME_absolute_get ();
1227     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1228         NULL );
1229   }
1230   else if (benchmark_receive) /* -b: Benchmark receiving */
1231   {
1232     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, &notify_receive, NULL,
1233         NULL );
1234     if (NULL == handle)
1235     {
1236       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n") );
1237       ret = 1;
1238       return;
1239     }
1240     if (verbosity > 0)
1241       FPRINTF (stdout, "%s", _("Starting to receive benchmark data\n") );
1242     start_time = GNUNET_TIME_absolute_get ();
1243
1244   }
1245   else if (iterate_connections) /* -i: List information about peers once */
1246   {
1247     address_resolution_in_progress = GNUNET_YES;
1248     pic = GNUNET_TRANSPORT_monitor_peers (cfg, (NULL == cpid) ? NULL : &pid,
1249         GNUNET_YES, TIMEOUT, &process_peer_iteration_cb, (void *) cfg);
1250     op_timeout = GNUNET_SCHEDULER_add_delayed (OP_TIMEOUT, &operation_timeout,
1251         NULL );
1252   }
1253   else if (monitor_connections) /* -m: List information about peers continuously */
1254   {
1255     monitored_peers = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1256     address_resolution_in_progress = GNUNET_YES;
1257     pic = GNUNET_TRANSPORT_monitor_peers (cfg, (NULL == cpid) ? NULL : &pid,
1258         GNUNET_NO, TIMEOUT, &process_peer_monitoring_cb, (void *) cfg);
1259   }
1260   else if (iterate_validation) /* -d: Print information about validations */
1261   {
1262     vic = GNUNET_TRANSPORT_monitor_validation_entries (cfg,
1263         (NULL == cpid) ? NULL : &pid,
1264         GNUNET_YES, TIMEOUT, &process_validation_cb, (void *) cfg);
1265   }
1266   else if (monitor_validation) /* -f: Print information about validations continuously */
1267   {
1268     vic = GNUNET_TRANSPORT_monitor_validation_entries (cfg,
1269         (NULL == cpid) ? NULL : &pid,
1270         GNUNET_NO, TIMEOUT, &process_validation_cb, (void *) cfg);
1271   }
1272   else if (monitor_connects) /* -e : Monitor (dis)connect events continuously */
1273   {
1274     monitor_connect_counter = 0;
1275     handle = GNUNET_TRANSPORT_connect (cfg, NULL, NULL, NULL,
1276         &monitor_notify_connect, &monitor_notify_disconnect);
1277     if (NULL == handle)
1278     {
1279       FPRINTF (stderr, "%s", _("Failed to connect to transport service\n") );
1280       ret = 1;
1281       return;
1282     }
1283     ret = 0;
1284   }
1285   else
1286   {
1287     GNUNET_break(0);
1288     return;
1289   }
1290
1291   end = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1292       &shutdown_task, NULL );
1293
1294 }
1295
1296 /**
1297  * Main function that will be run by the scheduler.
1298  *
1299  * @param cls closure
1300  * @param args remaining command-line arguments
1301  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1302  * @param mycfg configuration
1303  */
1304 static void
1305 run (void *cls, char * const *args, const char *cfgfile,
1306     const struct GNUNET_CONFIGURATION_Handle *mycfg)
1307 {
1308   cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
1309   if (test_configuration)
1310   {
1311     do_test_configuration (cfg);
1312     return;
1313   }
1314   GNUNET_CLIENT_service_test ("transport", cfg, GNUNET_TIME_UNIT_SECONDS,
1315       &testservice_task, (void *) cfg);
1316 }
1317
1318 int
1319 main (int argc, char * const *argv)
1320 {
1321   int res;
1322   static const struct GNUNET_GETOPT_CommandLineOption options[] =
1323       {
1324           { 'a', "all", NULL,
1325               gettext_noop ("print information for all peers (instead of only connected peers )"),
1326               0, &GNUNET_GETOPT_set_one, &iterate_all },
1327           { 'b', "benchmark", NULL,
1328               gettext_noop ("measure how fast we are receiving data from all peers (until CTRL-C)"),
1329               0, &GNUNET_GETOPT_set_one, &benchmark_receive }, { 'C', "connect",
1330               NULL, gettext_noop ("connect to a peer"), 0,
1331               &GNUNET_GETOPT_set_one, &try_connect },
1332           { 'd', "validation", NULL,
1333               gettext_noop ("print information for all pending validations "),
1334               0, &GNUNET_GETOPT_set_one, &iterate_validation },
1335           { 'f', "monitorvalidation", NULL,
1336               gettext_noop ("print information for all pending validations continously"),
1337               0, &GNUNET_GETOPT_set_one, &monitor_validation },
1338           { 'i', "information", NULL,
1339               gettext_noop ("provide information about all current connections (once)"),
1340               0, &GNUNET_GETOPT_set_one, &iterate_connections },
1341           { 'm', "monitor", NULL,
1342               gettext_noop ("provide information about all current connections (continuously)"),
1343               0, &GNUNET_GETOPT_set_one, &monitor_connections },
1344           { 'e', "events", NULL,
1345               gettext_noop ("provide information about all connects and disconnect events (continuously)"),
1346               0, &GNUNET_GETOPT_set_one, &monitor_connects }, { 'n', "numeric",
1347               NULL, gettext_noop ("do not resolve hostnames"), 0,
1348               &GNUNET_GETOPT_set_one, &numeric }, { 'p', "peer", "PEER",
1349               gettext_noop ("peer identity"), 1, &GNUNET_GETOPT_set_string,
1350               &cpid }, { 's', "send", NULL, gettext_noop
1351           ("send data for benchmarking to the other peer (until CTRL-C)"), 0,
1352               &GNUNET_GETOPT_set_one, &benchmark_send },
1353           { 't', "test", NULL,
1354               gettext_noop ("test transport configuration (involves external server)"),
1355               0, &GNUNET_GETOPT_set_one, &test_configuration },
1356               GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
1357               GNUNET_GETOPT_OPTION_END };
1358
1359   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1360     return 2;
1361
1362   res = GNUNET_PROGRAM_run (argc, argv, "gnunet-transport", gettext_noop
1363   ("Direct access to transport service."), options, &run, NULL );
1364   GNUNET_free((void * ) argv);
1365   if (GNUNET_OK == res)
1366     return ret;
1367   return 1;
1368 }
1369
1370 /* end of gnunet-transport.c */