2 This file is part of GNUnet.
3 Copyright (C) 2012, 2017 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;
52 static char *tunnel_id;
62 static char *channel_id;
65 * Port to listen on (-o).
67 static char *listen_port;
70 * Request echo service
75 * Request a debug dump
80 * Time of last echo request.
82 static struct GNUNET_TIME_Absolute echo_time;
85 * Task for next echo request.
87 static struct GNUNET_SCHEDULER_Task *echo_task;
92 static char *target_id;
97 static char *target_port = "default";
102 static struct GNUNET_CADET_Handle *mh;
107 static struct GNUNET_CADET_Channel *ch;
110 * HashCode of the given port string
112 static struct GNUNET_HashCode porthash;
115 * Data structure for ongoing reception of incoming virtual circuits.
117 struct GNUNET_CADET_Port *lp;
120 * Task for reading from stdin.
122 static struct GNUNET_SCHEDULER_Task *rd_task;
127 static struct GNUNET_SCHEDULER_Task *job;
129 static unsigned int sent_pkt;
133 * Wait for input on STDIO and send it out over the #ch.
140 * Convert encryption status to human readable string.
142 * @param status Encryption status.
144 * @return Human readable string.
147 enc_2s (uint16_t status)
166 * Convert connection status to human readable string.
168 * @param status Connection status.
170 * @return Human readable string.
173 conn_2s (uint16_t status)
195 * Task to shut down this application.
197 * @param cls Closure (unused).
200 shutdown_task (void *cls)
202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
206 GNUNET_CADET_close_port (lp);
211 GNUNET_CADET_channel_destroy (ch);
216 GNUNET_CADET_disconnect (mh);
221 GNUNET_SCHEDULER_cancel (rd_task);
224 if (NULL != echo_task)
226 GNUNET_SCHEDULER_cancel (echo_task);
231 GNUNET_SCHEDULER_cancel (job);
244 * Task run in stdio mode, after some data is available at stdin.
246 * @param cls Closure (unused).
249 read_stdio (void *cls)
251 struct GNUNET_MQ_Envelope *env;
252 struct GNUNET_MessageHeader *msg;
262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
263 "read() returned %s\n", strerror(errno));
264 GNUNET_SCHEDULER_shutdown();
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,
272 GNUNET_MESSAGE_TYPE_CADET_CLI);
273 GNUNET_memcpy (&msg[1],
276 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
281 if (GNUNET_NO == echo)
283 // Use MQ's notification if too much data of stdin is pooring in too fast.
284 if (STREAM_BUFFER_SIZE < sent_pkt)
286 GNUNET_MQ_notify_sent (env, mq_cb, cls);
296 echo_time = GNUNET_TIME_absolute_get ();
302 * Wait for input on STDIO and send it out over the #ch.
307 struct GNUNET_NETWORK_FDSet *rs;
309 /* FIXME: why use 'rs' here, seems overly complicated... */
310 rs = GNUNET_NETWORK_fdset_create ();
311 GNUNET_NETWORK_fdset_set_native (rs,
313 rd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
314 GNUNET_TIME_UNIT_FOREVER_REL,
319 GNUNET_NETWORK_fdset_destroy (rs);
324 * Function called whenever a channel is destroyed. Should clean up
325 * any associated state.
327 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
330 * @param channel connection to the other end (henceforth invalid)
333 channel_ended (void *cls,
334 const struct GNUNET_CADET_Channel *channel)
336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338 GNUNET_assert (channel == ch);
340 GNUNET_SCHEDULER_shutdown ();
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.
350 * A call to #GNUNET_CADET_channel_destroy causes the channel to be ignored.
351 * In this case the handler MUST return NULL.
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
359 channel_incoming (void *cls,
360 struct GNUNET_CADET_Channel *channel,
361 const struct GNUNET_PeerIdentity *initiator)
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);
371 if (GNUNET_NO == echo)
378 * @brief Send an echo request to the remote peer.
380 * @param cls Closure (NULL).
383 send_echo (void *cls)
385 struct GNUNET_MQ_Envelope *env;
386 struct GNUNET_MessageHeader *msg;
391 env = GNUNET_MQ_msg (msg,
392 GNUNET_MESSAGE_TYPE_CADET_CLI);
393 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
399 * Call CADET's monitor API, request debug dump on the service.
401 * @param cls Closure (unused).
404 request_dump (void *cls)
407 GNUNET_CADET_request_dump (mh);
408 GNUNET_SCHEDULER_shutdown ();
413 * Check data message sanity. Does nothing so far (all messages are OK).
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).
421 check_data (void *cls,
422 const struct GNUNET_MessageHeader *message)
424 return GNUNET_OK; /* all is well-formed */
429 * Function called whenever a message is received.
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.
436 * @param message The actual message.
439 handle_data (void *cls,
440 const struct GNUNET_MessageHeader *message)
442 size_t payload_size = ntohs (message->size) - sizeof (*message);
448 GNUNET_CADET_receive_done (ch);
449 if (GNUNET_YES == echo)
451 if (NULL != listen_port)
453 struct GNUNET_MQ_Envelope *env;
454 struct GNUNET_MessageHeader *msg;
456 env = GNUNET_MQ_msg_extra (msg,
458 GNUNET_MESSAGE_TYPE_CADET_CLI);
459 GNUNET_memcpy (&msg[1],
462 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
468 struct GNUNET_TIME_Relative latency;
470 latency = GNUNET_TIME_absolute_get_duration (echo_time);
471 echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
472 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
474 GNUNET_STRINGS_relative_time_to_string (latency,
476 echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
482 len = ntohs (message->size) - sizeof (*message);
483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
486 buf = (const char *) &message[1];
496 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
498 GNUNET_SCHEDULER_shutdown ();
507 * Method called to retrieve information about all peers in CADET, called
510 * After last peer has been reported, an additional call with NULL is done.
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)
520 peers_callback (void *cls,
521 const struct GNUNET_PeerIdentity *peer,
523 unsigned int n_paths,
524 unsigned int best_path)
528 GNUNET_SCHEDULER_shutdown();
532 "%s tunnel: %c, paths: %u\n",
533 GNUNET_i2s_full (peer),
540 * Method called to retrieve information about a specific peer
541 * known to the service.
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).
553 peer_callback (void *cls,
554 const struct GNUNET_PeerIdentity *peer,
557 unsigned int n_paths,
558 const struct GNUNET_PeerIdentity *paths,
560 int finished_with_paths)
563 const struct GNUNET_PeerIdentity *p;
566 if (GNUNET_YES == finished_with_paths)
568 GNUNET_SCHEDULER_shutdown();
574 "%s [TUNNEL: %s, NEIGHBOR: %s, PATHS: %u]\n",
575 GNUNET_i2s_full (peer),
577 neighbor ? "Y" : "N",
582 "Indirekt path with offset %u: ",
584 for (i = 0; i <= offset && NULL != p;)
604 * Method called to retrieve information about all tunnels in CADET.
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.
614 tunnels_callback (void *cls,
615 const struct GNUNET_PeerIdentity *peer,
616 unsigned int channels,
617 unsigned int connections,
623 GNUNET_SCHEDULER_shutdown();
627 "%s [ENC: %s, CON: %s] CHs: %u, CONNs: %u\n",
628 GNUNET_i2s_full (peer),
637 * Method called to retrieve information about a specific tunnel the cadet peer
638 * has established, o`r is trying to establish.
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.
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,
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));
673 GNUNET_SCHEDULER_shutdown ();
678 * Call CADET's meta API, get all peers known to a peer.
680 * @param cls Closure (unused).
683 get_peers (void *cls)
686 GNUNET_CADET_get_peers (mh, &peers_callback, NULL);
691 * Call CADET's monitor API, get info of one peer.
693 * @param cls Closure (unused).
696 show_peer (void *cls)
698 struct GNUNET_PeerIdentity pid;
702 GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
707 _("Invalid peer ID `%s'\n"),
709 GNUNET_SCHEDULER_shutdown();
712 GNUNET_CADET_get_peer (mh, &pid, peer_callback, NULL);
717 * Call CADET's meta API, get all tunnels known to a peer.
719 * @param cls Closure (unused).
722 get_tunnels (void *cls)
725 GNUNET_CADET_get_tunnels (mh, &tunnels_callback, NULL);
730 * Call CADET's monitor API, get info of one tunnel.
732 * @param cls Closure (unused).
735 show_tunnel (void *cls)
737 struct GNUNET_PeerIdentity pid;
741 GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
746 _("Invalid tunnel owner `%s'\n"),
748 GNUNET_SCHEDULER_shutdown ();
751 GNUNET_CADET_get_tunnel (mh,
759 * Call CADET's monitor API, get info of one channel.
761 * @param cls Closure (unused).
764 show_channel (void *cls)
772 * Call CADET's monitor API, get info of one connection.
774 * @param cls Closure (unused).
777 show_connection (void *cls)
785 * Main function that will be run by the scheduler.
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
796 const struct GNUNET_CONFIGURATION_Handle *cfg)
798 struct GNUNET_MQ_MessageHandler handlers[] = {
799 GNUNET_MQ_hd_var_size (data,
800 GNUNET_MESSAGE_TYPE_CADET_CLI,
801 struct GNUNET_MessageHeader,
803 GNUNET_MQ_handler_end ()
806 /* FIXME add option to monitor apps */
809 if (target_id && args[1])
810 target_port = args[1];
812 if ( (0 != (request_peers | request_tunnels)
815 || NULL != channel_id)
816 && target_id != NULL)
819 _("Extra arguments are not applicable "
820 "in combination with this option.\n"));
824 if (GNUNET_YES == dump)
826 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
827 "Requesting debug dump\n");
828 job = GNUNET_SCHEDULER_add_now (&request_dump,
831 else if (NULL != peer_id)
833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
835 job = GNUNET_SCHEDULER_add_now (&show_peer,
838 else if (NULL != tunnel_id)
840 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
842 job = GNUNET_SCHEDULER_add_now (&show_tunnel,
845 else if (NULL != channel_id)
847 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
849 job = GNUNET_SCHEDULER_add_now (&show_channel,
852 else if (NULL != conn_id)
854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
855 "Show connection\n");
856 job = GNUNET_SCHEDULER_add_now (&show_connection,
859 else if (GNUNET_YES == request_peers)
861 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
863 job = GNUNET_SCHEDULER_add_now (&get_peers,
866 else if (GNUNET_YES == request_tunnels)
868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
869 "Show all tunnels\n");
870 job = GNUNET_SCHEDULER_add_now (&get_tunnels,
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,
881 GNUNET_SCHEDULER_shutdown ();
884 if (NULL != listen_port)
886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
887 "Opening CADET listen port\n");
888 GNUNET_CRYPTO_hash (listen_port,
889 strlen (listen_port),
891 lp = GNUNET_CADET_open_port (mh,
895 NULL /* window changes */,
899 if (NULL != target_id)
901 struct GNUNET_PeerIdentity pid;
902 enum GNUNET_CADET_ChannelOption opt;
905 GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
909 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
910 _("Invalid target `%s'\n"),
912 GNUNET_SCHEDULER_shutdown ();
915 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
916 "Connecting to `%s:%s'\n",
919 opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE;
920 GNUNET_CRYPTO_hash (target_port,
923 ch = GNUNET_CADET_channel_create (mh,
928 NULL /* window changes */,
931 if (GNUNET_YES == echo)
933 echo_task = GNUNET_SCHEDULER_add_now (&send_echo,
946 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
947 _("No action requested\n"));
948 GNUNET_SCHEDULER_shutdown ();
955 * The main function to obtain peer information.
957 * @param argc number of arguments from the command line
958 * @param argv command line arguments
959 * @return 0 ok, 1 on error
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',
972 gettext_noop ("Provide information about a particular connection"),
975 GNUNET_GETOPT_option_flag ('e',
977 gettext_noop ("Activate echo mode"),
980 GNUNET_GETOPT_option_flag ('d',
982 gettext_noop ("Dump debug information to STDERR"),
985 GNUNET_GETOPT_option_string ('o',
988 gettext_noop ("Listen for connections using a shared secret among sender and recipient"),
992 GNUNET_GETOPT_option_string ('p',
995 gettext_noop ("Provide information about a patricular peer"),
999 GNUNET_GETOPT_option_flag ('P',
1001 gettext_noop ("Provide information about all peers"),
1004 GNUNET_GETOPT_option_string ('t',
1007 gettext_noop ("Provide information about a particular tunnel"),
1011 GNUNET_GETOPT_option_flag ('T',
1013 gettext_noop ("Provide information about all tunnels"),
1016 GNUNET_GETOPT_OPTION_END
1020 GNUNET_STRINGS_get_utf8_args (argc, argv,
1024 res = GNUNET_PROGRAM_run (argc, argv,
1025 "gnunet-cadet (OPTIONS | PEER_ID SHARED_SECRET)",
1026 gettext_noop (helpstr),
1027 options, &run, NULL);
1029 GNUNET_free ((void *) argv);
1031 if (GNUNET_OK == res)
1036 /* end of gnunet-cadet.c */