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