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