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