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