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 (-o).
70 static char *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 char *target_port = "default";
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 * HashCode of the given port string
125 static struct GNUNET_HashCode porthash;
128 * Data structure for ongoing reception of incoming virtual circuits.
130 struct GNUNET_CADET_Port *lp;
133 * Shutdown task handle.
135 static struct GNUNET_SCHEDULER_Task *sd;
138 * Task for reading from stdin.
140 static struct GNUNET_SCHEDULER_Task *rd_task;
145 static struct GNUNET_SCHEDULER_Task *job;
153 * Convert encryption status to human readable string.
155 * @param status Encryption status.
157 * @return Human readable string.
160 enc_2s (uint16_t status)
179 * Convert connection status to human readable string.
181 * @param status Connection status.
183 * @return Human readable string.
186 conn_2s (uint16_t status)
208 * Task to shut down this application.
210 * @param cls Closure (unused).
213 shutdown_task (void *cls)
215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
219 GNUNET_CADET_notify_transmit_ready_cancel (th);
224 GNUNET_CADET_channel_destroy (ch);
227 else if (NULL != target_id) {
228 // FIXME: would be nicer to have proper NACK support from cadet_api
229 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
230 "Connection refused to %s\n",
235 GNUNET_CADET_disconnect (mh);
240 GNUNET_SCHEDULER_cancel (rd_task);
243 if (NULL != echo_task)
245 GNUNET_SCHEDULER_cancel (echo_task);
250 GNUNET_SCHEDULER_cancel (job);
257 * Function called to notify a client about the connection
258 * begin ready to queue more data. "buf" will be
259 * NULL and "size" zero if the connection was closed for
260 * writing in the meantime.
265 * @param size number of bytes available in buf
266 * @param buf where the callee should write the message
267 * @return number of bytes written to buf
270 data_ready (void *cls, size_t size, void *buf)
272 struct GNUNET_MessageHeader *msg;
277 if (NULL == buf || 0 == size)
279 GNUNET_SCHEDULER_shutdown();
283 total_size = data_size + sizeof (struct GNUNET_MessageHeader);
284 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
285 "sending %u bytes\n",
286 (unsigned int) data_size);
287 GNUNET_assert (size >= total_size);
290 msg->size = htons (total_size);
291 msg->type = htons (GNUNET_MESSAGE_TYPE_CADET_CLI);
292 GNUNET_memcpy (&msg[1], cls, data_size);
293 if (GNUNET_NO == echo)
299 echo_time = GNUNET_TIME_absolute_get ();
307 * Task run in stdio mode, after some data is available at stdin.
309 * @param cls Closure (unused).
312 read_stdio (void *cls)
314 static char buf[60000];
317 data_size = read (0, buf, 60000);
318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
319 "stdio read %u bytes\n",
320 (unsigned int) data_size);
323 GNUNET_SCHEDULER_shutdown();
326 GNUNET_assert (NULL == th);
327 th = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
328 GNUNET_TIME_UNIT_FOREVER_REL,
329 sizeof (struct GNUNET_MessageHeader)
336 * Start listening to stdin
341 struct GNUNET_NETWORK_FDSet *rs;
343 rs = GNUNET_NETWORK_fdset_create ();
344 GNUNET_NETWORK_fdset_set_native (rs, 0);
345 rd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
346 GNUNET_TIME_UNIT_FOREVER_REL,
349 GNUNET_NETWORK_fdset_destroy (rs);
354 * Function called whenever a channel is destroyed. Should clean up
355 * any associated state.
357 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
359 * @param cls closure (set from #GNUNET_CADET_connect)
360 * @param channel connection to the other end (henceforth invalid)
361 * @param channel_ctx place where local state associated
362 * with the channel is stored
365 channel_ended (void *cls,
366 const struct GNUNET_CADET_Channel *channel,
369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n");
373 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ended: %p, expected: %p\n", channel, ch);
381 GNUNET_CADET_notify_transmit_ready_cancel (th);
385 GNUNET_SCHEDULER_shutdown ();
390 * Method called whenever another peer has added us to a channel
391 * the other peer initiated.
392 * Only called (once) upon reception of data with a message type which was
393 * subscribed to in #GNUNET_CADET_connect.
395 * A call to #GNUNET_CADET_channel_destroy causes the channel to be ignored.
396 * In this case the handler MUST return NULL.
399 * @param channel new handle to the channel
400 * @param initiator peer that started the channel
401 * @param port Port this channel is for.
402 * @param options CadetOption flag field, with all active option bits set to 1.
404 * @return initial channel context for the channel
405 * (can be NULL -- that's not an error)
408 channel_incoming (void *cls,
409 struct GNUNET_CADET_Channel *channel,
410 const struct GNUNET_PeerIdentity *initiator,
411 const struct GNUNET_HashCode *port,
412 enum GNUNET_CADET_ChannelOption options)
414 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
415 "Connected from %s\n",
416 GNUNET_i2s_full (initiator));
417 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
418 "Incoming channel %p on port %s\n",
419 channel, GNUNET_h2s (port));
423 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
424 "A channel already exists (%p)\n", ch);
426 * From now on multiple channels will be sending data to us
427 * making the service of this command unpredictable in its
428 * current implementation. So for now let's just bail out.
430 GNUNET_SCHEDULER_shutdown();
433 if (NULL == listen_port)
435 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Not listening to channels\n");
439 // Closing the listen port currently breaks open connections.
440 // Is this an intentional departure from POSIX socket behavior?
443 /* Now that we have our circuit up and running, let's not
444 * get confused by further incoming connect requests.
446 GNUNET_CADET_close_port (lp);
451 if (GNUNET_NO == echo)
461 * @brief Send an echo request to the remote peer.
463 * @param cls Closure (NULL).
466 send_echo (void *cls)
471 GNUNET_assert (NULL == th);
472 th = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
473 GNUNET_TIME_UNIT_FOREVER_REL,
474 sizeof (struct GNUNET_MessageHeader),
480 * Call CADET's monitor API, request debug dump on the service.
482 * @param cls Closure (unused).
485 request_dump (void *cls)
487 GNUNET_CADET_request_dump (mh);
488 GNUNET_SCHEDULER_cancel (sd);
489 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
490 &shutdown_task, NULL);
495 * Call CADET's monitor API, get info of one connection.
497 * @param cls Closure (unused).
500 create_channel (void *cls)
502 struct GNUNET_PeerIdentity pid;
503 enum GNUNET_CADET_ChannelOption opt;
505 GNUNET_assert (NULL == ch);
508 GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
513 _("Invalid target `%s'\n"),
515 GNUNET_SCHEDULER_shutdown ();
518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id);
519 opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE;
520 GNUNET_CRYPTO_hash (target_port, strlen(target_port), &porthash);
521 ch = GNUNET_CADET_channel_create (mh, NULL, &pid, &porthash, opt);
522 if (GNUNET_NO == echo)
525 echo_task = GNUNET_SCHEDULER_add_now (&send_echo, NULL);
530 * Function called whenever a message is received.
532 * Each time the function must call #GNUNET_CADET_receive_done on the channel
533 * in order to receive the next message. This doesn't need to be immediate:
534 * can be delayed if some processing is done on the message.
536 * @param cls Closure (set from #GNUNET_CADET_connect).
537 * @param channel Connection to the other end.
538 * @param channel_ctx Place to store local state associated with the channel.
539 * @param message The actual message.
540 * @return #GNUNET_OK to keep the channel open,
541 * #GNUNET_SYSERR to close it (signal serious error).
544 data_callback (void *cls,
545 struct GNUNET_CADET_Channel *channel,
547 const struct GNUNET_MessageHeader *message)
553 GNUNET_break (ch == channel);
554 GNUNET_CADET_receive_done (channel);
556 if (GNUNET_YES == echo)
558 if (NULL != listen_port)
560 /* Just listening to echo incoming messages*/
563 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
564 "Last echo reply not yet sent, dropping current reply.\n");
567 th = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
568 GNUNET_TIME_UNIT_FOREVER_REL,
569 sizeof (struct GNUNET_MessageHeader),
575 struct GNUNET_TIME_Relative latency;
577 latency = GNUNET_TIME_absolute_get_duration (echo_time);
578 echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
579 FPRINTF (stdout, "time: %s\n",
580 GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
581 echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
586 len = ntohs (message->size) - sizeof (*message);
587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len);
588 buf = (const char *) &message[1];
592 done = write (1, &buf[off], len - off);
596 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
598 return GNUNET_SYSERR;
607 * Method called to retrieve information about all peers in CADET, called
610 * After last peer has been reported, an additional call with NULL is done.
612 * @param cls Closure.
613 * @param peer Peer, or NULL on "EOF".
614 * @param tunnel Do we have a tunnel towards this peer?
615 * @param n_paths Number of known paths towards this peer.
616 * @param best_path How long is the best path?
617 * (0 = unknown, 1 = ourselves, 2 = neighbor)
620 peers_callback (void *cls,
621 const struct GNUNET_PeerIdentity *peer,
623 unsigned int n_paths,
624 unsigned int best_path)
628 if (GNUNET_YES != monitor_mode)
630 GNUNET_SCHEDULER_shutdown();
634 FPRINTF (stdout, "%s tunnel: %c, paths: %u\n",
635 GNUNET_i2s_full (peer), tunnel ? 'Y' : 'N', n_paths);
639 * Method called to retrieve information about a specific peer
640 * known to the service.
642 * @param cls Closure.
643 * @param peer Peer ID.
644 * @param tunnel Do we have a tunnel towards this peer? #GNUNET_YES/#GNUNET_NO
645 * @param neighbor Is this a direct neighbor? #GNUNET_YES/#GNUNET_NO
646 * @param n_paths Number of paths known towards peer.
647 * @param paths Array of PEER_IDs representing all paths to reach the peer.
648 * Each path starts with the local peer.
649 * Each path ends with the destination peer (given in @c peer).
652 peer_callback (void *cls,
653 const struct GNUNET_PeerIdentity *peer,
656 unsigned int n_paths,
657 struct GNUNET_PeerIdentity *paths)
660 struct GNUNET_PeerIdentity *p;
662 FPRINTF (stdout, "%s [TUNNEL: %s, NEIGHBOR: %s, PATHS: %u]\n",
663 GNUNET_i2s_full (peer),
664 tunnel ? "Y" : "N", neighbor ? "Y" : "N", n_paths);
666 for (i = 0; i < n_paths && NULL != p;)
668 FPRINTF (stdout, "%s ", GNUNET_i2s (p));
669 if (0 == memcmp (p, peer, sizeof (*p)))
671 FPRINTF (stdout, "\n");
677 GNUNET_SCHEDULER_shutdown();
682 * Method called to retrieve information about all tunnels in CADET.
684 * @param cls Closure.
685 * @param peer Destination peer.
686 * @param channels Number of channels.
687 * @param connections Number of connections.
688 * @param estate Encryption state.
689 * @param cstate Connectivity state.
692 tunnels_callback (void *cls,
693 const struct GNUNET_PeerIdentity *peer,
694 unsigned int channels,
695 unsigned int connections,
701 if (GNUNET_YES != monitor_mode)
703 GNUNET_SCHEDULER_shutdown();
707 FPRINTF (stdout, "%s [ENC: %s, CON: %s] CHs: %u, CONNs: %u\n",
708 GNUNET_i2s_full (peer),
709 enc_2s (estate), conn_2s (cstate),
710 channels, connections);
715 * Method called to retrieve information about a specific tunnel the cadet peer
716 * has established, o`r is trying to establish.
718 * @param cls Closure.
719 * @param peer Peer towards whom the tunnel is directed.
720 * @param n_channels Number of channels.
721 * @param n_connections Number of connections.
722 * @param channels Channels.
723 * @param connections Connections.
724 * @param estate Encryption status.
725 * @param cstate Connectivity status.
728 tunnel_callback (void *cls,
729 const struct GNUNET_PeerIdentity *peer,
730 unsigned int n_channels,
731 unsigned int n_connections,
732 const struct GNUNET_CADET_ChannelTunnelNumber *channels,
733 const struct GNUNET_CADET_ConnectionTunnelIdentifier *connections,
741 FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer));
742 FPRINTF (stdout, "\t%u channels\n", n_channels);
743 for (i = 0; i < n_channels; i++)
744 FPRINTF (stdout, "\t\t%X\n", ntohl (channels[i].cn));
745 FPRINTF (stdout, "\t%u connections\n", n_connections);
746 for (i = 0; i < n_connections; i++)
747 FPRINTF (stdout, "\t\t%s\n", GNUNET_sh2s (&connections[i].connection_of_tunnel));
748 FPRINTF (stdout, "\tencryption state: %s\n", enc_2s (estate));
749 FPRINTF (stdout, "\tconnection state: %s\n", conn_2s (cstate));
751 if (GNUNET_YES != monitor_mode)
753 GNUNET_SCHEDULER_shutdown ();
760 * Call CADET's meta API, get all peers known to a peer.
762 * @param cls Closure (unused).
765 get_peers (void *cls)
768 GNUNET_CADET_get_peers (mh, &peers_callback, NULL);
773 * Call CADET's monitor API, get info of one peer.
775 * @param cls Closure (unused).
778 show_peer (void *cls)
780 struct GNUNET_PeerIdentity pid;
784 GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
789 _("Invalid peer ID `%s'\n"),
791 GNUNET_SCHEDULER_shutdown();
794 GNUNET_CADET_get_peer (mh, &pid, peer_callback, NULL);
799 * Call CADET's meta API, get all tunnels known to a peer.
801 * @param cls Closure (unused).
804 get_tunnels (void *cls)
807 GNUNET_CADET_get_tunnels (mh, &tunnels_callback, NULL);
812 * Call CADET's monitor API, get info of one tunnel.
814 * @param cls Closure (unused).
817 show_tunnel (void *cls)
819 struct GNUNET_PeerIdentity pid;
822 GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
827 _("Invalid tunnel owner `%s'\n"),
829 GNUNET_SCHEDULER_shutdown ();
832 GNUNET_CADET_get_tunnel (mh,
840 * Call CADET's monitor API, get info of one channel.
842 * @param cls Closure (unused).
845 show_channel (void *cls)
853 * Call CADET's monitor API, get info of one connection.
855 * @param cls Closure (unused).
858 show_connection (void *cls)
866 * Main function that will be run by the scheduler.
869 * @param args remaining command-line arguments
870 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
871 * @param cfg configuration
877 const struct GNUNET_CONFIGURATION_Handle *cfg)
879 static const struct GNUNET_CADET_MessageHandler handlers[] = {
880 {&data_callback, GNUNET_MESSAGE_TYPE_CADET_CLI, 0},
881 {NULL, 0, 0} /* FIXME add option to monitor msg types */
884 /* FIXME add option to monitor apps */
887 if (target_id && args[1]) target_port = args[1];
889 if ( (0 != (request_peers | request_tunnels)
893 || NULL != channel_id)
894 && target_id != NULL)
897 _("You must NOT give a TARGET "
898 "when using 'request all' options\n"));
902 if (GNUNET_YES == dump)
904 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
905 "requesting debug dump\n");
906 GNUNET_SCHEDULER_add_now (&request_dump, NULL);
908 else if (NULL != target_id)
910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
911 "Creating channel to %s\n",
913 GNUNET_SCHEDULER_add_now (&create_channel, NULL);
915 else if (NULL != peer_id)
917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show peer\n");
918 job = GNUNET_SCHEDULER_add_now (&show_peer, NULL);
920 else if (NULL != tunnel_id)
922 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n");
923 job = GNUNET_SCHEDULER_add_now (&show_tunnel, NULL);
925 else if (NULL != channel_id)
927 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n");
928 job = GNUNET_SCHEDULER_add_now (&show_channel, NULL);
930 else if (NULL != conn_id)
932 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
933 job = GNUNET_SCHEDULER_add_now (&show_connection, NULL);
935 else if (GNUNET_YES == request_peers)
937 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n");
938 job = GNUNET_SCHEDULER_add_now (&get_peers, NULL);
940 else if (GNUNET_YES == request_tunnels)
942 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
943 job = GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
945 else if (NULL == listen_port)
947 FPRINTF (stderr, "No action requested\n");
951 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CADET service\n");
952 mh = GNUNET_CADET_connect (cfg,
954 &channel_ended, /* cleaner */
957 GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
959 sd = GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
961 if (NULL != listen_port)
963 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Opening CADET listen port\n");
964 GNUNET_CRYPTO_hash (listen_port, strlen(listen_port), &porthash);
965 lp = GNUNET_CADET_open_port (mh, &porthash, &channel_incoming, NULL);
971 * The main function to obtain peer information.
973 * @param argc number of arguments from the command line
974 * @param argv command line arguments
975 * @return 0 ok, 1 on error
978 main (int argc, char *const *argv)
981 const char helpstr[] = "Create channels and retreive info about cadets status.";
982 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
983 // {'a', "channel", "TUNNEL_ID:CHANNEL_ID",
984 // gettext_noop ("provide information about a particular channel"),
985 // GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id},
986 {'C', "connection", "CONNECTION_ID",
987 gettext_noop ("provide information about a particular connection"),
988 GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id},
990 gettext_noop ("activate echo mode"),
991 GNUNET_NO, &GNUNET_GETOPT_set_one, &echo},
993 gettext_noop ("dump debug information to STDERR"),
994 GNUNET_NO, &GNUNET_GETOPT_set_one, &dump},
995 // {'m', "monitor", NULL,
996 // gettext_noop ("provide information about all events (continuously)"),
997 // GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_mode},
998 {'o', "open-port", NULL,
999 gettext_noop ("port to listen to"),
1000 GNUNET_YES, &GNUNET_GETOPT_set_string, &listen_port},
1001 {'p', "peer", "PEER_ID",
1002 gettext_noop ("provide information about a patricular peer"),
1003 GNUNET_YES, &GNUNET_GETOPT_set_string, &peer_id},
1004 {'P', "peers", NULL,
1005 gettext_noop ("provide information about all peers"),
1006 GNUNET_NO, &GNUNET_GETOPT_set_one, &request_peers},
1007 {'t', "tunnel", "TUNNEL_ID",
1008 gettext_noop ("provide information about a particular tunnel"),
1009 GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id},
1010 {'T', "tunnels", NULL,
1011 gettext_noop ("provide information about all tunnels"),
1012 GNUNET_NO, &GNUNET_GETOPT_set_one, &request_tunnels},
1014 GNUNET_GETOPT_OPTION_END
1017 monitor_mode = GNUNET_NO;
1019 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1022 res = GNUNET_PROGRAM_run (argc, argv, "gnunet-cadet (OPTIONS | TARGET PORT)",
1023 gettext_noop (helpstr),
1024 options, &run, NULL);
1026 GNUNET_free ((void *) argv);
1028 if (GNUNET_OK == res)
1034 /* end of gnunet-cadet.c */