2 This file is part of GNUnet.
3 Copyright (C) 2012 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file cadet/gnunet-cadet.c
23 * @brief Print information about cadet tunnels and peers.
24 * @author Bartlomiej Polot
27 #include "gnunet_util_lib.h"
28 #include "gnunet_cadet_service.h"
35 static int monitor_mode;
40 static int request_peers;
50 static int request_tunnels;
55 static char *tunnel_id;
65 static char *channel_id;
68 * Port to listen on (-p).
70 static uint32_t listen_port;
73 * Request echo service
78 * Request a debug dump
83 * Time of last echo request.
85 static struct GNUNET_TIME_Absolute echo_time;
88 * Task for next echo request.
90 static struct GNUNET_SCHEDULER_Task *echo_task;
95 static char *target_id;
100 static uint32_t target_port;
103 * Data pending in netcat mode.
105 static size_t data_size;
110 static struct GNUNET_CADET_Handle *mh;
115 static struct GNUNET_CADET_Channel *ch;
120 static struct GNUNET_CADET_TransmitHandle *th;
123 * Shutdown task handle.
125 static struct GNUNET_SCHEDULER_Task *sd;
128 * Task for reading from stdin.
130 static struct GNUNET_SCHEDULER_Task *rd_task;
135 static struct GNUNET_SCHEDULER_Task *job;
143 * Convert encryption status to human readable string.
145 * @param status Encryption status.
147 * @return Human readable string.
150 enc_2s (uint16_t status)
169 * Convert connection status to human readable string.
171 * @param status Connection status.
173 * @return Human readable string.
176 conn_2s (uint16_t status)
198 * Task run in monitor mode when the user presses CTRL-C to abort.
199 * Stops monitoring activity.
201 * @param cls Closure (unused).
204 shutdown_task (void *cls)
206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
210 GNUNET_CADET_notify_transmit_ready_cancel (th);
215 GNUNET_CADET_channel_destroy (ch);
220 GNUNET_CADET_disconnect (mh);
225 GNUNET_SCHEDULER_cancel (rd_task);
228 if (NULL != echo_task)
230 GNUNET_SCHEDULER_cancel (echo_task);
235 GNUNET_SCHEDULER_cancel (job);
242 * Function called to notify a client about the connection
243 * begin ready to queue more data. "buf" will be
244 * NULL and "size" zero if the connection was closed for
245 * writing in the meantime.
250 * @param size number of bytes available in buf
251 * @param buf where the callee should write the message
252 * @return number of bytes written to buf
255 data_ready (void *cls, size_t size, void *buf)
257 struct GNUNET_MessageHeader *msg;
262 if (NULL == buf || 0 == size)
264 GNUNET_SCHEDULER_shutdown();
268 total_size = data_size + sizeof (struct GNUNET_MessageHeader);
269 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
270 "sending %u bytes\n",
271 (unsigned int) data_size);
272 GNUNET_assert (size >= total_size);
275 msg->size = htons (total_size);
276 msg->type = htons (GNUNET_MESSAGE_TYPE_CADET_CLI);
277 memcpy (&msg[1], cls, data_size);
278 if (GNUNET_NO == echo)
284 echo_time = GNUNET_TIME_absolute_get ();
292 * Task run in stdio mode, after some data is available at stdin.
294 * @param cls Closure (unused).
297 read_stdio (void *cls)
299 static char buf[60000];
301 data_size = read (0, buf, 60000);
302 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
303 "stdio read %u bytes\n",
304 (unsigned int) data_size);
307 GNUNET_SCHEDULER_shutdown();
310 GNUNET_assert (NULL == th);
311 th = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
312 GNUNET_TIME_UNIT_FOREVER_REL,
313 sizeof (struct GNUNET_MessageHeader)
320 * Start listening to stdin
325 struct GNUNET_NETWORK_FDSet *rs;
327 rs = GNUNET_NETWORK_fdset_create ();
328 GNUNET_NETWORK_fdset_set_native (rs, 0);
329 rd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
330 GNUNET_TIME_UNIT_FOREVER_REL,
333 GNUNET_NETWORK_fdset_destroy (rs);
338 * Function called whenever a channel is destroyed. Should clean up
339 * any associated state.
341 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
343 * @param cls closure (set from #GNUNET_CADET_connect)
344 * @param channel connection to the other end (henceforth invalid)
345 * @param channel_ctx place where local state associated
346 * with the channel is stored
349 channel_ended (void *cls,
350 const struct GNUNET_CADET_Channel *channel,
353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n");
357 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ended: %p, expected: %p\n", channel, ch);
365 GNUNET_CADET_notify_transmit_ready_cancel (th);
369 GNUNET_SCHEDULER_shutdown ();
374 * Method called whenever another peer has added us to a channel
375 * the other peer initiated.
376 * Only called (once) upon reception of data with a message type which was
377 * subscribed to in #GNUNET_CADET_connect.
379 * A call to #GNUNET_CADET_channel_destroy causes te channel to be ignored. In
380 * this case the handler MUST return NULL.
383 * @param channel new handle to the channel
384 * @param initiator peer that started the channel
385 * @param port Port this channel is for.
386 * @param options CadetOption flag field, with all active option bits set to 1.
388 * @return initial channel context for the channel
389 * (can be NULL -- that's not an error)
392 channel_incoming (void *cls,
393 struct GNUNET_CADET_Channel * channel,
394 const struct GNUNET_PeerIdentity * initiator,
395 uint32_t port, enum GNUNET_CADET_ChannelOption options)
397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
398 "Incoming channel %p on port %u\n",
403 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
404 "A channel already exists (%p)\n", ch);
405 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
406 "Incoming channel %p on port %u\n", channel, port);
409 if (0 == listen_port)
411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not listening to channels\n");
415 if (GNUNET_NO == echo)
425 * @brief Send an echo request to the remote peer.
427 * @param cls Closure (NULL).
430 send_echo (void *cls)
434 GNUNET_assert (NULL == th);
435 th = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
436 GNUNET_TIME_UNIT_FOREVER_REL,
437 sizeof (struct GNUNET_MessageHeader),
443 * Call CADET's monitor API, request debug dump on the service.
445 * @param cls Closure (unused).
448 request_dump (void *cls)
450 GNUNET_CADET_request_dump (mh);
451 GNUNET_SCHEDULER_cancel (sd);
452 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
453 &shutdown_task, NULL);
458 * Call CADET's monitor API, get info of one connection.
460 * @param cls Closure (unused).
463 create_channel (void *cls)
465 struct GNUNET_PeerIdentity pid;
466 enum GNUNET_CADET_ChannelOption opt;
468 GNUNET_assert (NULL == ch);
471 GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
476 _("Invalid target `%s'\n"),
478 GNUNET_SCHEDULER_shutdown ();
481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id);
482 opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE;
483 ch = GNUNET_CADET_channel_create (mh, NULL, &pid, target_port, opt);
484 if (GNUNET_NO == echo)
487 echo_task = GNUNET_SCHEDULER_add_now (&send_echo, NULL);
492 * Function called whenever a message is received.
494 * Each time the function must call #GNUNET_CADET_receive_done on the channel
495 * in order to receive the next message. This doesn't need to be immediate:
496 * can be delayed if some processing is done on the message.
498 * @param cls Closure (set from #GNUNET_CADET_connect).
499 * @param channel Connection to the other end.
500 * @param channel_ctx Place to store local state associated with the channel.
501 * @param message The actual message.
502 * @return #GNUNET_OK to keep the channel open,
503 * #GNUNET_SYSERR to close it (signal serious error).
506 data_callback (void *cls,
507 struct GNUNET_CADET_Channel *channel,
509 const struct GNUNET_MessageHeader *message)
515 GNUNET_break (ch == channel);
516 GNUNET_CADET_receive_done (channel);
518 if (GNUNET_YES == echo)
520 if (0 != listen_port)
522 /* Just listening to echo incoming messages*/
525 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
526 "Last echo reply not yet sent, dropping current reply.\n");
529 th = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
530 GNUNET_TIME_UNIT_FOREVER_REL,
531 sizeof (struct GNUNET_MessageHeader),
537 struct GNUNET_TIME_Relative latency;
539 latency = GNUNET_TIME_absolute_get_duration (echo_time);
540 echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
541 FPRINTF (stdout, "time: %s\n",
542 GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
543 echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
548 len = ntohs (message->size) - sizeof (*message);
549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len);
550 buf = (const char *) &message[1];
554 done = write (1, &buf[off], len - off);
558 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
560 return GNUNET_SYSERR;
569 * Method called to retrieve information about all peers in CADET, called
572 * After last peer has been reported, an additional call with NULL is done.
574 * @param cls Closure.
575 * @param peer Peer, or NULL on "EOF".
576 * @param tunnel Do we have a tunnel towards this peer?
577 * @param n_paths Number of known paths towards this peer.
578 * @param best_path How long is the best path?
579 * (0 = unknown, 1 = ourselves, 2 = neighbor)
582 peers_callback (void *cls,
583 const struct GNUNET_PeerIdentity *peer,
585 unsigned int n_paths,
586 unsigned int best_path)
590 if (GNUNET_YES != monitor_mode)
592 GNUNET_SCHEDULER_shutdown();
596 FPRINTF (stdout, "%s tunnel: %c, paths: %u\n",
597 GNUNET_i2s_full (peer), tunnel ? 'Y' : 'N', n_paths);
601 * Method called to retrieve information about a specific peer
602 * known to the service.
604 * @param cls Closure.
605 * @param peer Peer ID.
606 * @param tunnel Do we have a tunnel towards this peer? #GNUNET_YES/#GNUNET_NO
607 * @param neighbor Is this a direct neighbor? #GNUNET_YES/#GNUNET_NO
608 * @param n_paths Number of paths known towards peer.
609 * @param paths Array of PEER_IDs representing all paths to reach the peer.
610 * Each path starts with the local peer.
611 * Each path ends with the destination peer (given in @c peer).
614 peer_callback (void *cls,
615 const struct GNUNET_PeerIdentity *peer,
618 unsigned int n_paths,
619 struct GNUNET_PeerIdentity *paths)
622 struct GNUNET_PeerIdentity *p;
624 FPRINTF (stdout, "%s [TUNNEL: %s, NEIGHBOR: %s, PATHS: %u]\n",
625 GNUNET_i2s_full (peer),
626 tunnel ? "Y" : "N", neighbor ? "Y" : "N", n_paths);
628 for (i = 0; i < n_paths && NULL != p;)
630 FPRINTF (stdout, "%s ", GNUNET_i2s (p));
631 if (0 == memcmp (p, peer, sizeof (*p)))
633 FPRINTF (stdout, "\n");
639 GNUNET_SCHEDULER_shutdown();
644 * Method called to retrieve information about all tunnels in CADET.
646 * @param cls Closure.
647 * @param peer Destination peer.
648 * @param channels Number of channels.
649 * @param connections Number of connections.
650 * @param estate Encryption state.
651 * @param cstate Connectivity state.
654 tunnels_callback (void *cls,
655 const struct GNUNET_PeerIdentity *peer,
656 unsigned int channels,
657 unsigned int connections,
663 if (GNUNET_YES != monitor_mode)
665 GNUNET_SCHEDULER_shutdown();
669 FPRINTF (stdout, "%s [ENC: %s, CON: %s] CHs: %u, CONNs: %u\n",
670 GNUNET_i2s_full (peer),
671 enc_2s (estate), conn_2s (cstate),
672 channels, connections);
677 * Method called to retrieve information about a specific tunnel the cadet peer
678 * has established, o`r is trying to establish.
680 * @param cls Closure.
681 * @param peer Peer towards whom the tunnel is directed.
682 * @param n_channels Number of channels.
683 * @param n_connections Number of connections.
684 * @param channels Channels.
685 * @param connections Connections.
686 * @param estate Encryption status.
687 * @param cstate Connectivity status.
690 tunnel_callback (void *cls,
691 const struct GNUNET_PeerIdentity *peer,
692 unsigned int n_channels,
693 unsigned int n_connections,
695 struct GNUNET_CADET_Hash *connections,
703 FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer));
704 FPRINTF (stdout, "\t%u channels\n", n_channels);
705 for (i = 0; i < n_channels; i++)
706 FPRINTF (stdout, "\t\t%X\n", ntohl (channels[i]));
707 FPRINTF (stdout, "\t%u connections\n", n_connections);
708 for (i = 0; i < n_connections; i++)
709 FPRINTF (stdout, "\t\t%s\n", GC_h2s (&connections[i]));
710 FPRINTF (stdout, "\tencryption state: %s\n", enc_2s (estate));
711 FPRINTF (stdout, "\tconnection state: %s\n", conn_2s (cstate));
713 if (GNUNET_YES != monitor_mode)
715 GNUNET_SCHEDULER_shutdown ();
722 * Call CADET's meta API, get all peers known to a peer.
724 * @param cls Closure (unused).
727 get_peers (void *cls)
730 GNUNET_CADET_get_peers (mh, &peers_callback, NULL);
735 * Call CADET's monitor API, get info of one peer.
737 * @param cls Closure (unused).
740 show_peer (void *cls)
742 struct GNUNET_PeerIdentity pid;
746 GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
751 _("Invalid peer ID `%s'\n"),
753 GNUNET_SCHEDULER_shutdown();
756 GNUNET_CADET_get_peer (mh, &pid, peer_callback, NULL);
761 * Call CADET's meta API, get all tunnels known to a peer.
763 * @param cls Closure (unused).
766 get_tunnels (void *cls)
769 GNUNET_CADET_get_tunnels (mh, &tunnels_callback, NULL);
774 * Call CADET's monitor API, get info of one tunnel.
776 * @param cls Closure (unused).
779 show_tunnel (void *cls)
781 struct GNUNET_PeerIdentity pid;
784 GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
789 _("Invalid tunnel owner `%s'\n"),
791 GNUNET_SCHEDULER_shutdown ();
794 GNUNET_CADET_get_tunnel (mh, &pid, tunnel_callback, NULL);
799 * Call CADET's monitor API, get info of one channel.
801 * @param cls Closure (unused).
804 show_channel (void *cls)
812 * Call CADET's monitor API, get info of one connection.
814 * @param cls Closure (unused).
817 show_connection (void *cls)
825 * Main function that will be run by the scheduler.
828 * @param args remaining command-line arguments
829 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
830 * @param cfg configuration
836 const struct GNUNET_CONFIGURATION_Handle *cfg)
838 GNUNET_CADET_InboundChannelNotificationHandler *newch = NULL;
839 GNUNET_CADET_ChannelEndHandler *endch = NULL;
840 static const struct GNUNET_CADET_MessageHandler handlers[] = {
841 {&data_callback, GNUNET_MESSAGE_TYPE_CADET_CLI, 0},
842 {NULL, 0, 0} /* FIXME add option to monitor msg types */
844 static uint32_t *ports = NULL;
845 /* FIXME add option to monitor apps */
848 target_port = args[0] && args[1] ? atoi(args[1]) : 0;
849 if ( (0 != (request_peers | request_tunnels)
853 || NULL != channel_id)
854 && target_id != NULL)
857 _("You must NOT give a TARGET "
858 "when using 'request all' options\n"));
862 if (GNUNET_YES == dump)
864 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
865 "requesting debug dump\n");
866 GNUNET_SCHEDULER_add_now (&request_dump, NULL);
868 else if (NULL != target_id)
870 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
871 "Creating channel to %s\n",
873 GNUNET_SCHEDULER_add_now (&create_channel, NULL);
874 endch = &channel_ended;
876 else if (0 != listen_port)
878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Listen\n");
879 newch = &channel_incoming;
880 endch = &channel_ended;
881 ports = GNUNET_malloc (sizeof (uint32_t) * 2);
882 ports[0] = listen_port;
884 else if (NULL != peer_id)
886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show peer\n");
887 job = GNUNET_SCHEDULER_add_now (&show_peer, NULL);
889 else if (NULL != tunnel_id)
891 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n");
892 job = GNUNET_SCHEDULER_add_now (&show_tunnel, NULL);
894 else if (NULL != channel_id)
896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n");
897 job = GNUNET_SCHEDULER_add_now (&show_channel, NULL);
899 else if (NULL != conn_id)
901 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
902 job = GNUNET_SCHEDULER_add_now (&show_connection, NULL);
904 else if (GNUNET_YES == request_peers)
906 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n");
907 job = GNUNET_SCHEDULER_add_now (&get_peers, NULL);
909 else if (GNUNET_YES == request_tunnels)
911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
912 job = GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
916 FPRINTF (stderr, "No action requested\n");
920 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to cadet\n");
921 mh = GNUNET_CADET_connect (cfg,
923 newch, /* new channel */
927 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done\n");
929 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
931 sd = GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
936 * The main function to obtain peer information.
938 * @param argc number of arguments from the command line
939 * @param argv command line arguments
940 * @return 0 ok, 1 on error
943 main (int argc, char *const *argv)
946 const char helpstr[] = "Create channels and retreive info about cadets status.";
947 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
948 // {'a', "channel", "TUNNEL_ID:CHANNEL_ID",
949 // gettext_noop ("provide information about a particular channel"),
950 // GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id},
951 {'C', "connection", "CONNECTION_ID",
952 gettext_noop ("provide information about a particular connection"),
953 GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id},
955 gettext_noop ("activate echo mode"),
956 GNUNET_NO, &GNUNET_GETOPT_set_one, &echo},
958 gettext_noop ("dump debug information to STDERR"),
959 GNUNET_NO, &GNUNET_GETOPT_set_one, &dump},
960 // {'m', "monitor", NULL,
961 // gettext_noop ("provide information about all events (continuously)"),
962 // GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_mode},
963 {'o', "open-port", NULL,
964 gettext_noop ("port to listen to (default; 0)"),
965 GNUNET_YES, &GNUNET_GETOPT_set_uint, &listen_port},
966 {'p', "peer", "PEER_ID",
967 gettext_noop ("provide information about a patricular peer"),
968 GNUNET_YES, &GNUNET_GETOPT_set_string, &peer_id},
970 gettext_noop ("provide information about all peers"),
971 GNUNET_NO, &GNUNET_GETOPT_set_one, &request_peers},
972 {'t', "tunnel", "TUNNEL_ID",
973 gettext_noop ("provide information about a particular tunnel"),
974 GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id},
975 {'T', "tunnels", NULL,
976 gettext_noop ("provide information about all tunnels"),
977 GNUNET_NO, &GNUNET_GETOPT_set_one, &request_tunnels},
979 GNUNET_GETOPT_OPTION_END
982 monitor_mode = GNUNET_NO;
984 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
987 res = GNUNET_PROGRAM_run (argc, argv, "gnunet-cadet (OPTIONS | TARGET PORT)",
988 gettext_noop (helpstr),
989 options, &run, NULL);
991 GNUNET_free ((void *) argv);
993 if (GNUNET_OK == res)
999 /* end of gnunet-cadet.c */