glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / cadet / gnunet-cadet.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2017 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14 */
15
16 /**
17  * @file cadet/gnunet-cadet.c
18  * @brief Print information about cadet tunnels and peers.
19  * @author Bartlomiej Polot
20  * @author Christian Grothoff
21  */
22 #include "platform.h"
23 #include "gnunet_util_lib.h"
24 #include "gnunet_cadet_service.h"
25 #include "cadet.h"
26
27
28 /**
29  * Option -P.
30  */
31 static int request_peers;
32
33 /**
34  * Option --peer
35  */
36 static char *peer_id;
37
38 /**
39  * Option -T.
40  */
41 static int request_tunnels;
42
43 /**
44  * Option --tunnel
45  */
46 static char *tunnel_id;
47
48 /**
49  * Option --connection
50  */
51 static char *conn_id;
52
53 /**
54  * Option --channel
55  */
56 static char *channel_id;
57
58 /**
59  * Port to listen on (-o).
60  */
61 static char *listen_port;
62
63 /**
64  * Request echo service
65  */
66 static int echo;
67
68 /**
69  * Request a debug dump
70  */
71 static int dump;
72
73 /**
74  * Time of last echo request.
75  */
76 static struct GNUNET_TIME_Absolute echo_time;
77
78 /**
79  * Task for next echo request.
80  */
81 static struct GNUNET_SCHEDULER_Task *echo_task;
82
83 /**
84  * Peer to connect to.
85  */
86 static char *target_id;
87
88 /**
89  * Port to connect to
90  */
91 static char *target_port = "default";
92
93 /**
94  * Cadet handle.
95  */
96 static struct GNUNET_CADET_Handle *mh;
97
98 /**
99  * Channel handle.
100  */
101 static struct GNUNET_CADET_Channel *ch;
102
103 /**
104  * HashCode of the given port string
105  */
106 static struct GNUNET_HashCode porthash;
107
108 /**
109  * Data structure for ongoing reception of incoming virtual circuits.
110  */
111 struct GNUNET_CADET_Port *lp;
112
113 /**
114  * Task for reading from stdin.
115  */
116 static struct GNUNET_SCHEDULER_Task *rd_task;
117
118 /**
119  * Task for main job.
120  */
121 static struct GNUNET_SCHEDULER_Task *job;
122
123
124 /**
125  * Wait for input on STDIO and send it out over the #ch.
126  */
127 static void
128 listen_stdio (void);
129
130
131 /**
132  * Convert encryption status to human readable string.
133  *
134  * @param status Encryption status.
135  *
136  * @return Human readable string.
137  */
138 static const char *
139 enc_2s (uint16_t status)
140 {
141   switch (status)
142   {
143     case 0:
144       return "NULL ";
145     case 1:
146       return "KSENT";
147     case 2:
148       return "KRECV";
149     case 3:
150       return "READY";
151     default:
152       return "";
153   }
154 }
155
156
157 /**
158  * Convert connection status to human readable string.
159  *
160  * @param status Connection status.
161  *
162  * @return Human readable string.
163  */
164 static const char *
165 conn_2s (uint16_t status)
166 {
167   switch (status)
168   {
169     case 0:
170       return "NEW  ";
171     case 1:
172       return "SRCH ";
173     case 2:
174       return "WAIT ";
175     case 3:
176       return "READY";
177     case 4:
178       return "SHUTD";
179     default:
180       return "";
181   }
182 }
183
184
185
186 /**
187  * Task to shut down this application.
188  *
189  * @param cls Closure (unused).
190  */
191 static void
192 shutdown_task (void *cls)
193 {
194   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
195               "Shutdown\n");
196   if (NULL != ch)
197   {
198     GNUNET_CADET_channel_destroy (ch);
199     ch = NULL;
200   }
201   if (NULL != mh)
202   {
203     GNUNET_CADET_disconnect (mh);
204     mh = NULL;
205   }
206   if (NULL != rd_task)
207   {
208     GNUNET_SCHEDULER_cancel (rd_task);
209     rd_task = NULL;
210   }
211   if (NULL != echo_task)
212   {
213     GNUNET_SCHEDULER_cancel (echo_task);
214     echo_task = NULL;
215   }
216   if (NULL != job)
217   {
218     GNUNET_SCHEDULER_cancel (job);
219     job = NULL;
220   }
221 }
222
223
224 /**
225  * Task run in stdio mode, after some data is available at stdin.
226  *
227  * @param cls Closure (unused).
228  */
229 static void
230 read_stdio (void *cls)
231 {
232   struct GNUNET_MQ_Envelope *env;
233   struct GNUNET_MessageHeader *msg;
234   char buf[60000];
235   ssize_t data_size;
236
237   rd_task = NULL;
238   data_size = read (0,
239                     buf,
240                     60000);
241   if (data_size < 1)
242   {
243     GNUNET_SCHEDULER_shutdown();
244     return;
245   }
246   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
247               "Read %u bytes from stdio\n",
248               (unsigned int) data_size);
249   env = GNUNET_MQ_msg_extra (msg,
250                              data_size,
251                              GNUNET_MESSAGE_TYPE_CADET_CLI);
252   GNUNET_memcpy (&msg[1],
253                  buf,
254                  data_size);
255   GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
256                   env);
257   if (GNUNET_NO == echo)
258   {
259     listen_stdio ();
260   }
261   else
262   {
263     echo_time = GNUNET_TIME_absolute_get ();
264   }
265 }
266
267
268 /**
269  * Wait for input on STDIO and send it out over the #ch.
270  */
271 static void
272 listen_stdio ()
273 {
274   struct GNUNET_NETWORK_FDSet *rs;
275
276   /* FIXME: why use 'rs' here, seems overly complicated... */
277   rs = GNUNET_NETWORK_fdset_create ();
278   GNUNET_NETWORK_fdset_set_native (rs,
279                                    0); /* STDIN */
280   rd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
281                                          GNUNET_TIME_UNIT_FOREVER_REL,
282                                          rs,
283                                          NULL,
284                                          &read_stdio,
285                                          NULL);
286   GNUNET_NETWORK_fdset_destroy (rs);
287 }
288
289
290 /**
291  * Function called whenever a channel is destroyed.  Should clean up
292  * any associated state.
293  *
294  * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
295  *
296  * @param cls closure
297  * @param channel connection to the other end (henceforth invalid)
298  */
299 static void
300 channel_ended (void *cls,
301                const struct GNUNET_CADET_Channel *channel)
302 {
303   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
304               "Channel ended!\n");
305   GNUNET_assert (channel == ch);
306   ch = NULL;
307   GNUNET_SCHEDULER_shutdown ();
308 }
309
310
311 /**
312  * Method called whenever another peer has added us to a channel
313  * the other peer initiated.
314  * Only called (once) upon reception of data with a message type which was
315  * subscribed to in #GNUNET_CADET_connect.
316  *
317  * A call to #GNUNET_CADET_channel_destroy causes the channel to be ignored.
318  * In this case the handler MUST return NULL.
319  *
320  * @param cls closure
321  * @param channel new handle to the channel
322  * @param initiator peer that started the channel
323  * @return initial channel context for the channel, we use @a channel
324  */
325 static void *
326 channel_incoming (void *cls,
327                   struct GNUNET_CADET_Channel *channel,
328                   const struct GNUNET_PeerIdentity *initiator)
329 {
330   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
331               "Incoming connection from %s\n",
332               GNUNET_i2s_full (initiator));
333   GNUNET_assert (NULL == ch);
334   GNUNET_assert (NULL != lp);
335   GNUNET_CADET_close_port (lp);
336   lp = NULL;
337   ch = channel;
338   if (GNUNET_NO == echo)
339     listen_stdio ();
340   return channel;
341 }
342
343
344 /**
345  * @brief Send an echo request to the remote peer.
346  *
347  * @param cls Closure (NULL).
348  */
349 static void
350 send_echo (void *cls)
351 {
352   struct GNUNET_MQ_Envelope *env;
353   struct GNUNET_MessageHeader *msg;
354
355   echo_task = NULL;
356   if (NULL == ch)
357     return;
358   env = GNUNET_MQ_msg (msg,
359                        GNUNET_MESSAGE_TYPE_CADET_CLI);
360   GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
361                   env);
362 }
363
364
365 /**
366  * Call CADET's monitor API, request debug dump on the service.
367  *
368  * @param cls Closure (unused).
369  */
370 static void
371 request_dump (void *cls)
372 {
373   GNUNET_CADET_request_dump (mh);
374   GNUNET_SCHEDULER_shutdown ();
375 }
376
377
378 /**
379  * Check data message sanity. Does nothing so far (all messages are OK).
380  *
381  * @param cls Closure (unused).
382  * @param message The message to check.
383  * @return #GNUNET_OK to keep the channel open,
384  *         #GNUNET_SYSERR to close it (signal serious error).
385  */
386 static int
387 check_data (void *cls,
388             const struct GNUNET_MessageHeader *message)
389 {
390   return GNUNET_OK; /* all is well-formed */
391 }
392
393
394 /**
395  * Function called whenever a message is received.
396  *
397  * Each time the function must call #GNUNET_CADET_receive_done on the channel
398  * in order to receive the next message. This doesn't need to be immediate:
399  * can be delayed if some processing is done on the message.
400  *
401  * @param cls NULL
402  * @param message The actual message.
403  */
404 static void
405 handle_data (void *cls,
406              const struct GNUNET_MessageHeader *message)
407 {
408   size_t payload_size = ntohs (message->size) - sizeof (*message);
409   uint16_t len;
410   ssize_t done;
411   uint16_t off;
412   const char *buf;
413
414   GNUNET_CADET_receive_done (ch);
415   if (GNUNET_YES == echo)
416   {
417     if (NULL != listen_port)
418     {
419       struct GNUNET_MQ_Envelope *env;
420       struct GNUNET_MessageHeader *msg;
421
422       env = GNUNET_MQ_msg_extra (msg,
423                                  payload_size,
424                                  GNUNET_MESSAGE_TYPE_CADET_CLI);
425       GNUNET_memcpy (&msg[1],
426                      &message[1],
427                      payload_size);
428       GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
429                       env);
430       return;
431     }
432     else
433     {
434       struct GNUNET_TIME_Relative latency;
435
436       latency = GNUNET_TIME_absolute_get_duration (echo_time);
437       echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
438       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
439                   "time: %s\n",
440                   GNUNET_STRINGS_relative_time_to_string (latency,
441                                                           GNUNET_NO));
442       echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
443                                                 &send_echo,
444                                                 NULL);
445     }
446   }
447
448   len = ntohs (message->size) - sizeof (*message);
449   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
450               "Got %u bytes\n",
451               len);
452   buf = (const char *) &message[1];
453   off = 0;
454   while (off < len)
455   {
456     done = write (1,
457                   &buf[off],
458                   len - off);
459     if (done <= 0)
460     {
461       if (-1 == done)
462         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
463                              "write");
464       GNUNET_SCHEDULER_shutdown ();
465       return;
466     }
467     off += done;
468   }
469 }
470
471
472 /**
473  * Method called to retrieve information about all peers in CADET, called
474  * once per peer.
475  *
476  * After last peer has been reported, an additional call with NULL is done.
477  *
478  * @param cls Closure.
479  * @param peer Peer, or NULL on "EOF".
480  * @param tunnel Do we have a tunnel towards this peer?
481  * @param n_paths Number of known paths towards this peer.
482  * @param best_path How long is the best path?
483  *                  (0 = unknown, 1 = ourselves, 2 = neighbor)
484  */
485 static void
486 peers_callback (void *cls,
487                 const struct GNUNET_PeerIdentity *peer,
488                 int tunnel,
489                 unsigned int n_paths,
490                 unsigned int best_path)
491 {
492   if (NULL == peer)
493   {
494     GNUNET_SCHEDULER_shutdown();
495     return;
496   }
497   FPRINTF (stdout,
498            "%s tunnel: %c, paths: %u\n",
499            GNUNET_i2s_full (peer),
500            tunnel ? 'Y' : 'N',
501            n_paths);
502 }
503
504
505 /**
506  * Method called to retrieve information about a specific peer
507  * known to the service.
508  *
509  * @param cls Closure.
510  * @param peer Peer ID.
511  * @param tunnel Do we have a tunnel towards this peer? #GNUNET_YES/#GNUNET_NO
512  * @param neighbor Is this a direct neighbor? #GNUNET_YES/#GNUNET_NO
513  * @param n_paths Number of paths known towards peer.
514  * @param paths Array of PEER_IDs representing all paths to reach the peer.
515  *              Each path starts with the local peer.
516  *              Each path ends with the destination peer (given in @c peer).
517  */
518 static void
519 peer_callback (void *cls,
520                const struct GNUNET_PeerIdentity *peer,
521                int tunnel,
522                int neighbor,
523                unsigned int n_paths,
524                const struct GNUNET_PeerIdentity *paths)
525 {
526   unsigned int i;
527   const struct GNUNET_PeerIdentity *p;
528
529   FPRINTF (stdout,
530            "%s [TUNNEL: %s, NEIGHBOR: %s, PATHS: %u]\n",
531            GNUNET_i2s_full (peer),
532            tunnel ? "Y" : "N",
533            neighbor ? "Y" : "N",
534            n_paths);
535   p = paths;
536   for (i = 0; i < n_paths && NULL != p;)
537   {
538     FPRINTF (stdout,
539              "%s ",
540              GNUNET_i2s (p));
541     if (0 == memcmp (p,
542                      peer,
543                      sizeof (*p)))
544     {
545       FPRINTF (stdout, "\n");
546       i++;
547     }
548     p++;
549   }
550
551   GNUNET_SCHEDULER_shutdown();
552 }
553
554
555 /**
556  * Method called to retrieve information about all tunnels in CADET.
557  *
558  * @param cls Closure.
559  * @param peer Destination peer.
560  * @param channels Number of channels.
561  * @param connections Number of connections.
562  * @param estate Encryption state.
563  * @param cstate Connectivity state.
564  */
565 static void
566 tunnels_callback (void *cls,
567                   const struct GNUNET_PeerIdentity *peer,
568                   unsigned int channels,
569                   unsigned int connections,
570                   uint16_t estate,
571                   uint16_t cstate)
572 {
573   if (NULL == peer)
574   {
575     GNUNET_SCHEDULER_shutdown();
576     return;
577   }
578   FPRINTF (stdout,
579            "%s [ENC: %s, CON: %s] CHs: %u, CONNs: %u\n",
580            GNUNET_i2s_full (peer),
581            enc_2s (estate),
582            conn_2s (cstate),
583            channels,
584            connections);
585 }
586
587
588 /**
589  * Method called to retrieve information about a specific tunnel the cadet peer
590  * has established, o`r is trying to establish.
591  *
592  * @param cls Closure.
593  * @param peer Peer towards whom the tunnel is directed.
594  * @param n_channels Number of channels.
595  * @param n_connections Number of connections.
596  * @param channels Channels.
597  * @param connections Connections.
598  * @param estate Encryption status.
599  * @param cstate Connectivity status.
600  */
601 static void
602 tunnel_callback (void *cls,
603                  const struct GNUNET_PeerIdentity *peer,
604                  unsigned int n_channels,
605                  unsigned int n_connections,
606                  const struct GNUNET_CADET_ChannelTunnelNumber *channels,
607                  const struct GNUNET_CADET_ConnectionTunnelIdentifier *connections,
608                  unsigned int estate,
609                  unsigned int cstate)
610 {
611   unsigned int i;
612
613   if (NULL != peer)
614   {
615     FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer));
616     FPRINTF (stdout, "\t%u channels\n", n_channels);
617     for (i = 0; i < n_channels; i++)
618       FPRINTF (stdout, "\t\t%X\n", ntohl (channels[i].cn));
619     FPRINTF (stdout, "\t%u connections\n", n_connections);
620     for (i = 0; i < n_connections; i++)
621       FPRINTF (stdout, "\t\t%s\n", GNUNET_sh2s (&connections[i].connection_of_tunnel));
622     FPRINTF (stdout, "\tencryption state: %s\n", enc_2s (estate));
623     FPRINTF (stdout, "\tconnection state: %s\n", conn_2s (cstate));
624   }
625   GNUNET_SCHEDULER_shutdown ();
626 }
627
628
629 /**
630  * Call CADET's meta API, get all peers known to a peer.
631  *
632  * @param cls Closure (unused).
633  */
634 static void
635 get_peers (void *cls)
636 {
637   job = NULL;
638   GNUNET_CADET_get_peers (mh, &peers_callback, NULL);
639 }
640
641
642 /**
643  * Call CADET's monitor API, get info of one peer.
644  *
645  * @param cls Closure (unused).
646  */
647 static void
648 show_peer (void *cls)
649 {
650   struct GNUNET_PeerIdentity pid;
651
652   job = NULL;
653   if (GNUNET_OK !=
654       GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
655                                                   strlen (peer_id),
656                                                   &pid.public_key))
657     {
658     fprintf (stderr,
659              _("Invalid peer ID `%s'\n"),
660              peer_id);
661     GNUNET_SCHEDULER_shutdown();
662     return;
663   }
664   GNUNET_CADET_get_peer (mh, &pid, peer_callback, NULL);
665 }
666
667
668 /**
669  * Call CADET's meta API, get all tunnels known to a peer.
670  *
671  * @param cls Closure (unused).
672  */
673 static void
674 get_tunnels (void *cls)
675 {
676   job = NULL;
677   GNUNET_CADET_get_tunnels (mh, &tunnels_callback, NULL);
678 }
679
680
681 /**
682  * Call CADET's monitor API, get info of one tunnel.
683  *
684  * @param cls Closure (unused).
685  */
686 static void
687 show_tunnel (void *cls)
688 {
689   struct GNUNET_PeerIdentity pid;
690
691   job = NULL;
692   if (GNUNET_OK !=
693       GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
694                                                   strlen (tunnel_id),
695                                                   &pid.public_key))
696   {
697     fprintf (stderr,
698              _("Invalid tunnel owner `%s'\n"),
699              tunnel_id);
700     GNUNET_SCHEDULER_shutdown ();
701     return;
702   }
703   GNUNET_CADET_get_tunnel (mh,
704                            &pid,
705                            &tunnel_callback,
706                            NULL);
707 }
708
709
710 /**
711  * Call CADET's monitor API, get info of one channel.
712  *
713  * @param cls Closure (unused).
714  */
715 static void
716 show_channel (void *cls)
717 {
718   job = NULL;
719   GNUNET_break (0);
720 }
721
722
723 /**
724  * Call CADET's monitor API, get info of one connection.
725  *
726  * @param cls Closure (unused).
727  */
728 static void
729 show_connection (void *cls)
730 {
731   job = NULL;
732   GNUNET_break (0);
733 }
734
735
736 /**
737  * Main function that will be run by the scheduler.
738  *
739  * @param cls closure
740  * @param args remaining command-line arguments
741  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
742  * @param cfg configuration
743  */
744 static void
745 run (void *cls,
746      char *const *args,
747      const char *cfgfile,
748      const struct GNUNET_CONFIGURATION_Handle *cfg)
749 {
750   struct GNUNET_MQ_MessageHandler handlers[] = {
751     GNUNET_MQ_hd_var_size (data,
752                            GNUNET_MESSAGE_TYPE_CADET_CLI,
753                            struct GNUNET_MessageHeader,
754                            NULL),
755     GNUNET_MQ_handler_end ()
756   };
757
758   /* FIXME add option to monitor apps */
759
760   target_id = args[0];
761   if (target_id && args[1])
762     target_port = args[1];
763
764   if ( (0 != (request_peers | request_tunnels)
765         || NULL != tunnel_id
766         || NULL != conn_id
767         || NULL != channel_id)
768        && target_id != NULL)
769   {
770     FPRINTF (stderr,
771              _("Extra arguments are not applicable "
772                "in combination with this option.\n"));
773     return;
774   }
775
776   if (GNUNET_YES == dump)
777   {
778     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
779                 "Requesting debug dump\n");
780     job = GNUNET_SCHEDULER_add_now (&request_dump,
781                                     NULL);
782   }
783   else if (NULL != peer_id)
784   {
785     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
786                 "Show peer\n");
787     job = GNUNET_SCHEDULER_add_now (&show_peer,
788                                     NULL);
789   }
790   else if (NULL != tunnel_id)
791   {
792     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
793                 "Show tunnel\n");
794     job = GNUNET_SCHEDULER_add_now (&show_tunnel,
795                                     NULL);
796   }
797   else if (NULL != channel_id)
798   {
799     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
800                 "Show channel\n");
801     job = GNUNET_SCHEDULER_add_now (&show_channel,
802                                     NULL);
803   }
804   else if (NULL != conn_id)
805   {
806     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
807                 "Show connection\n");
808     job = GNUNET_SCHEDULER_add_now (&show_connection,
809                                     NULL);
810   }
811   else if (GNUNET_YES == request_peers)
812   {
813     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
814                 "Show all peers\n");
815     job = GNUNET_SCHEDULER_add_now (&get_peers,
816                                     NULL);
817   }
818   else if (GNUNET_YES == request_tunnels)
819   {
820     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
821                 "Show all tunnels\n");
822     job = GNUNET_SCHEDULER_add_now (&get_tunnels,
823                                     NULL);
824   }
825
826   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
827               "Connecting to CADET service\n");
828   mh = GNUNET_CADET_connect (cfg);
829   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
830                                  NULL);
831   if (NULL == mh)
832   {
833     GNUNET_SCHEDULER_shutdown ();
834     return;
835   }
836   if (NULL != listen_port)
837   {
838     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
839                 "Opening CADET listen port\n");
840     GNUNET_CRYPTO_hash (listen_port,
841                         strlen (listen_port),
842                         &porthash);
843     lp = GNUNET_CADET_open_port (mh,
844                                  &porthash,
845                                  &channel_incoming,
846                                  NULL,
847                                  NULL /* window changes */,
848                                  &channel_ended,
849                                  handlers);
850   }
851   if (NULL != target_id)
852   {
853     struct GNUNET_PeerIdentity pid;
854     enum GNUNET_CADET_ChannelOption opt;
855
856     if (GNUNET_OK !=
857         GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
858                                                     strlen (target_id),
859                                                     &pid.public_key))
860     {
861       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
862                   _("Invalid target `%s'\n"),
863                   target_id);
864       GNUNET_SCHEDULER_shutdown ();
865       return;
866     }
867     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
868                 "Connecting to `%s:%s'\n",
869                 target_id,
870                 target_port);
871     opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE;
872     GNUNET_CRYPTO_hash (target_port,
873                         strlen(target_port),
874                         &porthash);
875     ch = GNUNET_CADET_channel_create (mh,
876                                       NULL,
877                                       &pid,
878                                       &porthash,
879                                       opt,
880                                       NULL /* window changes */,
881                                       &channel_ended,
882                                       handlers);
883     if (GNUNET_YES == echo)
884     {
885       echo_task = GNUNET_SCHEDULER_add_now (&send_echo,
886                                             NULL);
887     }
888     else
889     {
890       listen_stdio ();
891     }
892   }
893
894   if ( (NULL == lp) &&
895        (NULL == job) &&
896        (NULL == ch) )
897   {
898     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
899                 _("No action requested\n"));
900     GNUNET_SCHEDULER_shutdown ();
901     return;
902   }
903 }
904
905
906 /**
907  * The main function to obtain peer information.
908  *
909  * @param argc number of arguments from the command line
910  * @param argv command line arguments
911  * @return 0 ok, 1 on error
912  */
913 int
914 main (int argc,
915       char *const *argv)
916 {
917   int res;
918   const char helpstr[] = "Create tunnels and retrieve info about CADET's status.";
919   struct GNUNET_GETOPT_CommandLineOption options[] = {
920     /* I would use the terminology 'circuit' here...  --lynX */
921     GNUNET_GETOPT_option_string ('C',
922                                  "connection",
923                                  "CONNECTION_ID",
924                                  gettext_noop ("Provide information about a particular connection"),
925                                  &conn_id),
926
927     GNUNET_GETOPT_option_flag ('e',
928                                   "echo",
929                                   gettext_noop ("Activate echo mode"),
930                                   &echo), 
931
932     GNUNET_GETOPT_option_flag ('d',
933                                   "dump",
934                                   gettext_noop ("Dump debug information to STDERR"),
935                                   &dump),
936
937     GNUNET_GETOPT_option_string ('o',
938                                  "open-port",
939                                  "SHARED_SECRET",
940                                  gettext_noop ("Listen for connections using a shared secret among sender and recipient"),
941                                  &listen_port),
942
943
944     GNUNET_GETOPT_option_string ('p',
945                                  "peer",
946                                  "PEER_ID",
947                                  gettext_noop ("Provide information about a patricular peer"),
948                                  &peer_id),
949
950
951     GNUNET_GETOPT_option_flag ('P',
952                                   "peers",
953                                   gettext_noop ("Provide information about all peers"),
954                                   &request_peers),
955
956     GNUNET_GETOPT_option_string ('t',
957                                  "tunnel",
958                                  "TUNNEL_ID",
959                                  gettext_noop ("Provide information about a particular tunnel"),
960                                  &tunnel_id),
961
962
963     GNUNET_GETOPT_option_flag ('T',
964                                   "tunnels",
965                                   gettext_noop ("Provide information about all tunnels"),
966                                   &request_tunnels),
967
968     GNUNET_GETOPT_OPTION_END
969   };
970
971   if (GNUNET_OK !=
972       GNUNET_STRINGS_get_utf8_args (argc, argv,
973                                     &argc, &argv))
974     return 2;
975
976   res = GNUNET_PROGRAM_run (argc, argv,
977                             "gnunet-cadet (OPTIONS | PEER_ID SHARED_SECRET)",
978                             gettext_noop (helpstr),
979                             options, &run, NULL);
980
981   GNUNET_free ((void *) argv);
982
983   if (GNUNET_OK == res)
984     return 0;
985   return 1;
986 }
987
988 /* end of gnunet-cadet.c */