2 This file is part of GNUnet.
3 (C) 2012 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, 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 struct GNUNET_TIME_Absolute echo_time;
88 * Task for next echo request.
90 GNUNET_SCHEDULER_TaskIdentifier echo_task;
95 static char *target_id;
100 static uint32_t target_port;
103 * Data pending in netcat mode.
111 static struct GNUNET_CADET_Handle *mh;
116 static struct GNUNET_CADET_Channel *ch;
119 * Shutdown task handle.
121 GNUNET_SCHEDULER_TaskIdentifier sd;
131 * Task run in monitor mode when the user presses CTRL-C to abort.
132 * Stops monitoring activity.
134 * @param cls Closure (unused).
135 * @param tc scheduler context
138 shutdown_task (void *cls,
139 const struct GNUNET_SCHEDULER_TaskContext *tc)
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
144 GNUNET_CADET_channel_destroy (ch);
149 GNUNET_CADET_disconnect (mh);
156 * Function called to notify a client about the connection
157 * begin ready to queue more data. "buf" will be
158 * NULL and "size" zero if the connection was closed for
159 * writing in the meantime.
164 * @param size number of bytes available in buf
165 * @param buf where the callee should write the message
166 * @return number of bytes written to buf
169 data_ready (void *cls, size_t size, void *buf)
171 struct GNUNET_MessageHeader *msg;
174 if (NULL == buf || 0 == size)
176 GNUNET_SCHEDULER_shutdown();
180 total_size = data_size + sizeof (struct GNUNET_MessageHeader);
181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending %u bytes\n", data_size);
182 GNUNET_assert (size >= total_size);
185 msg->size = htons (total_size);
186 msg->type = htons (GNUNET_MESSAGE_TYPE_CADET_CLI);
187 memcpy (&msg[1], cls, data_size);
188 if (GNUNET_NO == echo)
194 echo_time = GNUNET_TIME_absolute_get ();
202 * Task run in monitor mode when the user presses CTRL-C to abort.
203 * Stops monitoring activity.
205 * @param cls Closure (unused).
206 * @param tc scheduler context
209 read_stdio (void *cls,
210 const struct GNUNET_SCHEDULER_TaskContext *tc)
212 static char buf[60000];
214 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
219 data_size = read (0, buf, 60000);
220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stdio read %u bytes\n", data_size);
223 GNUNET_SCHEDULER_shutdown();
226 GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
227 GNUNET_TIME_UNIT_FOREVER_REL,
229 + sizeof (struct GNUNET_MessageHeader),
235 * Start listening to stdin
240 struct GNUNET_NETWORK_FDSet *rs;
242 rs = GNUNET_NETWORK_fdset_create ();
243 GNUNET_NETWORK_fdset_set_native (rs, 0);
244 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
245 GNUNET_TIME_UNIT_FOREVER_REL,
248 GNUNET_NETWORK_fdset_destroy (rs);
253 * Function called whenever a channel is destroyed. Should clean up
254 * any associated state.
256 * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
258 * @param cls closure (set from #GNUNET_CADET_connect)
259 * @param channel connection to the other end (henceforth invalid)
260 * @param channel_ctx place where local state associated
261 * with the channel is stored
264 channel_ended (void *cls,
265 const struct GNUNET_CADET_Channel *channel,
268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n");
269 GNUNET_break (channel == ch);
271 GNUNET_SCHEDULER_shutdown ();
276 * Method called whenever another peer has added us to a channel
277 * the other peer initiated.
278 * Only called (once) upon reception of data with a message type which was
279 * subscribed to in #GNUNET_CADET_connect.
281 * A call to #GNUNET_CADET_channel_destroy causes te channel to be ignored. In
282 * this case the handler MUST return NULL.
285 * @param channel new handle to the channel
286 * @param initiator peer that started the channel
287 * @param port Port this channel is for.
288 * @param options CadetOption flag field, with all active option bits set to 1.
290 * @return initial channel context for the channel
291 * (can be NULL -- that's not an error)
294 channel_incoming (void *cls,
295 struct GNUNET_CADET_Channel * channel,
296 const struct GNUNET_PeerIdentity * initiator,
297 uint32_t port, enum GNUNET_CADET_ChannelOption options)
299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
300 "Incoming channel %p on port %u\n",
304 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "A channel already exists\n");
307 if (0 == listen_port)
309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not listening to channels\n");
313 if (GNUNET_NO == echo)
323 * @brief Send an echo request to the remote peer.
325 * @param cls Closure (NULL).
326 * @param tc Task context.
329 send_echo (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
331 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) || NULL == ch)
334 GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
335 GNUNET_TIME_UNIT_FOREVER_REL,
336 sizeof (struct GNUNET_MessageHeader),
342 * Call CADET's monitor API, request debug dump on the service.
344 * @param cls Closure (unused).
345 * @param tc TaskContext
348 request_dump (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
350 GNUNET_CADET_request_dump (mh);
351 GNUNET_SCHEDULER_cancel (sd);
352 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &shutdown_task, NULL);
357 * Call CADET's monitor API, get info of one connection.
359 * @param cls Closure (unused).
360 * @param tc TaskContext
363 create_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
365 struct GNUNET_PeerIdentity pid;
366 enum GNUNET_CADET_ChannelOption opt;
368 GNUNET_assert (NULL == ch);
371 GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
376 _("Invalid target `%s'\n"),
378 GNUNET_SCHEDULER_shutdown ();
381 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id);
382 opt = GNUNET_CADET_OPTION_DEFAULT | GNUNET_CADET_OPTION_RELIABLE;
383 ch = GNUNET_CADET_channel_create (mh, NULL, &pid, target_port, opt);
384 if (GNUNET_NO == echo)
387 GNUNET_SCHEDULER_add_now (send_echo, NULL);
392 * Function called whenever a message is received.
394 * Each time the function must call #GNUNET_CADET_receive_done on the channel
395 * in order to receive the next message. This doesn't need to be immediate:
396 * can be delayed if some processing is done on the message.
398 * @param cls Closure (set from #GNUNET_CADET_connect).
399 * @param channel Connection to the other end.
400 * @param channel_ctx Place to store local state associated with the channel.
401 * @param message The actual message.
402 * @return #GNUNET_OK to keep the channel open,
403 * #GNUNET_SYSERR to close it (signal serious error).
406 data_callback (void *cls,
407 struct GNUNET_CADET_Channel *channel,
409 const struct GNUNET_MessageHeader *message)
415 GNUNET_break (ch == channel);
417 if (GNUNET_YES == echo)
419 if (0 != listen_port)
421 /* Just listening to echo incoming messages*/
422 GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
423 GNUNET_TIME_UNIT_FOREVER_REL,
424 sizeof (struct GNUNET_MessageHeader),
430 struct GNUNET_TIME_Relative latency;
432 latency = GNUNET_TIME_absolute_get_duration (echo_time);
433 echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
434 FPRINTF (stdout, "time: %s\n",
435 GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
436 echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
441 len = ntohs (message->size) - sizeof (*message);
442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len);
443 buf = (const char *) &message[1];
447 done = write (1, &buf[off], len - off);
451 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
453 return GNUNET_SYSERR;
462 * Method called to retrieve information about all peers in CADET, called
465 * After last peer has been reported, an additional call with NULL is done.
467 * @param cls Closure.
468 * @param peer Peer, or NULL on "EOF".
469 * @param tunnel Do we have a tunnel towards this peer?
470 * @param n_paths Number of known paths towards this peer.
471 * @param best_path How long is the best path?
472 * (0 = unknown, 1 = ourselves, 2 = neighbor)
475 peers_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
476 int tunnel, unsigned int n_paths, unsigned int best_path)
480 if (GNUNET_YES != monitor_mode)
482 GNUNET_SCHEDULER_shutdown();
486 FPRINTF (stdout, "%s tunnel: %c, paths: %u\n",
487 GNUNET_i2s_full (peer), tunnel ? 'Y' : 'N', n_paths);
491 * Method called to retrieve information about a specific peer
492 * known to the service.
494 * @param cls Closure.
495 * @param peer Peer ID.
496 * @param tunnel Do we have a tunnel towards this peer? #GNUNET_YES/#GNUNET_NO
497 * @param neighbor Is this a direct neighbor? #GNUNET_YES/#GNUNET_NO
498 * @param n_paths Number of paths known towards peer.
499 * @param paths Array of PEER_IDs representing all paths to reach the peer.
500 * Each path starts with the local peer.
501 * Each path ends with the destination peer (given in @c peer).
504 peer_callback (void *cls,
505 const struct GNUNET_PeerIdentity *peer,
508 unsigned int n_paths,
509 struct GNUNET_PeerIdentity *paths)
515 * Method called to retrieve information about all tunnels in CADET.
517 * @param cls Closure.
518 * @param peer Destination peer.
519 * @param channels Number of channels.
520 * @param connections Number of connections.
521 * @param estate Encryption state.
522 * @param cstate Connectivity state.
525 tunnels_callback (void *cls,
526 const struct GNUNET_PeerIdentity *peer,
527 unsigned int channels,
528 unsigned int connections,
534 if (GNUNET_YES != monitor_mode)
536 GNUNET_SCHEDULER_shutdown();
540 FPRINTF (stdout, "%s [ENC: %u, CON: %u] CHs: %u, CONNs: %u\n",
541 GNUNET_i2s_full (peer), estate, cstate, channels, connections);
546 * Method called to retrieve information about a specific tunnel the cadet peer
547 * has established, o`r is trying to establish.
549 * @param cls Closure.
550 * @param peer Peer towards whom the tunnel is directed.
551 * @param n_channels Number of channels.
552 * @param n_connections Number of connections.
553 * @param channels Channels.
554 * @param connections Connections.
555 * @param estate Encryption status.
556 * @param cstate Connectivity status.
559 tunnel_callback (void *cls,
560 const struct GNUNET_PeerIdentity *peer,
561 unsigned int n_channels,
562 unsigned int n_connections,
564 struct GNUNET_CADET_Hash *connections,
572 FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer));
573 FPRINTF (stdout, "- %u channels\n", n_channels);
574 for (i = 0; i < n_channels; i++)
575 FPRINTF (stdout, " %u\n", channels[i]);
576 FPRINTF (stdout, "- %u connections\n", n_connections);
577 for (i = 0; i < n_connections; i++)
578 FPRINTF (stdout, " %s\n", GC_h2s (&connections[i]));
579 FPRINTF (stdout, "- enc state: %u\n", estate);
580 FPRINTF (stdout, "- con state: %u\n", cstate);
582 if (GNUNET_YES != monitor_mode)
584 GNUNET_SCHEDULER_shutdown();
592 * Call CADET's meta API, get all peers known to a peer.
594 * @param cls Closure (unused).
595 * @param tc TaskContext
598 get_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
600 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
602 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
605 GNUNET_CADET_get_peers (mh, &peers_callback, NULL);
610 * Call CADET's monitor API, get info of one peer.
612 * @param cls Closure (unused).
613 * @param tc TaskContext
616 show_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
618 struct GNUNET_PeerIdentity pid;
621 GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
626 _("Invalid peer ID `%s'\n"),
628 GNUNET_SCHEDULER_shutdown();
631 GNUNET_CADET_get_peer (mh, &pid, peer_callback, NULL);
635 * Call CADET's meta API, get all tunnels known to a peer.
637 * @param cls Closure (unused).
638 * @param tc TaskContext
641 get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
643 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
645 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
648 GNUNET_CADET_get_tunnels (mh, &tunnels_callback, NULL);
653 * Call CADET's monitor API, get info of one tunnel.
655 * @param cls Closure (unused).
656 * @param tc TaskContext
659 show_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
661 struct GNUNET_PeerIdentity pid;
664 GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
669 _("Invalid tunnel owner `%s'\n"),
671 GNUNET_SCHEDULER_shutdown();
674 GNUNET_CADET_get_tunnel (mh, &pid, tunnel_callback, NULL);
679 * Call CADET's monitor API, get info of one channel.
681 * @param cls Closure (unused).
682 * @param tc TaskContext
685 show_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
692 * Call CADET's monitor API, get info of one connection.
694 * @param cls Closure (unused).
695 * @param tc TaskContext
698 show_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
705 * Main function that will be run by the scheduler.
708 * @param args remaining command-line arguments
709 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
710 * @param cfg configuration
713 run (void *cls, char *const *args, const char *cfgfile,
714 const struct GNUNET_CONFIGURATION_Handle *cfg)
716 GNUNET_CADET_InboundChannelNotificationHandler *newch = NULL;
717 GNUNET_CADET_ChannelEndHandler *endch = NULL;
718 static const struct GNUNET_CADET_MessageHandler handlers[] = {
719 {&data_callback, GNUNET_MESSAGE_TYPE_CADET_CLI, 0},
720 {NULL, 0, 0} /* FIXME add option to monitor msg types */
722 static uint32_t *ports = NULL;
723 /* FIXME add option to monitor apps */
726 target_port = args[0] && args[1] ? atoi(args[1]) : 0;
727 if ( (0 != (request_peers | request_tunnels)
731 || NULL != channel_id)
732 && target_id != NULL)
735 _("You must NOT give a TARGET"
736 "when using 'request all' options\n"));
740 if (GNUNET_YES == dump)
742 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
743 "requesting debug dump\n");
744 GNUNET_SCHEDULER_add_now (&request_dump, NULL);
746 else if (NULL != target_id)
748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
749 "Creating channel to %s\n",
751 GNUNET_SCHEDULER_add_now (&create_channel, NULL);
752 endch = &channel_ended;
754 else if (0 != listen_port)
756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Listen\n");
757 newch = &channel_incoming;
758 endch = &channel_ended;
759 ports = GNUNET_malloc (sizeof (uint32_t) * 2);
760 ports[0] = listen_port;
762 else if (NULL != peer_id)
764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show peer\n");
765 GNUNET_SCHEDULER_add_now (&show_peer, NULL);
767 else if (NULL != tunnel_id)
769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n");
770 GNUNET_SCHEDULER_add_now (&show_tunnel, NULL);
772 else if (NULL != channel_id)
774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n");
775 GNUNET_SCHEDULER_add_now (&show_channel, NULL);
777 else if (NULL != conn_id)
779 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
780 GNUNET_SCHEDULER_add_now (&show_connection, NULL);
782 else if (GNUNET_YES == request_peers)
784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n");
785 GNUNET_SCHEDULER_add_now (&get_peers, NULL);
787 else if (GNUNET_YES == request_tunnels)
789 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
790 GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
794 FPRINTF (stderr, "No action requested\n");
798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to cadet\n");
799 mh = GNUNET_CADET_connect (cfg,
801 newch, /* new channel */
805 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done\n");
807 GNUNET_SCHEDULER_add_now (shutdown_task, NULL);
809 sd = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
810 shutdown_task, NULL);
816 * The main function to obtain peer information.
818 * @param argc number of arguments from the command line
819 * @param argv command line arguments
820 * @return 0 ok, 1 on error
823 main (int argc, char *const *argv)
826 const char helpstr[] = "Create channels and retreive info about cadets status.";
827 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
828 // {'a', "channel", "TUNNEL_ID:CHANNEL_ID",
829 // gettext_noop ("provide information about a particular channel"),
830 // GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id},
831 {'C', "connection", "CONNECTION_ID",
832 gettext_noop ("provide information about a particular connection"),
833 GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id},
835 gettext_noop ("activate echo mode"),
836 GNUNET_NO, &GNUNET_GETOPT_set_one, &echo},
838 gettext_noop ("dump debug information to STDERR"),
839 GNUNET_NO, &GNUNET_GETOPT_set_one, &dump},
840 // {'m', "monitor", NULL,
841 // gettext_noop ("provide information about all events (continuously)"),
842 // GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_mode},
843 {'o', "open-port", NULL,
844 gettext_noop ("port to listen to (default; 0)"),
845 GNUNET_YES, &GNUNET_GETOPT_set_uint, &listen_port},
846 {'p', "peer", "PEER_ID",
847 gettext_noop ("provide information about a patricular peer"),
848 GNUNET_YES, &GNUNET_GETOPT_set_string, &peer_id},
850 gettext_noop ("provide information about all peers"),
851 GNUNET_NO, &GNUNET_GETOPT_set_one, &request_peers},
852 {'t', "tunnel", "TUNNEL_ID",
853 gettext_noop ("provide information about a particular tunnel"),
854 GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id},
855 {'T', "tunnels", NULL,
856 gettext_noop ("provide information about all tunnels"),
857 GNUNET_NO, &GNUNET_GETOPT_set_one, &request_tunnels},
859 GNUNET_GETOPT_OPTION_END
862 monitor_mode = GNUNET_NO;
864 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
867 res = GNUNET_PROGRAM_run (argc, argv, "gnunet-cadet (OPTIONS | TARGET PORT)",
868 gettext_noop (helpstr),
869 options, &run, NULL);
871 GNUNET_free ((void *) argv);
873 if (GNUNET_OK == res)
879 /* end of gnunet-cadet.c */