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