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