- moved timeout handling responsibility from for nat tests from caller to the library
[oweals/gnunet.git] / src / cadet / gnunet-cadet.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 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 cadet/gnunet-cadet.c
23  * @brief Print information about cadet tunnels and peers.
24  * @author Bartlomiej Polot
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_cadet_service.h"
29 #include "cadet.h"
30
31
32 /**
33  * Option -m.
34  */
35 static int monitor_connections;
36
37 /**
38  * Option -P.
39  */
40 static int request_peers;
41
42 /**
43  * Option --peer
44  */
45 static char *peer_id;
46
47 /**
48  * Option -T.
49  */
50 static int request_tunnels;
51
52 /**
53  * Option --tunnel
54  */
55 static char *tunnel_id;
56
57 /**
58  * Option --connection
59  */
60 static char *conn_id;
61
62 /**
63  * Option --channel
64  */
65 static char *channel_id;
66
67 /**
68  * Port to listen on (-p).
69  */
70 static uint32_t listen_port;
71
72 /**
73  * Request echo service
74  */
75 int echo;
76
77 /**
78  * Time of last echo request.
79  */
80 struct GNUNET_TIME_Absolute echo_time;
81
82 /**
83  * Task for next echo request.
84  */
85 GNUNET_SCHEDULER_TaskIdentifier echo_task;
86
87 /**
88  * Peer to connect to.
89  */
90 static char *target_id;
91
92 /**
93  * Port to connect to
94  */
95 static uint32_t target_port;
96
97 /**
98  * Data pending in netcat mode.
99  */
100 size_t data_size;
101
102
103 /**
104  * Cadet handle.
105  */
106 static struct GNUNET_CADET_Handle *mh;
107
108 /**
109  * Channel handle.
110  */
111 static struct GNUNET_CADET_Channel *ch;
112
113 /**
114  * Shutdown task handle.
115  */
116 GNUNET_SCHEDULER_TaskIdentifier sd;
117
118
119
120 static void
121 listen_stdio (void);
122
123
124
125 /**
126  * Task run in monitor mode when the user presses CTRL-C to abort.
127  * Stops monitoring activity.
128  *
129  * @param cls Closure (unused).
130  * @param tc scheduler context
131  */
132 static void
133 shutdown_task (void *cls,
134                const struct GNUNET_SCHEDULER_TaskContext *tc)
135 {
136   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
137   if (NULL != ch)
138   {
139     GNUNET_CADET_channel_destroy (ch);
140     ch = NULL;
141   }
142   if (NULL != mh)
143   {
144     GNUNET_CADET_disconnect (mh);
145         mh = NULL;
146   }
147 }
148
149
150 /**
151  * Function called to notify a client about the connection
152  * begin ready to queue more data.  "buf" will be
153  * NULL and "size" zero if the connection was closed for
154  * writing in the meantime.
155  *
156  * FIXME
157  *
158  * @param cls closure
159  * @param size number of bytes available in buf
160  * @param buf where the callee should write the message
161  * @return number of bytes written to buf
162  */
163 size_t
164 data_ready (void *cls, size_t size, void *buf)
165 {
166   struct GNUNET_MessageHeader *msg;
167   size_t total_size;
168
169   if (NULL == buf || 0 == size)
170   {
171     GNUNET_SCHEDULER_shutdown();
172     return 0;
173   }
174
175   total_size = data_size + sizeof (struct GNUNET_MessageHeader);
176   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending %u bytes\n", data_size);
177   GNUNET_assert (size >= total_size);
178
179   msg = buf;
180   msg->size = htons (total_size);
181   msg->type = htons (GNUNET_MESSAGE_TYPE_CADET_CLI);
182   memcpy (&msg[1], cls, data_size);
183   if (GNUNET_NO == echo)
184   {
185     listen_stdio ();
186   }
187   else
188   {
189     echo_time = GNUNET_TIME_absolute_get ();
190   }
191
192   return total_size;
193 }
194
195
196 /**
197  * Task run in monitor mode when the user presses CTRL-C to abort.
198  * Stops monitoring activity.
199  *
200  * @param cls Closure (unused).
201  * @param tc scheduler context
202  */
203 static void
204 read_stdio (void *cls,
205             const struct GNUNET_SCHEDULER_TaskContext *tc)
206 {
207   static char buf[60000];
208
209   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
210   {
211     return;
212   }
213
214   data_size = read (0, buf, 60000);
215   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stdio read %u bytes\n", data_size);
216   if (data_size < 1)
217   {
218     GNUNET_SCHEDULER_shutdown();
219     return;
220   }
221   GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
222                                      GNUNET_TIME_UNIT_FOREVER_REL,
223                                      data_size
224                                      + sizeof (struct GNUNET_MessageHeader),
225                                      &data_ready, buf);
226 }
227
228
229 /**
230  * Start listening to stdin
231  */
232 static void
233 listen_stdio (void)
234 {
235   struct GNUNET_NETWORK_FDSet *rs;
236
237   rs = GNUNET_NETWORK_fdset_create ();
238   GNUNET_NETWORK_fdset_set_native (rs, 0);
239   GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
240                                GNUNET_TIME_UNIT_FOREVER_REL,
241                                rs, NULL,
242                                &read_stdio, NULL);
243   GNUNET_NETWORK_fdset_destroy (rs);
244 }
245
246
247 /**
248  * Function called whenever a channel is destroyed.  Should clean up
249  * any associated state.
250  *
251  * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
252  *
253  * @param cls closure (set from #GNUNET_CADET_connect)
254  * @param channel connection to the other end (henceforth invalid)
255  * @param channel_ctx place where local state associated
256  *                   with the channel is stored
257  */
258 static void
259 channel_ended (void *cls,
260                const struct GNUNET_CADET_Channel *channel,
261                void *channel_ctx)
262 {
263   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n");
264   GNUNET_break (channel == ch);
265   ch = NULL;
266   GNUNET_SCHEDULER_shutdown ();
267 }
268
269
270 /**
271  * Method called whenever another peer has added us to a channel
272  * the other peer initiated.
273  * Only called (once) upon reception of data with a message type which was
274  * subscribed to in #GNUNET_CADET_connect.
275  *
276  * A call to #GNUNET_CADET_channel_destroy causes te channel to be ignored. In
277  * this case the handler MUST return NULL.
278  *
279  * @param cls closure
280  * @param channel new handle to the channel
281  * @param initiator peer that started the channel
282  * @param port Port this channel is for.
283  * @param options CadetOption flag field, with all active option bits set to 1.
284  *
285  * @return initial channel context for the channel
286  *         (can be NULL -- that's not an error)
287  */
288 static void *
289 channel_incoming (void *cls,
290                   struct GNUNET_CADET_Channel * channel,
291                   const struct GNUNET_PeerIdentity * initiator,
292                   uint32_t port, enum GNUNET_CADET_ChannelOption options)
293 {
294   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
295               "Incoming channel %p on port %u\n",
296               channel, port);
297   if (NULL != ch)
298   {
299     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "A channel already exists\n");
300     return NULL;
301   }
302   if (0 == listen_port)
303   {
304     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not listening to channels\n");
305     return NULL;
306   }
307   ch = channel;
308   if (GNUNET_NO == echo)
309   {
310     listen_stdio ();
311     return NULL;
312   }
313   data_size = 0;
314   return NULL;
315 }
316
317 /**
318  * @brief Send an echo request to the remote peer.
319  *
320  * @param cls Closure (NULL).
321  * @param tc Task context.
322  */
323 static void
324 send_echo (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
325 {
326   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) || NULL == ch)
327     return;
328
329   GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
330                                      GNUNET_TIME_UNIT_FOREVER_REL,
331                                      sizeof (struct GNUNET_MessageHeader),
332                                      &data_ready, NULL);
333 }
334
335
336
337 /**
338  * Call CADET's monitor API, get info of one connection.
339  *
340  * @param cls Closure (unused).
341  * @param tc TaskContext
342  */
343 static void
344 create_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
345 {
346   struct GNUNET_PeerIdentity pid;
347   enum GNUNET_CADET_ChannelOption opt;
348
349   GNUNET_assert (NULL == ch);
350
351   if (GNUNET_OK !=
352       GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
353                                                   strlen (target_id),
354                                                   &pid.public_key))
355   {
356     FPRINTF (stderr,
357              _("Invalid target `%s'\n"),
358              target_id);
359     GNUNET_SCHEDULER_shutdown ();
360     return;
361   }
362   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id);
363   opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE;
364   ch = GNUNET_CADET_channel_create (mh, NULL, &pid, target_port, opt);
365   if (GNUNET_NO == echo)
366     listen_stdio ();
367   else
368     GNUNET_SCHEDULER_add_now (send_echo, NULL);
369 }
370
371
372 /**
373  * Function called whenever a message is received.
374  *
375  * Each time the function must call #GNUNET_CADET_receive_done on the channel
376  * in order to receive the next message. This doesn't need to be immediate:
377  * can be delayed if some processing is done on the message.
378  *
379  * @param cls Closure (set from #GNUNET_CADET_connect).
380  * @param channel Connection to the other end.
381  * @param channel_ctx Place to store local state associated with the channel.
382  * @param message The actual message.
383  * @return #GNUNET_OK to keep the channel open,
384  *         #GNUNET_SYSERR to close it (signal serious error).
385  */
386 static int
387 data_callback (void *cls,
388                struct GNUNET_CADET_Channel *channel,
389                void **channel_ctx,
390                const struct GNUNET_MessageHeader *message)
391 {
392   uint16_t len;
393   ssize_t done;
394   uint16_t off;
395   const char *buf;
396   GNUNET_break (ch == channel);
397
398   if (GNUNET_YES == echo)
399   {
400     if (0 != listen_port)
401     {
402       /* Just listening to echo incoming messages*/
403       GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
404                                         GNUNET_TIME_UNIT_FOREVER_REL,
405                                         sizeof (struct GNUNET_MessageHeader),
406                                         &data_ready, NULL);
407       return GNUNET_OK;
408     }
409     else
410     {
411       struct GNUNET_TIME_Relative latency;
412
413       latency = GNUNET_TIME_absolute_get_duration (echo_time);
414       echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
415       FPRINTF (stdout, "time: %s\n",
416                GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
417       echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
418                                                 &send_echo, NULL);
419     }
420   }
421
422   len = ntohs (message->size) - sizeof (*message);
423   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len);
424   buf = (const char *) &message[1];
425   off = 0;
426   while (off < len)
427   {
428     done = write (1, &buf[off], len - off);
429     if (done <= 0)
430     {
431       if (-1 == done)
432         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
433                              "write");
434       return GNUNET_SYSERR;
435     }
436     off += done;
437   }
438   return GNUNET_OK;
439 }
440
441
442 /**
443  * Method called to retrieve information about all peers in CADET, called
444  * once per peer.
445  *
446  * After last peer has been reported, an additional call with NULL is done.
447  *
448  * @param cls Closure.
449  * @param peer Peer, or NULL on "EOF".
450  * @param tunnel Do we have a tunnel towards this peer?
451  * @param n_paths Number of known paths towards this peer.
452  * @param best_path How long is the best path?
453  *                  (0 = unknown, 1 = ourselves, 2 = neighbor)
454  */
455 static void
456 peers_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
457                 int tunnel, unsigned int n_paths, unsigned int best_path)
458 {
459   if (NULL == peer)
460   {
461     if (GNUNET_YES != monitor_connections)
462     {
463       GNUNET_SCHEDULER_shutdown();
464     }
465     return;
466   }
467   FPRINTF (stdout, "%s tunnel: %c, paths: %u\n",
468            GNUNET_i2s_full (peer), tunnel ? 'Y' : 'N', n_paths);
469 }
470
471 /**
472  * Method called to retrieve information about a specific peer
473  * known to the service.
474  *
475  * @param cls Closure.
476  * @param peer Peer ID.
477  * @param tunnel Do we have a tunnel towards this peer? #GNUNET_YES/#GNUNET_NO
478  * @param neighbor Is this a direct neighbor? #GNUNET_YES/#GNUNET_NO
479  * @param n_paths Number of paths known towards peer.
480  * @param paths Array of PEER_IDs representing all paths to reach the peer.
481  *              Each path starts with the local peer.
482  *              Each path ends with the destination peer (given in @c peer).
483  */
484 void
485 peer_callback (void *cls,
486                const struct GNUNET_PeerIdentity *peer,
487                int tunnel,
488                int neighbor,
489                unsigned int n_paths,
490                struct GNUNET_PeerIdentity *paths)
491 {
492 }
493
494
495 /**
496  * Method called to retrieve information about all tunnels in CADET.
497  *
498  * @param cls Closure.
499  * @param peer Destination peer.
500  * @param channels Number of channels.
501  * @param connections Number of connections.
502  * @param estate Encryption state.
503  * @param cstate Connectivity state.
504  */
505 void
506 tunnels_callback (void *cls,
507                   const struct GNUNET_PeerIdentity *peer,
508                   unsigned int channels,
509                   unsigned int connections,
510                   uint16_t estate,
511                   uint16_t cstate)
512 {
513   if (NULL == peer)
514   {
515     if (GNUNET_YES != monitor_connections)
516     {
517       GNUNET_SCHEDULER_shutdown();
518     }
519     return;
520   }
521   FPRINTF (stdout, "%s [ENC: %u, CON: %u] CHs: %u, CONNs: %u\n",
522            GNUNET_i2s_full (peer), estate, cstate, channels, connections);
523 }
524
525
526 /**
527  * Method called to retrieve information about a specific tunnel the cadet peer
528  * has established, o`r is trying to establish.
529  *
530  * @param cls Closure.
531  * @param peer Peer towards whom the tunnel is directed.
532  * @param n_channels Number of channels.
533  * @param n_connections Number of connections.
534  * @param channels Channels.
535  * @param connections Connections.
536  * @param estate Encryption status.
537  * @param cstate Connectivity status.
538  */
539 void
540 tunnel_callback (void *cls,
541                  const struct GNUNET_PeerIdentity *peer,
542                  unsigned int n_channels,
543                  unsigned int n_connections,
544                  uint32_t *channels,
545                  struct GNUNET_CADET_Hash *connections,
546                  unsigned int estate,
547                  unsigned int cstate)
548 {
549   unsigned int i;
550
551   if (NULL != peer)
552   {
553     FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer));
554     FPRINTF (stdout, "- %u channels\n", n_channels);
555     for (i = 0; i < n_channels; i++)
556       FPRINTF (stdout, "   %u\n", channels[i]);
557     FPRINTF (stdout, "- %u connections\n", n_connections);
558     for (i = 0; i < n_connections; i++)
559       FPRINTF (stdout, "   %s\n", GC_h2s (&connections[i]));
560     FPRINTF (stdout, "- enc state: %u\n", estate);
561     FPRINTF (stdout, "- con state: %u\n", cstate);
562   }
563   if (GNUNET_YES != monitor_connections)
564   {
565     GNUNET_SCHEDULER_shutdown();
566   }
567   return;
568
569 }
570
571
572 /**
573  * Call CADET's meta API, get all peers known to a peer.
574  *
575  * @param cls Closure (unused).
576  * @param tc TaskContext
577  */
578 static void
579 get_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
580 {
581   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
582   {
583     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
584     return;
585   }
586   GNUNET_CADET_get_peers (mh, &peers_callback, NULL);
587 }
588
589
590 /**
591  * Call CADET's monitor API, get info of one peer.
592  *
593  * @param cls Closure (unused).
594  * @param tc TaskContext
595  */
596 static void
597 show_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
598 {
599   struct GNUNET_PeerIdentity pid;
600
601   if (GNUNET_OK !=
602     GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
603                                                 strlen (peer_id),
604                                                 &pid.public_key))
605   {
606     fprintf (stderr,
607              _("Invalid peer ID `%s'\n"),
608              peer_id);
609     GNUNET_SCHEDULER_shutdown();
610     return;
611   }
612   GNUNET_CADET_get_peer (mh, &pid, peer_callback, NULL);
613 }
614
615 /**
616  * Call CADET's meta API, get all tunnels known to a peer.
617  *
618  * @param cls Closure (unused).
619  * @param tc TaskContext
620  */
621 static void
622 get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
623 {
624   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
625   {
626     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
627     return;
628   }
629   GNUNET_CADET_get_tunnels (mh, &tunnels_callback, NULL);
630 }
631
632
633 /**
634  * Call CADET's monitor API, get info of one tunnel.
635  *
636  * @param cls Closure (unused).
637  * @param tc TaskContext
638  */
639 static void
640 show_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
641 {
642   struct GNUNET_PeerIdentity pid;
643
644   if (GNUNET_OK !=
645       GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
646                                                   strlen (tunnel_id),
647                                                   &pid.public_key))
648   {
649     fprintf (stderr,
650              _("Invalid tunnel owner `%s'\n"),
651              tunnel_id);
652     GNUNET_SCHEDULER_shutdown();
653     return;
654   }
655   GNUNET_CADET_get_tunnel (mh, &pid, tunnel_callback, NULL);
656 }
657
658
659 /**
660  * Call CADET's monitor API, get info of one channel.
661  *
662  * @param cls Closure (unused).
663  * @param tc TaskContext
664  */
665 static void
666 show_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
667 {
668
669 }
670
671
672 /**
673  * Call CADET's monitor API, get info of one connection.
674  *
675  * @param cls Closure (unused).
676  * @param tc TaskContext
677  */
678 static void
679 show_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
680 {
681
682 }
683
684
685 /**
686  * Main function that will be run by the scheduler.
687  *
688  * @param cls closure
689  * @param args remaining command-line arguments
690  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
691  * @param cfg configuration
692  */
693 static void
694 run (void *cls, char *const *args, const char *cfgfile,
695      const struct GNUNET_CONFIGURATION_Handle *cfg)
696 {
697   GNUNET_CADET_InboundChannelNotificationHandler *newch = NULL;
698   GNUNET_CADET_ChannelEndHandler *endch = NULL;
699   static const struct GNUNET_CADET_MessageHandler handlers[] = {
700     {&data_callback, GNUNET_MESSAGE_TYPE_CADET_CLI, 0},
701     {NULL, 0, 0} /* FIXME add option to monitor msg types */
702   };
703   static uint32_t *ports = NULL;
704   /* FIXME add option to monitor apps */
705
706   target_id = args[0];
707   target_port = args[0] && args[1] ? atoi(args[1]) : 0;
708   if ( (0 != (request_peers | request_tunnels)
709         || 0 != monitor_connections
710         || NULL != tunnel_id
711         || NULL != conn_id
712         || NULL != channel_id)
713        && target_id != NULL)
714   {
715     FPRINTF (stderr,
716              _("You must NOT give a TARGET"
717                "when using 'request all' options\n"));
718     return;
719   }
720
721   if (NULL != target_id)
722   {
723     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
724                 "Creating channel to %s\n",
725                 target_id);
726     GNUNET_SCHEDULER_add_now (&create_channel, NULL);
727     endch = &channel_ended;
728   }
729   else if (0 != listen_port)
730   {
731     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Listen\n");
732     newch = &channel_incoming;
733     endch = &channel_ended;
734     ports = GNUNET_malloc (sizeof (uint32_t) * 2);
735     ports[0] = listen_port;
736   }
737   else if (NULL != peer_id)
738   {
739     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show peer\n");
740     GNUNET_SCHEDULER_add_now (&show_peer, NULL);
741   }
742   else if (NULL != tunnel_id)
743   {
744     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n");
745     GNUNET_SCHEDULER_add_now (&show_tunnel, NULL);
746   }
747   else if (NULL != channel_id)
748   {
749     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n");
750     GNUNET_SCHEDULER_add_now (&show_channel, NULL);
751   }
752   else if (NULL != conn_id)
753   {
754     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
755     GNUNET_SCHEDULER_add_now (&show_connection, NULL);
756   }
757   else if (GNUNET_YES == request_peers)
758   {
759     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n");
760     GNUNET_SCHEDULER_add_now (&get_peers, NULL);
761   }
762   else if (GNUNET_YES == request_tunnels)
763   {
764     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
765     GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
766   }
767   else
768   {
769     FPRINTF (stderr, "No action requested\n");
770     return;
771   }
772
773   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to cadet\n");
774   mh = GNUNET_CADET_connect (cfg,
775                             NULL, /* cls */
776                             newch, /* new channel */
777                             endch, /* cleaner */
778                             handlers,
779                             ports);
780   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done\n");
781   if (NULL == mh)
782     GNUNET_SCHEDULER_add_now (shutdown_task, NULL);
783   else
784     sd = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
785                                        shutdown_task, NULL);
786
787 }
788
789
790 /**
791  * The main function to obtain peer information.
792  *
793  * @param argc number of arguments from the command line
794  * @param argv command line arguments
795  * @return 0 ok, 1 on error
796  */
797 int
798 main (int argc, char *const *argv)
799 {
800   int res;
801   const char helpstr[] = "Create channels and retreive info about cadets status.";
802   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
803 //     {'a', "channel", "TUNNEL_ID:CHANNEL_ID",
804 //      gettext_noop ("provide information about a particular channel"),
805 //      GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id},
806     {'C', "connection", "CONNECTION_ID",
807      gettext_noop ("provide information about a particular connection"),
808      GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id},
809     {'e', "echo", NULL,
810      gettext_noop ("activate echo mode"),
811      GNUNET_NO, &GNUNET_GETOPT_set_one, &echo},
812 //     {'m', "monitor", NULL,
813 //      gettext_noop ("provide information about all events (continuously)"),
814 //      GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_mode},
815     {'o', "open-port", NULL,
816      gettext_noop ("port to listen to (default; 0)"),
817      GNUNET_YES, &GNUNET_GETOPT_set_uint, &listen_port},
818     {'p', "peer", "PEER_ID",
819      gettext_noop ("provide information about a patricular peer"),
820      GNUNET_YES, &GNUNET_GETOPT_set_string, &peer_id},
821     {'P', "peers", NULL,
822       gettext_noop ("provide information about all peers"),
823       GNUNET_NO, &GNUNET_GETOPT_set_one, &request_peers},
824     {'t', "tunnel", "TUNNEL_ID",
825      gettext_noop ("provide information about a particular tunnel"),
826      GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id},
827     {'T', "tunnels", NULL,
828      gettext_noop ("provide information about all tunnels"),
829      GNUNET_NO, &GNUNET_GETOPT_set_one, &request_tunnels},
830
831     GNUNET_GETOPT_OPTION_END
832   };
833
834   monitor_connections = GNUNET_NO;
835
836   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
837     return 2;
838
839   res = GNUNET_PROGRAM_run (argc, argv, "gnunet-cadet (OPTIONS | TARGET PORT)",
840                             gettext_noop (helpstr),
841                             options, &run, NULL);
842
843   GNUNET_free ((void *) argv);
844
845   if (GNUNET_OK == res)
846     return 0;
847   else
848     return 1;
849 }
850
851 /* end of gnunet-cadet.c */