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