2 This file is part of GNUnet.
3 Copyright (C) 2012, 2017, 2019 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file cadet/gnunet-cadet.c
23 * @brief Print information about cadet tunnels and peers.
24 * @author Bartlomiej Polot
25 * @author Christian Grothoff
28 #include "gnunet_util_lib.h"
29 #include "gnunet_cadet_service.h"
32 #define STREAM_BUFFER_SIZE 1024 // Pakets
37 static int request_peers;
47 static int request_tunnels;
57 static char *channel_id;
60 * Port to listen on (-o).
62 static char *listen_port;
65 * Request echo service
70 * Time of last echo request.
72 static struct GNUNET_TIME_Absolute echo_time;
75 * Task for next echo request.
77 static struct GNUNET_SCHEDULER_Task *echo_task;
82 static char *target_id;
87 static char *target_port = "default";
92 static struct GNUNET_CADET_Handle *mh;
97 static const struct GNUNET_CONFIGURATION_Handle *my_cfg;
100 * Active get path operation.
102 static struct GNUNET_CADET_GetPath *gpo;
105 * Active peer listing operation.
107 static struct GNUNET_CADET_PeersLister *plo;
110 * Active tunnel listing operation.
112 static struct GNUNET_CADET_ListTunnels *tio;
117 static struct GNUNET_CADET_Channel *ch;
120 * HashCode of the given port string
122 static struct GNUNET_HashCode porthash;
125 * Data structure for ongoing reception of incoming virtual circuits.
127 struct GNUNET_CADET_Port *lp;
130 * Task for reading from stdin.
132 static struct GNUNET_SCHEDULER_Task *rd_task;
137 static struct GNUNET_SCHEDULER_Task *job;
139 static unsigned int sent_pkt;
143 * Wait for input on STDIO and send it out over the #ch.
150 * Convert encryption status to human readable string.
152 * @param status Encryption status.
154 * @return Human readable string.
157 enc_2s (uint16_t status)
176 * Convert connection status to human readable string.
178 * @param status Connection status.
180 * @return Human readable string.
183 conn_2s (uint16_t status)
205 * Task to shut down this application.
207 * @param cls Closure (unused).
210 shutdown_task (void *cls)
212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
216 GNUNET_CADET_close_port (lp);
221 GNUNET_CADET_channel_destroy (ch);
226 GNUNET_CADET_get_path_cancel (gpo);
231 GNUNET_CADET_list_peers_cancel (plo);
236 GNUNET_CADET_list_tunnels_cancel (tio);
241 GNUNET_CADET_disconnect (mh);
246 GNUNET_SCHEDULER_cancel (rd_task);
249 if (NULL != echo_task)
251 GNUNET_SCHEDULER_cancel (echo_task);
256 GNUNET_SCHEDULER_cancel (job);
269 * Task run in stdio mode, after some data is available at stdin.
271 * @param cls Closure (unused).
274 read_stdio (void *cls)
276 struct GNUNET_MQ_Envelope *env;
277 struct GNUNET_MessageHeader *msg;
287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
288 "read() returned %s\n", strerror(errno));
289 GNUNET_SCHEDULER_shutdown();
292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
293 "Read %u bytes from stdio\n",
294 (unsigned int) data_size);
295 env = GNUNET_MQ_msg_extra (msg,
297 GNUNET_MESSAGE_TYPE_CADET_CLI);
298 GNUNET_memcpy (&msg[1],
301 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
306 if (GNUNET_NO == echo)
308 // Use MQ's notification if too much data of stdin is pooring in too fast.
309 if (STREAM_BUFFER_SIZE < sent_pkt)
311 GNUNET_MQ_notify_sent (env, mq_cb, cls);
321 echo_time = GNUNET_TIME_absolute_get ();
327 * Wait for input on STDIO and send it out over the #ch.
332 struct GNUNET_NETWORK_FDSet *rs;
334 /* FIXME: why use 'rs' here, seems overly complicated... */
335 rs = GNUNET_NETWORK_fdset_create ();
336 GNUNET_NETWORK_fdset_set_native (rs,
338 rd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
339 GNUNET_TIME_UNIT_FOREVER_REL,
344 GNUNET_NETWORK_fdset_destroy (rs);
349 * Function called whenever a channel is destroyed. Should clean up
350 * any associated state.
352 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
355 * @param channel connection to the other end (henceforth invalid)
358 channel_ended (void *cls,
359 const struct GNUNET_CADET_Channel *channel)
361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
363 GNUNET_assert (channel == ch);
365 GNUNET_SCHEDULER_shutdown ();
370 * Method called whenever another peer has added us to a channel
371 * the other peer initiated.
372 * Only called (once) upon reception of data with a message type which was
373 * subscribed to in #GNUNET_CADET_connect.
375 * A call to #GNUNET_CADET_channel_destroy causes the channel to be ignored.
376 * In this case the handler MUST return NULL.
379 * @param channel new handle to the channel
380 * @param initiator peer that started the channel
381 * @return initial channel context for the channel, we use @a channel
384 channel_incoming (void *cls,
385 struct GNUNET_CADET_Channel *channel,
386 const struct GNUNET_PeerIdentity *initiator)
388 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
389 "Incoming connection from %s\n",
390 GNUNET_i2s_full (initiator));
391 GNUNET_assert (NULL == ch);
392 GNUNET_assert (NULL != lp);
393 GNUNET_CADET_close_port (lp);
396 if (GNUNET_NO == echo)
403 * @brief Send an echo request to the remote peer.
405 * @param cls Closure (NULL).
408 send_echo (void *cls)
410 struct GNUNET_MQ_Envelope *env;
411 struct GNUNET_MessageHeader *msg;
416 env = GNUNET_MQ_msg (msg,
417 GNUNET_MESSAGE_TYPE_CADET_CLI);
418 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
424 * Check data message sanity. Does nothing so far (all messages are OK).
426 * @param cls Closure (unused).
427 * @param message The message to check.
428 * @return #GNUNET_OK to keep the channel open,
429 * #GNUNET_SYSERR to close it (signal serious error).
432 check_data (void *cls,
433 const struct GNUNET_MessageHeader *message)
435 return GNUNET_OK; /* all is well-formed */
440 * Function called whenever a message is received.
442 * Each time the function must call #GNUNET_CADET_receive_done on the channel
443 * in order to receive the next message. This doesn't need to be immediate:
444 * can be delayed if some processing is done on the message.
447 * @param message The actual message.
450 handle_data (void *cls,
451 const struct GNUNET_MessageHeader *message)
453 size_t payload_size = ntohs (message->size) - sizeof (*message);
459 GNUNET_CADET_receive_done (ch);
460 if (GNUNET_YES == echo)
462 if (NULL != listen_port)
464 struct GNUNET_MQ_Envelope *env;
465 struct GNUNET_MessageHeader *msg;
467 env = GNUNET_MQ_msg_extra (msg,
469 GNUNET_MESSAGE_TYPE_CADET_CLI);
470 GNUNET_memcpy (&msg[1],
473 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
479 struct GNUNET_TIME_Relative latency;
481 latency = GNUNET_TIME_absolute_get_duration (echo_time);
482 echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
483 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
485 GNUNET_STRINGS_relative_time_to_string (latency,
487 echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
493 len = ntohs (message->size) - sizeof (*message);
494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
497 buf = (const char *) &message[1];
507 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
509 GNUNET_SCHEDULER_shutdown ();
518 * Method called to retrieve information about all peers in CADET, called
521 * After last peer has been reported, an additional call with NULL is done.
523 * @param cls Closure.
524 * @param ple information about peer, or NULL on "EOF".
527 peers_callback (void *cls,
528 const struct GNUNET_CADET_PeerListEntry *ple)
533 GNUNET_SCHEDULER_shutdown();
537 "%s tunnel: %c, paths: %u\n",
538 GNUNET_i2s_full (&ple->peer),
539 ple->have_tunnel ? 'Y' : 'N',
545 * Method called to retrieve information about paths to a specific peer
546 * known to the service.
548 * @param cls Closure.
549 * @param ppd path detail
552 path_callback (void *cls,
553 const struct GNUNET_CADET_PeerPathDetail *ppd)
558 GNUNET_SCHEDULER_shutdown();
562 "Path of length %u: ",
564 for (unsigned int i = 0; i < ppd->path_length; i++)
566 (i == ppd->target_offset) ? "*%s* " : "%s ",
567 GNUNET_i2s (&ppd->path[i]));
574 * Method called to retrieve information about all tunnels in CADET.
576 * @param cls Closure.
577 * @param td tunnel details
580 tunnels_callback (void *cls,
581 const struct GNUNET_CADET_TunnelDetails *td)
586 GNUNET_SCHEDULER_shutdown();
590 "%s [ENC: %s, CON: %s] CHs: %u, CONNs: %u\n",
591 GNUNET_i2s_full (&td->peer),
593 conn_2s (td->cstate),
600 * Call CADET's meta API, get all peers known to a peer.
602 * @param cls Closure (unused).
605 get_peers (void *cls)
608 plo = GNUNET_CADET_list_peers (my_cfg,
615 * Call CADET's monitor API, get info of one peer.
617 * @param cls Closure (unused).
620 show_peer (void *cls)
622 struct GNUNET_PeerIdentity pid;
626 GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
631 _("Invalid peer ID `%s'\n"),
633 GNUNET_SCHEDULER_shutdown();
636 gpo = GNUNET_CADET_get_path (my_cfg,
644 * Call CADET's meta API, get all tunnels known to a peer.
646 * @param cls Closure (unused).
649 get_tunnels (void *cls)
652 tio = GNUNET_CADET_list_tunnels (my_cfg,
659 * Call CADET's monitor API, get info of one channel.
661 * @param cls Closure (unused).
664 show_channel (void *cls)
672 * Call CADET's monitor API, get info of one connection.
674 * @param cls Closure (unused).
677 show_connection (void *cls)
685 * Main function that will be run by the scheduler.
688 * @param args remaining command-line arguments
689 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
690 * @param cfg configuration
696 const struct GNUNET_CONFIGURATION_Handle *cfg)
698 struct GNUNET_MQ_MessageHandler handlers[] = {
699 GNUNET_MQ_hd_var_size (data,
700 GNUNET_MESSAGE_TYPE_CADET_CLI,
701 struct GNUNET_MessageHeader,
703 GNUNET_MQ_handler_end ()
706 /* FIXME add option to monitor apps */
709 if (target_id && args[1])
710 target_port = args[1];
712 if ( (0 != (request_peers | request_tunnels)
714 || NULL != channel_id)
715 && target_id != NULL)
718 _("Extra arguments are not applicable "
719 "in combination with this option.\n"));
725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
727 job = GNUNET_SCHEDULER_add_now (&show_peer,
730 else if (NULL != channel_id)
732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
734 job = GNUNET_SCHEDULER_add_now (&show_channel,
737 else if (NULL != conn_id)
739 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
740 "Show connection\n");
741 job = GNUNET_SCHEDULER_add_now (&show_connection,
744 else if (GNUNET_YES == request_peers)
746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
748 job = GNUNET_SCHEDULER_add_now (&get_peers,
751 else if (GNUNET_YES == request_tunnels)
753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
754 "Show all tunnels\n");
755 job = GNUNET_SCHEDULER_add_now (&get_tunnels,
759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
760 "Connecting to CADET service\n");
761 mh = GNUNET_CADET_connect (cfg);
762 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
766 GNUNET_SCHEDULER_shutdown ();
769 if (NULL != listen_port)
771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
772 "Opening CADET listen port\n");
773 GNUNET_CRYPTO_hash (listen_port,
774 strlen (listen_port),
776 lp = GNUNET_CADET_open_port (mh,
780 NULL /* window changes */,
784 if (NULL != target_id)
786 struct GNUNET_PeerIdentity pid;
787 enum GNUNET_CADET_ChannelOption opt;
790 GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
794 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
795 _("Invalid target `%s'\n"),
797 GNUNET_SCHEDULER_shutdown ();
800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
801 "Connecting to `%s:%s'\n",
804 opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE;
805 GNUNET_CRYPTO_hash (target_port,
808 ch = GNUNET_CADET_channel_create (mh,
813 NULL /* window changes */,
816 if (GNUNET_YES == echo)
818 echo_task = GNUNET_SCHEDULER_add_now (&send_echo,
831 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
832 _("No action requested\n"));
833 GNUNET_SCHEDULER_shutdown ();
840 * The main function to obtain peer information.
842 * @param argc number of arguments from the command line
843 * @param argv command line arguments
844 * @return 0 ok, 1 on error
851 const char helpstr[] = "Create tunnels and retrieve info about CADET's status.";
852 struct GNUNET_GETOPT_CommandLineOption options[] = {
853 /* I would use the terminology 'circuit' here... --lynX */
854 GNUNET_GETOPT_option_string ('C',
857 gettext_noop ("Provide information about a particular connection"),
859 GNUNET_GETOPT_option_flag ('e',
861 gettext_noop ("Activate echo mode"),
863 GNUNET_GETOPT_option_string ('o',
866 gettext_noop ("Listen for connections using a shared secret among sender and recipient"),
868 GNUNET_GETOPT_option_string ('p',
871 gettext_noop ("Provide information about a patricular peer"),
873 GNUNET_GETOPT_option_flag ('P',
875 gettext_noop ("Provide information about all peers"),
877 GNUNET_GETOPT_option_flag ('T',
879 gettext_noop ("Provide information about all tunnels"),
881 GNUNET_GETOPT_OPTION_END
885 GNUNET_STRINGS_get_utf8_args (argc, argv,
889 res = GNUNET_PROGRAM_run (argc, argv,
890 "gnunet-cadet (OPTIONS | PEER_ID SHARED_SECRET)",
891 gettext_noop (helpstr),
892 options, &run, NULL);
894 GNUNET_free ((void *) argv);
896 if (GNUNET_OK == res)
901 /* end of gnunet-cadet.c */