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