refactor DHT for new service API
[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   data_size = read (0, buf, 60000);
317   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
318               "stdio read %u bytes\n",
319               (unsigned int) data_size);
320   if (data_size < 1)
321   {
322     GNUNET_SCHEDULER_shutdown();
323     return;
324   }
325   GNUNET_assert (NULL == th);
326   th = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
327                                            GNUNET_TIME_UNIT_FOREVER_REL,
328                                            sizeof (struct GNUNET_MessageHeader)
329                                            + data_size,
330                                            &data_ready, buf);
331 }
332
333
334 /**
335  * Start listening to stdin
336  */
337 static void
338 listen_stdio (void)
339 {
340   struct GNUNET_NETWORK_FDSet *rs;
341
342   rs = GNUNET_NETWORK_fdset_create ();
343   GNUNET_NETWORK_fdset_set_native (rs, 0);
344   rd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
345                                          GNUNET_TIME_UNIT_FOREVER_REL,
346                                          rs, NULL,
347                                          &read_stdio, NULL);
348   GNUNET_NETWORK_fdset_destroy (rs);
349 }
350
351
352 /**
353  * Function called whenever a channel is destroyed.  Should clean up
354  * any associated state.
355  *
356  * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
357  *
358  * @param cls closure (set from #GNUNET_CADET_connect)
359  * @param channel connection to the other end (henceforth invalid)
360  * @param channel_ctx place where local state associated
361  *                   with the channel is stored
362  */
363 static void
364 channel_ended (void *cls,
365                const struct GNUNET_CADET_Channel *channel,
366                void *channel_ctx)
367 {
368   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n");
369   if (channel != ch)
370   {
371     GNUNET_break (0);
372     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ended: %p, expected: %p\n", channel, ch);
373   }
374   else
375   {
376     ch = NULL;
377   }
378   if (NULL != th)
379   {
380     GNUNET_CADET_notify_transmit_ready_cancel (th);
381     th = NULL;
382   }
383
384   GNUNET_SCHEDULER_shutdown ();
385 }
386
387
388 /**
389  * Method called whenever another peer has added us to a channel
390  * the other peer initiated.
391  * Only called (once) upon reception of data with a message type which was
392  * subscribed to in #GNUNET_CADET_connect.
393  *
394  * A call to #GNUNET_CADET_channel_destroy causes the channel to be ignored.
395  * In this case the handler MUST return NULL.
396  *
397  * @param cls closure
398  * @param channel new handle to the channel
399  * @param initiator peer that started the channel
400  * @param port Port this channel is for.
401  * @param options CadetOption flag field, with all active option bits set to 1.
402  *
403  * @return initial channel context for the channel
404  *         (can be NULL -- that's not an error)
405  */
406 static void *
407 channel_incoming (void *cls,
408                   struct GNUNET_CADET_Channel *channel,
409                   const struct GNUNET_PeerIdentity *initiator,
410                   const struct GNUNET_HashCode *port,
411                   enum GNUNET_CADET_ChannelOption options)
412 {
413   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
414               "Connected from %s\n",
415               GNUNET_i2s_full (initiator));
416   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
417               "Incoming channel %p on port %s\n",
418               channel, GNUNET_h2s (port));
419   if (NULL != ch)
420   {
421     GNUNET_break (0);
422     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
423                 "A channel already exists (%p)\n", ch);
424     /*
425      * From now on multiple channels will be sending data to us
426      * making the service of this command unpredictable in its
427      * current implementation. So for now let's just bail out.
428      */
429     GNUNET_SCHEDULER_shutdown();
430     return NULL;
431   }
432   if (NULL == listen_port)
433   {
434     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Not listening to channels\n");
435     return NULL;
436   }
437 #if 0
438   // Closing the listen port currently breaks open connections.
439   // Is this an intentional departure from POSIX socket behavior?
440   //
441   if (NULL != lp) {
442     /* Now that we have our circuit up and running, let's not
443      * get confused by further incoming connect requests.
444      */
445     GNUNET_CADET_close_port (lp);
446     lp = NULL;
447   }
448 #endif
449   ch = channel;
450   if (GNUNET_NO == echo)
451   {
452     listen_stdio ();
453     return NULL;
454   }
455   data_size = 0;
456   return NULL;
457 }
458
459 /**
460  * @brief Send an echo request to the remote peer.
461  *
462  * @param cls Closure (NULL).
463  */
464 static void
465 send_echo (void *cls)
466 {
467   if (NULL == ch)
468     return;
469   GNUNET_assert (NULL == th);
470   th = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
471                                            GNUNET_TIME_UNIT_FOREVER_REL,
472                                            sizeof (struct GNUNET_MessageHeader),
473                                            &data_ready, NULL);
474 }
475
476
477 /**
478  * Call CADET's monitor API, request debug dump on the service.
479  *
480  * @param cls Closure (unused).
481  */
482 static void
483 request_dump (void *cls)
484 {
485   GNUNET_CADET_request_dump (mh);
486   GNUNET_SCHEDULER_cancel (sd);
487   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
488                                 &shutdown_task, NULL);
489 }
490
491
492 /**
493  * Call CADET's monitor API, get info of one connection.
494  *
495  * @param cls Closure (unused).
496  */
497 static void
498 create_channel (void *cls)
499 {
500   struct GNUNET_PeerIdentity pid;
501   enum GNUNET_CADET_ChannelOption opt;
502
503   GNUNET_assert (NULL == ch);
504
505   if (GNUNET_OK !=
506       GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
507                                                   strlen (target_id),
508                                                   &pid.public_key))
509   {
510     FPRINTF (stderr,
511              _("Invalid target `%s'\n"),
512              target_id);
513     GNUNET_SCHEDULER_shutdown ();
514     return;
515   }
516   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id);
517   opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE;
518   GNUNET_CRYPTO_hash (target_port, strlen(target_port), &porthash);
519   ch = GNUNET_CADET_channel_create (mh, NULL, &pid, &porthash, opt);
520   if (GNUNET_NO == echo)
521     listen_stdio ();
522   else
523     echo_task = GNUNET_SCHEDULER_add_now (&send_echo, NULL);
524 }
525
526
527 /**
528  * Function called whenever a message is received.
529  *
530  * Each time the function must call #GNUNET_CADET_receive_done on the channel
531  * in order to receive the next message. This doesn't need to be immediate:
532  * can be delayed if some processing is done on the message.
533  *
534  * @param cls Closure (set from #GNUNET_CADET_connect).
535  * @param channel Connection to the other end.
536  * @param channel_ctx Place to store local state associated with the channel.
537  * @param message The actual message.
538  * @return #GNUNET_OK to keep the channel open,
539  *         #GNUNET_SYSERR to close it (signal serious error).
540  */
541 static int
542 data_callback (void *cls,
543        struct GNUNET_CADET_Channel *channel,
544        void **channel_ctx,
545        const struct GNUNET_MessageHeader *message)
546 {
547   uint16_t len;
548   ssize_t done;
549   uint16_t off;
550   const char *buf;
551   GNUNET_break (ch == channel);
552   GNUNET_CADET_receive_done (channel);
553
554   if (GNUNET_YES == echo)
555   {
556     if (NULL != listen_port)
557     {
558       /* Just listening to echo incoming messages*/
559       if (NULL != th)
560       {
561         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
562                     "Last echo reply not yet sent, dropping current reply.\n");
563         return GNUNET_OK;
564       }
565       th = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
566                                                GNUNET_TIME_UNIT_FOREVER_REL,
567                                                sizeof (struct GNUNET_MessageHeader),
568                                                &data_ready, NULL);
569       return GNUNET_OK;
570     }
571     else
572     {
573       struct GNUNET_TIME_Relative latency;
574
575       latency = GNUNET_TIME_absolute_get_duration (echo_time);
576       echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
577       FPRINTF (stdout, "time: %s\n",
578                GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
579       echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
580                                                 &send_echo, NULL);
581     }
582   }
583
584   len = ntohs (message->size) - sizeof (*message);
585   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len);
586   buf = (const char *) &message[1];
587   off = 0;
588   while (off < len)
589   {
590     done = write (1, &buf[off], len - off);
591     if (done <= 0)
592     {
593       if (-1 == done)
594         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
595                              "write");
596       return GNUNET_SYSERR;
597     }
598     off += done;
599   }
600   return GNUNET_OK;
601 }
602
603
604 /**
605  * Method called to retrieve information about all peers in CADET, called
606  * once per peer.
607  *
608  * After last peer has been reported, an additional call with NULL is done.
609  *
610  * @param cls Closure.
611  * @param peer Peer, or NULL on "EOF".
612  * @param tunnel Do we have a tunnel towards this peer?
613  * @param n_paths Number of known paths towards this peer.
614  * @param best_path How long is the best path?
615  *                  (0 = unknown, 1 = ourselves, 2 = neighbor)
616  */
617 static void
618 peers_callback (void *cls,
619                 const struct GNUNET_PeerIdentity *peer,
620                 int tunnel,
621                 unsigned int n_paths,
622                 unsigned int best_path)
623 {
624   if (NULL == peer)
625   {
626     if (GNUNET_YES != monitor_mode)
627     {
628       GNUNET_SCHEDULER_shutdown();
629     }
630     return;
631   }
632   FPRINTF (stdout, "%s tunnel: %c, paths: %u\n",
633            GNUNET_i2s_full (peer), tunnel ? 'Y' : 'N', n_paths);
634 }
635
636 /**
637  * Method called to retrieve information about a specific peer
638  * known to the service.
639  *
640  * @param cls Closure.
641  * @param peer Peer ID.
642  * @param tunnel Do we have a tunnel towards this peer? #GNUNET_YES/#GNUNET_NO
643  * @param neighbor Is this a direct neighbor? #GNUNET_YES/#GNUNET_NO
644  * @param n_paths Number of paths known towards peer.
645  * @param paths Array of PEER_IDs representing all paths to reach the peer.
646  *              Each path starts with the local peer.
647  *              Each path ends with the destination peer (given in @c peer).
648  */
649 static void
650 peer_callback (void *cls,
651                const struct GNUNET_PeerIdentity *peer,
652                int tunnel,
653                int neighbor,
654                unsigned int n_paths,
655                struct GNUNET_PeerIdentity *paths)
656 {
657   unsigned int i;
658   struct GNUNET_PeerIdentity *p;
659
660   FPRINTF (stdout, "%s [TUNNEL: %s, NEIGHBOR: %s, PATHS: %u]\n",
661            GNUNET_i2s_full (peer),
662            tunnel ? "Y" : "N", neighbor ? "Y" : "N", n_paths);
663   p = paths;
664   for (i = 0; i < n_paths && NULL != p;)
665   {
666     FPRINTF (stdout, "%s ", GNUNET_i2s (p));
667     if (0 == memcmp (p, peer, sizeof (*p)))
668     {
669       FPRINTF (stdout, "\n");
670       i++;
671     }
672     p++;
673   }
674
675   GNUNET_SCHEDULER_shutdown();
676 }
677
678
679 /**
680  * Method called to retrieve information about all tunnels in CADET.
681  *
682  * @param cls Closure.
683  * @param peer Destination peer.
684  * @param channels Number of channels.
685  * @param connections Number of connections.
686  * @param estate Encryption state.
687  * @param cstate Connectivity state.
688  */
689 static void
690 tunnels_callback (void *cls,
691                   const struct GNUNET_PeerIdentity *peer,
692                   unsigned int channels,
693                   unsigned int connections,
694                   uint16_t estate,
695                   uint16_t cstate)
696 {
697   if (NULL == peer)
698   {
699     if (GNUNET_YES != monitor_mode)
700     {
701       GNUNET_SCHEDULER_shutdown();
702     }
703     return;
704   }
705   FPRINTF (stdout, "%s [ENC: %s, CON: %s] CHs: %u, CONNs: %u\n",
706            GNUNET_i2s_full (peer),
707            enc_2s (estate), conn_2s (cstate),
708            channels, connections);
709 }
710
711
712 /**
713  * Method called to retrieve information about a specific tunnel the cadet peer
714  * has established, o`r is trying to establish.
715  *
716  * @param cls Closure.
717  * @param peer Peer towards whom the tunnel is directed.
718  * @param n_channels Number of channels.
719  * @param n_connections Number of connections.
720  * @param channels Channels.
721  * @param connections Connections.
722  * @param estate Encryption status.
723  * @param cstate Connectivity status.
724  */
725 static void
726 tunnel_callback (void *cls,
727                  const struct GNUNET_PeerIdentity *peer,
728                  unsigned int n_channels,
729                  unsigned int n_connections,
730                  uint32_t *channels,
731                  struct GNUNET_CADET_Hash *connections,
732                  unsigned int estate,
733                  unsigned int cstate)
734 {
735   unsigned int i;
736
737   if (NULL != peer)
738   {
739     FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer));
740     FPRINTF (stdout, "\t%u channels\n", n_channels);
741     for (i = 0; i < n_channels; i++)
742       FPRINTF (stdout, "\t\t%X\n", ntohl (channels[i]));
743     FPRINTF (stdout, "\t%u connections\n", n_connections);
744     for (i = 0; i < n_connections; i++)
745       FPRINTF (stdout, "\t\t%s\n", GC_h2s (&connections[i]));
746     FPRINTF (stdout, "\tencryption state: %s\n", enc_2s (estate));
747     FPRINTF (stdout, "\tconnection state: %s\n", conn_2s (cstate));
748   }
749   if (GNUNET_YES != monitor_mode)
750   {
751     GNUNET_SCHEDULER_shutdown ();
752   }
753   return;
754 }
755
756
757 /**
758  * Call CADET's meta API, get all peers known to a peer.
759  *
760  * @param cls Closure (unused).
761  */
762 static void
763 get_peers (void *cls)
764 {
765   job = NULL;
766   GNUNET_CADET_get_peers (mh, &peers_callback, NULL);
767 }
768
769
770 /**
771  * Call CADET's monitor API, get info of one peer.
772  *
773  * @param cls Closure (unused).
774  */
775 static void
776 show_peer (void *cls)
777 {
778   struct GNUNET_PeerIdentity pid;
779
780   job = NULL;
781   if (GNUNET_OK !=
782       GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
783                                                   strlen (peer_id),
784                                                   &pid.public_key))
785     {
786     fprintf (stderr,
787              _("Invalid peer ID `%s'\n"),
788              peer_id);
789     GNUNET_SCHEDULER_shutdown();
790     return;
791   }
792   GNUNET_CADET_get_peer (mh, &pid, peer_callback, NULL);
793 }
794
795
796 /**
797  * Call CADET's meta API, get all tunnels known to a peer.
798  *
799  * @param cls Closure (unused).
800  */
801 static void
802 get_tunnels (void *cls)
803 {
804   job = NULL;
805   GNUNET_CADET_get_tunnels (mh, &tunnels_callback, NULL);
806 }
807
808
809 /**
810  * Call CADET's monitor API, get info of one tunnel.
811  *
812  * @param cls Closure (unused).
813  */
814 static void
815 show_tunnel (void *cls)
816 {
817   struct GNUNET_PeerIdentity pid;
818
819   if (GNUNET_OK !=
820       GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
821                                                   strlen (tunnel_id),
822                                                   &pid.public_key))
823   {
824     fprintf (stderr,
825              _("Invalid tunnel owner `%s'\n"),
826              tunnel_id);
827     GNUNET_SCHEDULER_shutdown ();
828     return;
829   }
830   GNUNET_CADET_get_tunnel (mh, &pid, tunnel_callback, NULL);
831 }
832
833
834 /**
835  * Call CADET's monitor API, get info of one channel.
836  *
837  * @param cls Closure (unused).
838  */
839 static void
840 show_channel (void *cls)
841 {
842   job = NULL;
843   GNUNET_break (0);
844 }
845
846
847 /**
848  * Call CADET's monitor API, get info of one connection.
849  *
850  * @param cls Closure (unused).
851  */
852 static void
853 show_connection (void *cls)
854 {
855   job = NULL;
856   GNUNET_break (0);
857 }
858
859
860 /**
861  * Main function that will be run by the scheduler.
862  *
863  * @param cls closure
864  * @param args remaining command-line arguments
865  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
866  * @param cfg configuration
867  */
868 static void
869 run (void *cls,
870      char *const *args,
871      const char *cfgfile,
872      const struct GNUNET_CONFIGURATION_Handle *cfg)
873 {
874   static const struct GNUNET_CADET_MessageHandler handlers[] = {
875     {&data_callback, GNUNET_MESSAGE_TYPE_CADET_CLI, 0},
876     {NULL, 0, 0} /* FIXME add option to monitor msg types */
877   };
878
879   /* FIXME add option to monitor apps */
880
881   target_id = args[0];
882   if (target_id && args[1]) target_port = args[1];
883
884   if ( (0 != (request_peers | request_tunnels)
885         || 0 != monitor_mode
886         || NULL != tunnel_id
887         || NULL != conn_id
888         || NULL != channel_id)
889        && target_id != NULL)
890   {
891     FPRINTF (stderr,
892              _("You must NOT give a TARGET "
893                "when using 'request all' options\n"));
894     return;
895   }
896
897   if (GNUNET_YES == dump)
898   {
899     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
900                 "requesting debug dump\n");
901     GNUNET_SCHEDULER_add_now (&request_dump, NULL);
902   }
903   else if (NULL != target_id)
904   {
905     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
906                 "Creating channel to %s\n",
907                 target_id);
908     GNUNET_SCHEDULER_add_now (&create_channel, NULL);
909   }
910   else if (NULL != peer_id)
911   {
912     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show peer\n");
913     job = GNUNET_SCHEDULER_add_now (&show_peer, NULL);
914   }
915   else if (NULL != tunnel_id)
916   {
917     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n");
918     job = GNUNET_SCHEDULER_add_now (&show_tunnel, NULL);
919   }
920   else if (NULL != channel_id)
921   {
922     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n");
923     job = GNUNET_SCHEDULER_add_now (&show_channel, NULL);
924   }
925   else if (NULL != conn_id)
926   {
927     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
928     job = GNUNET_SCHEDULER_add_now (&show_connection, NULL);
929   }
930   else if (GNUNET_YES == request_peers)
931   {
932     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n");
933     job = GNUNET_SCHEDULER_add_now (&get_peers, NULL);
934   }
935   else if (GNUNET_YES == request_tunnels)
936   {
937     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
938     job = GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
939   }
940   else if (NULL == listen_port)
941   {
942     FPRINTF (stderr, "No action requested\n");
943     return;
944   }
945
946   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CADET service\n");
947   mh = GNUNET_CADET_connect (cfg,
948                             NULL, /* cls */
949                             &channel_ended, /* cleaner */
950                             handlers);
951   if (NULL == mh)
952     GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
953   else
954     sd = GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
955
956   if (NULL != listen_port)
957   {
958     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Opening CADET listen port\n");
959     GNUNET_CRYPTO_hash (listen_port, strlen(listen_port), &porthash);
960     lp = GNUNET_CADET_open_port (mh, &porthash, &channel_incoming, NULL);
961   }
962 }
963
964
965 /**
966  * The main function to obtain peer information.
967  *
968  * @param argc number of arguments from the command line
969  * @param argv command line arguments
970  * @return 0 ok, 1 on error
971  */
972 int
973 main (int argc, char *const *argv)
974 {
975   int res;
976   const char helpstr[] = "Create channels and retreive info about cadets status.";
977   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
978 //     {'a', "channel", "TUNNEL_ID:CHANNEL_ID",
979 //      gettext_noop ("provide information about a particular channel"),
980 //      GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id},
981     {'C', "connection", "CONNECTION_ID",
982      gettext_noop ("provide information about a particular connection"),
983      GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id},
984     {'e', "echo", NULL,
985      gettext_noop ("activate echo mode"),
986      GNUNET_NO, &GNUNET_GETOPT_set_one, &echo},
987     {'d', "dump", NULL,
988      gettext_noop ("dump debug information to STDERR"),
989      GNUNET_NO, &GNUNET_GETOPT_set_one, &dump},
990 //     {'m', "monitor", NULL,
991 //      gettext_noop ("provide information about all events (continuously)"),
992 //      GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_mode},
993     {'o', "open-port", NULL,
994      gettext_noop ("port to listen to"),
995      GNUNET_YES, &GNUNET_GETOPT_set_string, &listen_port},
996     {'p', "peer", "PEER_ID",
997      gettext_noop ("provide information about a patricular peer"),
998      GNUNET_YES, &GNUNET_GETOPT_set_string, &peer_id},
999     {'P', "peers", NULL,
1000       gettext_noop ("provide information about all peers"),
1001       GNUNET_NO, &GNUNET_GETOPT_set_one, &request_peers},
1002     {'t', "tunnel", "TUNNEL_ID",
1003      gettext_noop ("provide information about a particular tunnel"),
1004      GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id},
1005     {'T', "tunnels", NULL,
1006      gettext_noop ("provide information about all tunnels"),
1007      GNUNET_NO, &GNUNET_GETOPT_set_one, &request_tunnels},
1008
1009     GNUNET_GETOPT_OPTION_END
1010   };
1011
1012   monitor_mode = GNUNET_NO;
1013
1014   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1015     return 2;
1016
1017   res = GNUNET_PROGRAM_run (argc, argv, "gnunet-cadet (OPTIONS | TARGET PORT)",
1018                             gettext_noop (helpstr),
1019                             options, &run, NULL);
1020
1021   GNUNET_free ((void *) argv);
1022
1023   if (GNUNET_OK == res)
1024     return 0;
1025   else
1026     return 1;
1027 }
1028
1029 /* end of gnunet-cadet.c */