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 mesh/gnunet-mesh.c
23 * @brief Print information about mesh tunnels and peers.
24 * @author Bartlomiej Polot
27 #include "gnunet_util_lib.h"
28 #include "gnunet_mesh_service.h"
35 static int monitor_connections;
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 * Time of last echo request.
80 struct GNUNET_TIME_Absolute echo_time;
83 * Task for next echo request.
85 GNUNET_SCHEDULER_TaskIdentifier echo_task;
90 static char *target_id;
95 static uint32_t target_port;
98 * Data pending in netcat mode.
106 static struct GNUNET_MESH_Handle *mh;
111 static struct GNUNET_MESH_Channel *ch;
114 * Shutdown task handle.
116 GNUNET_SCHEDULER_TaskIdentifier sd;
126 * Task run in monitor mode when the user presses CTRL-C to abort.
127 * Stops monitoring activity.
129 * @param cls Closure (unused).
130 * @param tc scheduler context
133 shutdown_task (void *cls,
134 const struct GNUNET_SCHEDULER_TaskContext *tc)
136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
139 GNUNET_MESH_channel_destroy (ch);
144 GNUNET_MESH_disconnect (mh);
151 * Function called to notify a client about the connection
152 * begin ready to queue more data. "buf" will be
153 * NULL and "size" zero if the connection was closed for
154 * writing in the meantime.
159 * @param size number of bytes available in buf
160 * @param buf where the callee should write the message
161 * @return number of bytes written to buf
164 data_ready (void *cls, size_t size, void *buf)
166 struct GNUNET_MessageHeader *msg;
169 if (NULL == buf || 0 == size)
171 GNUNET_SCHEDULER_shutdown();
175 total_size = data_size + sizeof (struct GNUNET_MessageHeader);
176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending %u bytes\n", data_size);
177 GNUNET_assert (size >= total_size);
180 msg->size = htons (total_size);
181 msg->type = htons (GNUNET_MESSAGE_TYPE_MESH_CLI);
182 memcpy (&msg[1], cls, data_size);
183 if (GNUNET_NO == echo)
189 echo_time = GNUNET_TIME_absolute_get ();
197 * Task run in monitor mode when the user presses CTRL-C to abort.
198 * Stops monitoring activity.
200 * @param cls Closure (unused).
201 * @param tc scheduler context
204 read_stdio (void *cls,
205 const struct GNUNET_SCHEDULER_TaskContext *tc)
207 static char buf[60000];
209 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
214 data_size = read (0, buf, 60000);
215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stdio read %u bytes\n", data_size);
218 GNUNET_SCHEDULER_shutdown();
221 GNUNET_MESH_notify_transmit_ready (ch, GNUNET_NO,
222 GNUNET_TIME_UNIT_FOREVER_REL,
224 + sizeof (struct GNUNET_MessageHeader),
230 * Start listening to stdin
235 struct GNUNET_NETWORK_FDSet *rs;
237 rs = GNUNET_NETWORK_fdset_create ();
238 GNUNET_NETWORK_fdset_set_native (rs, 0);
239 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
240 GNUNET_TIME_UNIT_FOREVER_REL,
243 GNUNET_NETWORK_fdset_destroy (rs);
248 * Function called whenever a channel is destroyed. Should clean up
249 * any associated state.
251 * It must NOT call #GNUNET_MESH_channel_destroy on the channel.
253 * @param cls closure (set from #GNUNET_MESH_connect)
254 * @param channel connection to the other end (henceforth invalid)
255 * @param channel_ctx place where local state associated
256 * with the channel is stored
259 channel_ended (void *cls,
260 const struct GNUNET_MESH_Channel *channel,
263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n");
264 GNUNET_break (channel == ch);
266 GNUNET_SCHEDULER_shutdown ();
271 * Method called whenever another peer has added us to a channel
272 * the other peer initiated.
273 * Only called (once) upon reception of data with a message type which was
274 * subscribed to in #GNUNET_MESH_connect.
276 * A call to #GNUNET_MESH_channel_destroy causes te channel to be ignored. In
277 * this case the handler MUST return NULL.
280 * @param channel new handle to the channel
281 * @param initiator peer that started the channel
282 * @param port Port this channel is for.
283 * @param options MeshOption flag field, with all active option bits set to 1.
285 * @return initial channel context for the channel
286 * (can be NULL -- that's not an error)
289 channel_incoming (void *cls,
290 struct GNUNET_MESH_Channel * channel,
291 const struct GNUNET_PeerIdentity * initiator,
292 uint32_t port, enum GNUNET_MESH_ChannelOption options)
294 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
295 "Incoming channel %p on port %u\n",
299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "A channel already exists\n");
302 if (0 == listen_port)
304 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not listening to channels\n");
308 if (GNUNET_NO == echo)
318 * @brief Send an echo request to the remote peer.
320 * @param cls Closure (NULL).
321 * @param tc Task context.
324 send_echo (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
326 GNUNET_MESH_notify_transmit_ready (ch, GNUNET_NO,
327 GNUNET_TIME_UNIT_FOREVER_REL,
328 sizeof (struct GNUNET_MessageHeader),
335 * Call MESH's monitor API, get info of one connection.
337 * @param cls Closure (unused).
338 * @param tc TaskContext
341 create_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
343 struct GNUNET_PeerIdentity pid;
344 enum GNUNET_MESH_ChannelOption opt;
346 GNUNET_assert (NULL == ch);
349 GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
354 _("Invalid target `%s'\n"),
356 GNUNET_SCHEDULER_shutdown ();
359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id);
360 opt = GNUNET_MESH_OPTION_DEFAULT | GNUNET_MESH_OPTION_RELIABLE;
361 ch = GNUNET_MESH_channel_create (mh, NULL, &pid, target_port, opt);
362 if (GNUNET_NO == echo)
365 GNUNET_SCHEDULER_add_now (send_echo, NULL);
370 * Function called whenever a message is received.
372 * Each time the function must call #GNUNET_MESH_receive_done on the channel
373 * in order to receive the next message. This doesn't need to be immediate:
374 * can be delayed if some processing is done on the message.
376 * @param cls Closure (set from #GNUNET_MESH_connect).
377 * @param channel Connection to the other end.
378 * @param channel_ctx Place to store local state associated with the channel.
379 * @param message The actual message.
380 * @return #GNUNET_OK to keep the channel open,
381 * #GNUNET_SYSERR to close it (signal serious error).
384 data_callback (void *cls,
385 struct GNUNET_MESH_Channel *channel,
387 const struct GNUNET_MessageHeader *message)
393 GNUNET_break (ch == channel);
395 if (GNUNET_YES == echo)
397 if (0 != listen_port)
399 /* Just listening to echo incoming messages*/
400 GNUNET_MESH_notify_transmit_ready (channel, GNUNET_NO,
401 GNUNET_TIME_UNIT_FOREVER_REL,
402 sizeof (struct GNUNET_MessageHeader),
408 struct GNUNET_TIME_Relative latency;
410 latency = GNUNET_TIME_absolute_get_duration (echo_time);
411 echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
412 FPRINTF (stdout, "time: %s\n",
413 GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
414 echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
419 len = ntohs (message->size) - sizeof (*message);
420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len);
421 buf = (const char *) &message[1];
425 done = write (1, &buf[off], len - off);
429 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
431 return GNUNET_SYSERR;
440 * Method called to retrieve information about all peers in MESH, called
443 * After last peer has been reported, an additional call with NULL is done.
445 * @param cls Closure.
446 * @param peer Peer, or NULL on "EOF".
447 * @param tunnel Do we have a tunnel towards this peer?
448 * @param n_paths Number of known paths towards this peer.
449 * @param best_path How long is the best path?
450 * (0 = unknown, 1 = ourselves, 2 = neighbor)
453 peers_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
454 int tunnel, unsigned int n_paths, unsigned int best_path)
458 if (GNUNET_YES != monitor_connections)
460 GNUNET_SCHEDULER_shutdown();
464 FPRINTF (stdout, "%s tunnel: %c, paths: %u\n",
465 GNUNET_i2s_full (peer), tunnel ? 'Y' : 'N', n_paths);
469 * Method called to retrieve information about a specific peer
470 * known to the service.
472 * @param cls Closure.
473 * @param peer Peer ID.
474 * @param tunnel Do we have a tunnel towards this peer? #GNUNET_YES/#GNUNET_NO
475 * @param neighbor Is this a direct neighbor? #GNUNET_YES/#GNUNET_NO
476 * @param n_paths Number of paths known towards peer.
477 * @param paths Array of PEER_IDs representing all paths to reach the peer.
478 * Each path starts with the local peer.
479 * Each path ends with the destination peer (given in @c peer).
482 peer_callback (void *cls,
483 const struct GNUNET_PeerIdentity *peer,
486 unsigned int n_paths,
487 struct GNUNET_PeerIdentity *paths)
493 * Method called to retrieve information about all tunnels in MESH.
495 * @param cls Closure.
496 * @param peer Destination peer.
497 * @param channels Number of channels.
498 * @param connections Number of connections.
499 * @param estate Encryption state.
500 * @param cstate Connectivity state.
503 tunnels_callback (void *cls,
504 const struct GNUNET_PeerIdentity *peer,
505 unsigned int channels,
506 unsigned int connections,
512 if (GNUNET_YES != monitor_connections)
514 GNUNET_SCHEDULER_shutdown();
518 FPRINTF (stdout, "%s [ENC: %u, CON: %u] CHs: %u, CONNs: %u\n",
519 GNUNET_i2s_full (peer), estate, cstate, channels, connections);
524 * Method called to retrieve information about a specific tunnel the mesh peer
525 * has established, o`r is trying to establish.
527 * @param cls Closure.
528 * @param peer Peer towards whom the tunnel is directed.
529 * @param n_channels Number of channels.
530 * @param n_connections Number of connections.
531 * @param channels Channels.
532 * @param connections Connections.
533 * @param estate Encryption status.
534 * @param cstate Connectivity status.
537 tunnel_callback (void *cls,
538 const struct GNUNET_PeerIdentity *peer,
539 unsigned int n_channels,
540 unsigned int n_connections,
542 struct GNUNET_MeshHash *connections,
550 FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer));
551 FPRINTF (stdout, "- %u channels\n", n_channels);
552 for (i = 0; i < n_channels; i++)
553 FPRINTF (stdout, " %u\n", channels[i]);
554 FPRINTF (stdout, "- %u connections\n", n_connections);
555 for (i = 0; i < n_connections; i++)
556 FPRINTF (stdout, " %s\n", GM_h2s (&connections[i]));
557 FPRINTF (stdout, "- enc state: %u\n", estate);
558 FPRINTF (stdout, "- con state: %u\n", cstate);
560 if (GNUNET_YES != monitor_connections)
562 GNUNET_SCHEDULER_shutdown();
570 * Call MESH's meta API, get all peers known to a peer.
572 * @param cls Closure (unused).
573 * @param tc TaskContext
576 get_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
578 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
583 GNUNET_MESH_get_peers (mh, &peers_callback, NULL);
588 * Call MESH's monitor API, get info of one peer.
590 * @param cls Closure (unused).
591 * @param tc TaskContext
594 show_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
596 struct GNUNET_PeerIdentity pid;
599 GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
604 _("Invalid peer ID `%s'\n"),
606 GNUNET_SCHEDULER_shutdown();
609 GNUNET_MESH_get_peer (mh, &pid, peer_callback, NULL);
613 * Call MESH's meta API, get all tunnels known to a peer.
615 * @param cls Closure (unused).
616 * @param tc TaskContext
619 get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
621 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
626 GNUNET_MESH_get_tunnels (mh, &tunnels_callback, NULL);
631 * Call MESH's monitor API, get info of one tunnel.
633 * @param cls Closure (unused).
634 * @param tc TaskContext
637 show_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
639 struct GNUNET_PeerIdentity pid;
642 GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
647 _("Invalid tunnel owner `%s'\n"),
649 GNUNET_SCHEDULER_shutdown();
652 GNUNET_MESH_get_tunnel (mh, &pid, tunnel_callback, NULL);
657 * Call MESH's monitor API, get info of one channel.
659 * @param cls Closure (unused).
660 * @param tc TaskContext
663 show_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
670 * Call MESH's monitor API, get info of one connection.
672 * @param cls Closure (unused).
673 * @param tc TaskContext
676 show_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
683 * Main function that will be run by the scheduler.
686 * @param args remaining command-line arguments
687 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
688 * @param cfg configuration
691 run (void *cls, char *const *args, const char *cfgfile,
692 const struct GNUNET_CONFIGURATION_Handle *cfg)
694 GNUNET_MESH_InboundChannelNotificationHandler *newch = NULL;
695 GNUNET_MESH_ChannelEndHandler *endch = NULL;
696 static const struct GNUNET_MESH_MessageHandler handlers[] = {
697 {&data_callback, GNUNET_MESSAGE_TYPE_MESH_CLI, 0},
698 {NULL, 0, 0} /* FIXME add option to monitor msg types */
700 static uint32_t *ports = NULL;
701 /* FIXME add option to monitor apps */
704 target_port = args[0] && args[1] ? atoi(args[1]) : 0;
705 if ( (0 != (request_peers | request_tunnels)
706 || 0 != monitor_connections
709 || NULL != channel_id)
710 && target_id != NULL)
713 _("You must NOT give a TARGET"
714 "when using 'request all' options\n"));
718 if (NULL != target_id)
720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
721 "Creating channel to %s\n",
723 GNUNET_SCHEDULER_add_now (&create_channel, NULL);
724 endch = &channel_ended;
726 else if (0 != listen_port)
728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Listen\n");
729 newch = &channel_incoming;
730 endch = &channel_ended;
731 ports = GNUNET_malloc (sizeof (uint32_t) * 2);
732 ports[0] = listen_port;
734 else if (NULL != peer_id)
736 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show peer\n");
737 GNUNET_SCHEDULER_add_now (&show_peer, NULL);
739 else if (NULL != tunnel_id)
741 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n");
742 GNUNET_SCHEDULER_add_now (&show_tunnel, NULL);
744 else if (NULL != channel_id)
746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n");
747 GNUNET_SCHEDULER_add_now (&show_channel, NULL);
749 else if (NULL != conn_id)
751 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
752 GNUNET_SCHEDULER_add_now (&show_connection, NULL);
754 else if (GNUNET_YES == request_peers)
756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n");
757 GNUNET_SCHEDULER_add_now (&get_peers, NULL);
759 else if (GNUNET_YES == request_tunnels)
761 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
762 GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
766 FPRINTF (stderr, "No action requested\n");
770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to mesh\n");
771 mh = GNUNET_MESH_connect (cfg,
773 newch, /* new channel */
777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done\n");
779 GNUNET_SCHEDULER_add_now (shutdown_task, NULL);
781 sd = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
782 shutdown_task, NULL);
788 * The main function to obtain peer information.
790 * @param argc number of arguments from the command line
791 * @param argv command line arguments
792 * @return 0 ok, 1 on error
795 main (int argc, char *const *argv)
798 const char helpstr[] = "Create channels and retreive info about meshs status.";
799 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
800 // {'a', "channel", "TUNNEL_ID:CHANNEL_ID",
801 // gettext_noop ("provide information about a particular channel"),
802 // GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id},
803 {'C', "connection", "CONNECTION_ID",
804 gettext_noop ("provide information about a particular connection"),
805 GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id},
807 gettext_noop ("activate echo mode"),
808 GNUNET_NO, &GNUNET_GETOPT_set_one, &echo},
809 // {'m', "monitor", NULL,
810 // gettext_noop ("provide information about all tunnels (continuously) NOT IMPLEMENTED"), /* FIXME */
811 // GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_connections},
812 {'o', "open-port", NULL,
813 gettext_noop ("port to listen to (default; 0)"),
814 GNUNET_YES, &GNUNET_GETOPT_set_uint, &listen_port},
815 {'p', "peer", "PEER_ID",
816 gettext_noop ("provide information about all peers"),
817 GNUNET_NO, &GNUNET_GETOPT_set_string, &peer_id},
819 gettext_noop ("provide information about all peers"),
820 GNUNET_NO, &GNUNET_GETOPT_set_one, &request_peers},
821 {'t', "tunnel", "TUNNEL_ID",
822 gettext_noop ("provide information about a particular tunnel"),
823 GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id},
824 {'T', "tunnels", NULL,
825 gettext_noop ("provide information about all tunnels"),
826 GNUNET_NO, &GNUNET_GETOPT_set_one, &request_tunnels},
828 GNUNET_GETOPT_OPTION_END
831 monitor_connections = GNUNET_NO;
833 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
836 res = GNUNET_PROGRAM_run (argc, argv, "gnunet-mesh (OPTIONS | TARGET PORT)",
837 gettext_noop (helpstr),
838 options, &run, NULL);
840 GNUNET_free ((void *) argv);
842 if (GNUNET_OK == res)
848 /* end of gnunet-mesh.c */