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