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