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