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/>.
20 * @file cadet/gnunet-cadet.c
21 * @brief Print information about cadet tunnels and peers.
22 * @author Bartlomiej Polot
23 * @author Christian Grothoff
26 #include "gnunet_util_lib.h"
27 #include "gnunet_cadet_service.h"
30 #define STREAM_BUFFER_SIZE 1024 // Pakets
35 static int request_peers;
45 static int request_tunnels;
50 static char *tunnel_id;
60 static char *channel_id;
63 * Port to listen on (-o).
65 static char *listen_port;
68 * Request echo service
73 * Request a debug dump
78 * Time of last echo request.
80 static struct GNUNET_TIME_Absolute echo_time;
83 * Task for next echo request.
85 static struct GNUNET_SCHEDULER_Task *echo_task;
90 static char *target_id;
95 static char *target_port = "default";
100 static struct GNUNET_CADET_Handle *mh;
105 static struct GNUNET_CADET_Channel *ch;
108 * HashCode of the given port string
110 static struct GNUNET_HashCode porthash;
113 * Data structure for ongoing reception of incoming virtual circuits.
115 struct GNUNET_CADET_Port *lp;
118 * Task for reading from stdin.
120 static struct GNUNET_SCHEDULER_Task *rd_task;
125 static struct GNUNET_SCHEDULER_Task *job;
127 static unsigned int sent_pkt;
131 * Wait for input on STDIO and send it out over the #ch.
138 * Convert encryption status to human readable string.
140 * @param status Encryption status.
142 * @return Human readable string.
145 enc_2s (uint16_t status)
164 * Convert connection status to human readable string.
166 * @param status Connection status.
168 * @return Human readable string.
171 conn_2s (uint16_t status)
193 * Task to shut down this application.
195 * @param cls Closure (unused).
198 shutdown_task (void *cls)
200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
204 GNUNET_CADET_close_port (lp);
209 GNUNET_CADET_channel_destroy (ch);
214 GNUNET_CADET_disconnect (mh);
219 GNUNET_SCHEDULER_cancel (rd_task);
222 if (NULL != echo_task)
224 GNUNET_SCHEDULER_cancel (echo_task);
229 GNUNET_SCHEDULER_cancel (job);
242 * Task run in stdio mode, after some data is available at stdin.
244 * @param cls Closure (unused).
247 read_stdio (void *cls)
249 struct GNUNET_MQ_Envelope *env;
250 struct GNUNET_MessageHeader *msg;
260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
261 "read() returned %s\n", strerror(errno));
262 GNUNET_SCHEDULER_shutdown();
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,
270 GNUNET_MESSAGE_TYPE_CADET_CLI);
271 GNUNET_memcpy (&msg[1],
274 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
279 if (GNUNET_NO == echo)
281 // Use MQ's notification if too much data of stdin is pooring in too fast.
282 if (STREAM_BUFFER_SIZE < sent_pkt)
284 GNUNET_MQ_notify_sent (env, mq_cb, cls);
294 echo_time = GNUNET_TIME_absolute_get ();
300 * Wait for input on STDIO and send it out over the #ch.
305 struct GNUNET_NETWORK_FDSet *rs;
307 /* FIXME: why use 'rs' here, seems overly complicated... */
308 rs = GNUNET_NETWORK_fdset_create ();
309 GNUNET_NETWORK_fdset_set_native (rs,
311 rd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
312 GNUNET_TIME_UNIT_FOREVER_REL,
317 GNUNET_NETWORK_fdset_destroy (rs);
322 * Function called whenever a channel is destroyed. Should clean up
323 * any associated state.
325 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
328 * @param channel connection to the other end (henceforth invalid)
331 channel_ended (void *cls,
332 const struct GNUNET_CADET_Channel *channel)
334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
336 GNUNET_assert (channel == ch);
338 GNUNET_SCHEDULER_shutdown ();
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.
348 * A call to #GNUNET_CADET_channel_destroy causes the channel to be ignored.
349 * In this case the handler MUST return NULL.
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
357 channel_incoming (void *cls,
358 struct GNUNET_CADET_Channel *channel,
359 const struct GNUNET_PeerIdentity *initiator)
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);
369 if (GNUNET_NO == echo)
376 * @brief Send an echo request to the remote peer.
378 * @param cls Closure (NULL).
381 send_echo (void *cls)
383 struct GNUNET_MQ_Envelope *env;
384 struct GNUNET_MessageHeader *msg;
389 env = GNUNET_MQ_msg (msg,
390 GNUNET_MESSAGE_TYPE_CADET_CLI);
391 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
397 * Call CADET's monitor API, request debug dump on the service.
399 * @param cls Closure (unused).
402 request_dump (void *cls)
405 GNUNET_CADET_request_dump (mh);
406 GNUNET_SCHEDULER_shutdown ();
411 * Check data message sanity. Does nothing so far (all messages are OK).
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).
419 check_data (void *cls,
420 const struct GNUNET_MessageHeader *message)
422 return GNUNET_OK; /* all is well-formed */
427 * Function called whenever a message is received.
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.
434 * @param message The actual message.
437 handle_data (void *cls,
438 const struct GNUNET_MessageHeader *message)
440 size_t payload_size = ntohs (message->size) - sizeof (*message);
446 GNUNET_CADET_receive_done (ch);
447 if (GNUNET_YES == echo)
449 if (NULL != listen_port)
451 struct GNUNET_MQ_Envelope *env;
452 struct GNUNET_MessageHeader *msg;
454 env = GNUNET_MQ_msg_extra (msg,
456 GNUNET_MESSAGE_TYPE_CADET_CLI);
457 GNUNET_memcpy (&msg[1],
460 GNUNET_MQ_send (GNUNET_CADET_get_mq (ch),
466 struct GNUNET_TIME_Relative latency;
468 latency = GNUNET_TIME_absolute_get_duration (echo_time);
469 echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
470 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
472 GNUNET_STRINGS_relative_time_to_string (latency,
474 echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
480 len = ntohs (message->size) - sizeof (*message);
481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
484 buf = (const char *) &message[1];
494 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
496 GNUNET_SCHEDULER_shutdown ();
505 * Method called to retrieve information about all peers in CADET, called
508 * After last peer has been reported, an additional call with NULL is done.
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)
518 peers_callback (void *cls,
519 const struct GNUNET_PeerIdentity *peer,
521 unsigned int n_paths,
522 unsigned int best_path)
526 GNUNET_SCHEDULER_shutdown();
530 "%s tunnel: %c, paths: %u\n",
531 GNUNET_i2s_full (peer),
538 * Method called to retrieve information about a specific peer
539 * known to the service.
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).
551 peer_callback (void *cls,
552 const struct GNUNET_PeerIdentity *peer,
555 unsigned int n_paths,
556 const struct GNUNET_PeerIdentity *paths,
558 int finished_with_paths)
561 const struct GNUNET_PeerIdentity *p;
564 if (GNUNET_YES == finished_with_paths)
566 GNUNET_SCHEDULER_shutdown();
572 "%s [TUNNEL: %s, NEIGHBOR: %s, PATHS: %u]\n",
573 GNUNET_i2s_full (peer),
575 neighbor ? "Y" : "N",
580 "Indirekt path with offset %u: ",
582 for (i = 0; i <= offset && NULL != p;)
602 * Method called to retrieve information about all tunnels in CADET.
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.
612 tunnels_callback (void *cls,
613 const struct GNUNET_PeerIdentity *peer,
614 unsigned int channels,
615 unsigned int connections,
621 GNUNET_SCHEDULER_shutdown();
625 "%s [ENC: %s, CON: %s] CHs: %u, CONNs: %u\n",
626 GNUNET_i2s_full (peer),
635 * Method called to retrieve information about a specific tunnel the cadet peer
636 * has established, o`r is trying to establish.
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.
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,
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));
671 GNUNET_SCHEDULER_shutdown ();
676 * Call CADET's meta API, get all peers known to a peer.
678 * @param cls Closure (unused).
681 get_peers (void *cls)
684 GNUNET_CADET_get_peers (mh, &peers_callback, NULL);
689 * Call CADET's monitor API, get info of one peer.
691 * @param cls Closure (unused).
694 show_peer (void *cls)
696 struct GNUNET_PeerIdentity pid;
700 GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
705 _("Invalid peer ID `%s'\n"),
707 GNUNET_SCHEDULER_shutdown();
710 GNUNET_CADET_get_peer (mh, &pid, peer_callback, NULL);
715 * Call CADET's meta API, get all tunnels known to a peer.
717 * @param cls Closure (unused).
720 get_tunnels (void *cls)
723 GNUNET_CADET_get_tunnels (mh, &tunnels_callback, NULL);
728 * Call CADET's monitor API, get info of one tunnel.
730 * @param cls Closure (unused).
733 show_tunnel (void *cls)
735 struct GNUNET_PeerIdentity pid;
739 GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
744 _("Invalid tunnel owner `%s'\n"),
746 GNUNET_SCHEDULER_shutdown ();
749 GNUNET_CADET_get_tunnel (mh,
757 * Call CADET's monitor API, get info of one channel.
759 * @param cls Closure (unused).
762 show_channel (void *cls)
770 * Call CADET's monitor API, get info of one connection.
772 * @param cls Closure (unused).
775 show_connection (void *cls)
783 * Main function that will be run by the scheduler.
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
794 const struct GNUNET_CONFIGURATION_Handle *cfg)
796 struct GNUNET_MQ_MessageHandler handlers[] = {
797 GNUNET_MQ_hd_var_size (data,
798 GNUNET_MESSAGE_TYPE_CADET_CLI,
799 struct GNUNET_MessageHeader,
801 GNUNET_MQ_handler_end ()
804 /* FIXME add option to monitor apps */
807 if (target_id && args[1])
808 target_port = args[1];
810 if ( (0 != (request_peers | request_tunnels)
813 || NULL != channel_id)
814 && target_id != NULL)
817 _("Extra arguments are not applicable "
818 "in combination with this option.\n"));
822 if (GNUNET_YES == dump)
824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
825 "Requesting debug dump\n");
826 job = GNUNET_SCHEDULER_add_now (&request_dump,
829 else if (NULL != peer_id)
831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
833 job = GNUNET_SCHEDULER_add_now (&show_peer,
836 else if (NULL != tunnel_id)
838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
840 job = GNUNET_SCHEDULER_add_now (&show_tunnel,
843 else if (NULL != channel_id)
845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
847 job = GNUNET_SCHEDULER_add_now (&show_channel,
850 else if (NULL != conn_id)
852 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
853 "Show connection\n");
854 job = GNUNET_SCHEDULER_add_now (&show_connection,
857 else if (GNUNET_YES == request_peers)
859 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
861 job = GNUNET_SCHEDULER_add_now (&get_peers,
864 else if (GNUNET_YES == request_tunnels)
866 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
867 "Show all tunnels\n");
868 job = GNUNET_SCHEDULER_add_now (&get_tunnels,
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,
879 GNUNET_SCHEDULER_shutdown ();
882 if (NULL != listen_port)
884 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
885 "Opening CADET listen port\n");
886 GNUNET_CRYPTO_hash (listen_port,
887 strlen (listen_port),
889 lp = GNUNET_CADET_open_port (mh,
893 NULL /* window changes */,
897 if (NULL != target_id)
899 struct GNUNET_PeerIdentity pid;
900 enum GNUNET_CADET_ChannelOption opt;
903 GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
907 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
908 _("Invalid target `%s'\n"),
910 GNUNET_SCHEDULER_shutdown ();
913 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
914 "Connecting to `%s:%s'\n",
917 opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE;
918 GNUNET_CRYPTO_hash (target_port,
921 ch = GNUNET_CADET_channel_create (mh,
926 NULL /* window changes */,
929 if (GNUNET_YES == echo)
931 echo_task = GNUNET_SCHEDULER_add_now (&send_echo,
944 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
945 _("No action requested\n"));
946 GNUNET_SCHEDULER_shutdown ();
953 * The main function to obtain peer information.
955 * @param argc number of arguments from the command line
956 * @param argv command line arguments
957 * @return 0 ok, 1 on error
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',
970 gettext_noop ("Provide information about a particular connection"),
973 GNUNET_GETOPT_option_flag ('e',
975 gettext_noop ("Activate echo mode"),
978 GNUNET_GETOPT_option_flag ('d',
980 gettext_noop ("Dump debug information to STDERR"),
983 GNUNET_GETOPT_option_string ('o',
986 gettext_noop ("Listen for connections using a shared secret among sender and recipient"),
990 GNUNET_GETOPT_option_string ('p',
993 gettext_noop ("Provide information about a patricular peer"),
997 GNUNET_GETOPT_option_flag ('P',
999 gettext_noop ("Provide information about all peers"),
1002 GNUNET_GETOPT_option_string ('t',
1005 gettext_noop ("Provide information about a particular tunnel"),
1009 GNUNET_GETOPT_option_flag ('T',
1011 gettext_noop ("Provide information about all tunnels"),
1014 GNUNET_GETOPT_OPTION_END
1018 GNUNET_STRINGS_get_utf8_args (argc, argv,
1022 res = GNUNET_PROGRAM_run (argc, argv,
1023 "gnunet-cadet (OPTIONS | PEER_ID SHARED_SECRET)",
1024 gettext_noop (helpstr),
1025 options, &run, NULL);
1027 GNUNET_free ((void *) argv);
1029 if (GNUNET_OK == res)
1034 /* end of gnunet-cadet.c */