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