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