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"
34 static int monitor_connections;
44 static char *tunnel_id;
54 static char *channel_id;
57 * Port to listen on (-p).
59 static uint32_t listen_port;
62 * Request echo service
67 * Time of last echo request.
69 struct GNUNET_TIME_Absolute echo_time;
72 * Task for next echo request.
74 GNUNET_SCHEDULER_TaskIdentifier echo_task;
79 static char *target_id;
84 static uint32_t target_port;
87 * Data pending in netcat mode.
95 static struct GNUNET_MESH_Handle *mh;
100 static struct GNUNET_MESH_Channel *ch;
103 * Shutdown task handle.
105 GNUNET_SCHEDULER_TaskIdentifier sd;
115 * Task run in monitor mode when the user presses CTRL-C to abort.
116 * Stops monitoring activity.
118 * @param cls Closure (unused).
119 * @param tc scheduler context
122 shutdown_task (void *cls,
123 const struct GNUNET_SCHEDULER_TaskContext *tc)
125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
128 GNUNET_MESH_channel_destroy (ch);
133 GNUNET_MESH_disconnect (mh);
140 * Function called to notify a client about the connection
141 * begin ready to queue more data. "buf" will be
142 * NULL and "size" zero if the connection was closed for
143 * writing in the meantime.
148 * @param size number of bytes available in buf
149 * @param buf where the callee should write the message
150 * @return number of bytes written to buf
153 data_ready (void *cls, size_t size, void *buf)
155 struct GNUNET_MessageHeader *msg;
158 if (NULL == buf || 0 == size)
160 GNUNET_SCHEDULER_shutdown();
164 total_size = data_size + sizeof (struct GNUNET_MessageHeader);
165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending %u bytes\n", data_size);
166 GNUNET_assert (size >= total_size);
169 msg->size = htons (total_size);
170 msg->type = htons (GNUNET_MESSAGE_TYPE_MESH_CLI);
171 memcpy (&msg[1], cls, data_size);
172 if (GNUNET_NO == echo)
178 echo_time = GNUNET_TIME_absolute_get ();
186 * Task run in monitor mode when the user presses CTRL-C to abort.
187 * Stops monitoring activity.
189 * @param cls Closure (unused).
190 * @param tc scheduler context
193 read_stdio (void *cls,
194 const struct GNUNET_SCHEDULER_TaskContext *tc)
196 static char buf[60000];
198 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
203 data_size = read (0, buf, 60000);
204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stdio read %u bytes\n", data_size);
207 GNUNET_SCHEDULER_shutdown();
210 GNUNET_MESH_notify_transmit_ready (ch, GNUNET_NO,
211 GNUNET_TIME_UNIT_FOREVER_REL,
213 + sizeof (struct GNUNET_MessageHeader),
219 * Start listening to stdin
224 struct GNUNET_NETWORK_FDSet *rs;
226 rs = GNUNET_NETWORK_fdset_create ();
227 GNUNET_NETWORK_fdset_set_native (rs, 0);
228 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
229 GNUNET_TIME_UNIT_FOREVER_REL,
232 GNUNET_NETWORK_fdset_destroy (rs);
237 * Function called whenever a channel is destroyed. Should clean up
238 * any associated state.
240 * It must NOT call #GNUNET_MESH_channel_destroy on the channel.
242 * @param cls closure (set from #GNUNET_MESH_connect)
243 * @param channel connection to the other end (henceforth invalid)
244 * @param channel_ctx place where local state associated
245 * with the channel is stored
248 channel_ended (void *cls,
249 const struct GNUNET_MESH_Channel *channel,
252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n");
253 GNUNET_break (channel == ch);
255 GNUNET_SCHEDULER_shutdown ();
260 * Method called whenever another peer has added us to a channel
261 * the other peer initiated.
262 * Only called (once) upon reception of data with a message type which was
263 * subscribed to in #GNUNET_MESH_connect.
265 * A call to #GNUNET_MESH_channel_destroy causes te channel to be ignored. In
266 * this case the handler MUST return NULL.
269 * @param channel new handle to the channel
270 * @param initiator peer that started the channel
271 * @param port Port this channel is for.
272 * @param options MeshOption flag field, with all active option bits set to 1.
274 * @return initial channel context for the channel
275 * (can be NULL -- that's not an error)
278 channel_incoming (void *cls,
279 struct GNUNET_MESH_Channel * channel,
280 const struct GNUNET_PeerIdentity * initiator,
281 uint32_t port, enum GNUNET_MESH_ChannelOption options)
283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
284 "Incoming channel %p on port %u\n",
288 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "A channel already exists\n");
291 if (0 == listen_port)
293 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not listening to channels\n");
297 if (GNUNET_NO == echo)
307 * @brief Send an echo request to the remote peer.
309 * @param cls Closure (NULL).
310 * @param tc Task context.
313 send_echo (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
315 GNUNET_MESH_notify_transmit_ready (ch, GNUNET_NO,
316 GNUNET_TIME_UNIT_FOREVER_REL,
317 sizeof (struct GNUNET_MessageHeader),
324 * Call MESH's monitor API, get info of one connection.
326 * @param cls Closure (unused).
327 * @param tc TaskContext
330 create_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
332 struct GNUNET_PeerIdentity pid;
333 enum GNUNET_MESH_ChannelOption opt;
335 GNUNET_assert (NULL == ch);
338 GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
343 _("Invalid target `%s'\n"),
345 GNUNET_SCHEDULER_shutdown ();
348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id);
349 opt = GNUNET_MESH_OPTION_DEFAULT | GNUNET_MESH_OPTION_RELIABLE;
350 ch = GNUNET_MESH_channel_create (mh, NULL, &pid, target_port, opt);
351 if (GNUNET_NO == echo)
354 GNUNET_SCHEDULER_add_now (send_echo, NULL);
359 * Function called whenever a message is received.
361 * Each time the function must call #GNUNET_MESH_receive_done on the channel
362 * in order to receive the next message. This doesn't need to be immediate:
363 * can be delayed if some processing is done on the message.
365 * @param cls Closure (set from #GNUNET_MESH_connect).
366 * @param channel Connection to the other end.
367 * @param channel_ctx Place to store local state associated with the channel.
368 * @param message The actual message.
369 * @return #GNUNET_OK to keep the channel open,
370 * #GNUNET_SYSERR to close it (signal serious error).
373 data_callback (void *cls,
374 struct GNUNET_MESH_Channel *channel,
376 const struct GNUNET_MessageHeader *message)
382 GNUNET_break (ch == channel);
384 if (GNUNET_YES == echo)
386 if (0 != listen_port)
388 /* Just listening to echo incoming messages*/
389 GNUNET_MESH_notify_transmit_ready (channel, GNUNET_NO,
390 GNUNET_TIME_UNIT_FOREVER_REL,
391 sizeof (struct GNUNET_MessageHeader),
397 struct GNUNET_TIME_Relative latency;
399 latency = GNUNET_TIME_absolute_get_duration (echo_time);
400 echo_time = GNUNET_TIME_UNIT_FOREVER_ABS;
401 FPRINTF (stdout, "time: %s\n",
402 GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO));
403 echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
408 len = ntohs (message->size) - sizeof (*message);
409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len);
410 buf = (const char *) &message[1];
414 done = write (1, &buf[off], len - off);
418 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
420 return GNUNET_SYSERR;
429 * Method called to retrieve information about all tunnels in MESH.
431 * @param cls Closure.
432 * @param peer Destination peer.
433 * @param channels Number of channels.
434 * @param connections Number of connections.
435 * @param estate Encryption state.
436 * @param cstate Connectivity state.
439 tunnels_callback (void *cls,
440 const struct GNUNET_PeerIdentity *peer,
441 unsigned int channels,
442 unsigned int connections,
448 if (GNUNET_YES != monitor_connections)
450 GNUNET_SCHEDULER_shutdown();
454 FPRINTF (stdout, "%s [ENC: %u, CON: %u] CHs: %u, CONNs: %u\n",
455 GNUNET_i2s_full (peer), estate, cstate, channels, connections);
460 * Method called to retrieve information about a specific tunnel the mesh peer
461 * has established, o`r is trying to establish.
463 * @param cls Closure.
464 * @param peer Peer towards whom the tunnel is directed.
465 * @param channels Number of channels.
466 * @param connections Number of connections.
467 * @param estate Encryption status.
468 * @param cstate Connectivity status.
471 tunnel_callback (void *cls,
472 const struct GNUNET_PeerIdentity *peer,
473 unsigned int channels,
474 unsigned int connections,
478 FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer));
479 FPRINTF (stdout, "- %u channels\n", channels);
480 FPRINTF (stdout, "- %u connections\n", connections);
481 FPRINTF (stdout, "- enc state: %u\n", estate);
482 FPRINTF (stdout, "- con state: %u\n", cstate);
487 * Call MESH's monitor API, get all tunnels known to peer.
489 * @param cls Closure (unused).
490 * @param tc TaskContext
493 get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n");
496 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
500 GNUNET_MESH_get_tunnels (mh, &tunnels_callback, NULL);
505 * Call MESH's monitor API, get info of one tunnel.
507 * @param cls Closure (unused).
508 * @param tc TaskContext
511 show_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
513 struct GNUNET_PeerIdentity pid;
516 GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
521 _("Invalid tunnel owner `%s'\n"),
523 GNUNET_SCHEDULER_shutdown();
526 GNUNET_MESH_get_tunnel (mh, &pid, tunnel_callback, NULL);
531 * Call MESH's monitor API, get info of one channel.
533 * @param cls Closure (unused).
534 * @param tc TaskContext
537 show_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
544 * Call MESH's monitor API, get info of one connection.
546 * @param cls Closure (unused).
547 * @param tc TaskContext
550 show_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
557 * Main function that will be run by the scheduler.
560 * @param args remaining command-line arguments
561 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
562 * @param cfg configuration
565 run (void *cls, char *const *args, const char *cfgfile,
566 const struct GNUNET_CONFIGURATION_Handle *cfg)
568 GNUNET_MESH_InboundChannelNotificationHandler *newch = NULL;
569 GNUNET_MESH_ChannelEndHandler *endch = NULL;
570 static const struct GNUNET_MESH_MessageHandler handlers[] = {
571 {&data_callback, GNUNET_MESSAGE_TYPE_MESH_CLI, 0},
572 {NULL, 0, 0} /* FIXME add option to monitor msg types */
574 static uint32_t *ports = NULL;
575 /* FIXME add option to monitor apps */
578 target_port = args[0] && args[1] ? atoi(args[1]) : 0;
580 || 0 != monitor_connections
583 || NULL != channel_id)
584 && target_id != NULL)
586 FPRINTF (stderr, _("You must NOT give a TARGET when using options\n"));
590 if (NULL != target_id)
592 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
593 "Creating channel to %s\n",
595 GNUNET_SCHEDULER_add_now (&create_channel, NULL);
596 endch = &channel_ended;
598 else if (0 != listen_port)
600 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Listen\n");
601 newch = &channel_incoming;
602 endch = &channel_ended;
603 ports = GNUNET_malloc (sizeof (uint32_t) * 2);
604 ports[0] = listen_port;
606 else if (NULL != tunnel_id)
608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n");
609 GNUNET_SCHEDULER_add_now (&show_tunnel, NULL);
611 else if (NULL != channel_id)
613 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n");
614 GNUNET_SCHEDULER_add_now (&show_channel, NULL);
616 else if (NULL != conn_id)
618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
619 GNUNET_SCHEDULER_add_now (&show_connection, NULL);
621 else if (GNUNET_YES == get_info)
623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
624 GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
628 FPRINTF (stderr, "No action requested\n");
632 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to mesh\n");
633 mh = GNUNET_MESH_connect (cfg,
635 newch, /* new channel */
639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done\n");
641 GNUNET_SCHEDULER_add_now (shutdown_task, NULL);
643 sd = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
644 shutdown_task, NULL);
650 * The main function to obtain peer information.
652 * @param argc number of arguments from the command line
653 * @param argv command line arguments
654 * @return 0 ok, 1 on error
657 main (int argc, char *const *argv)
660 const char helpstr[] = "Create channels and retreive info about meshs status.";
661 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
662 {'a', "channel", "TUNNEL_ID:CHANNEL_ID",
663 gettext_noop ("provide information about a particular channel"),
664 GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id},
665 {'b', "connection", "TUNNEL_ID:CONNECTION_ID",
666 gettext_noop ("provide information about a particular connection"),
667 GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id},
669 gettext_noop ("activate echo mode"),
670 GNUNET_NO, &GNUNET_GETOPT_set_one, &echo},
672 gettext_noop ("provide information about all tunnels"),
673 GNUNET_NO, &GNUNET_GETOPT_set_one, &get_info},
674 {'m', "monitor", NULL,
675 gettext_noop ("provide information about all tunnels (continuously) NOT IMPLEMENTED"), /* FIXME */
676 GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_connections},
678 gettext_noop ("port to listen to (default; 0)"),
679 GNUNET_YES, &GNUNET_GETOPT_set_uint, &listen_port},
680 {'t', "tunnel", "TUNNEL_ID",
681 gettext_noop ("provide information about a particular tunnel"),
682 GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id},
684 GNUNET_GETOPT_OPTION_END
687 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
690 res = GNUNET_PROGRAM_run (argc, argv, "gnunet-mesh (OPTIONS | TARGET PORT)",
691 gettext_noop (helpstr),
692 options, &run, NULL);
694 GNUNET_free ((void *) argv);
696 if (GNUNET_OK == res)
702 /* end of gnunet-mesh.c */