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;
64 static char *target_id;
69 static uint32_t target_port;
72 * Data pending in netcat mode.
80 static struct GNUNET_MESH_Handle *mh;
85 static struct GNUNET_MESH_Channel *ch;
88 * Shutdown task handle.
90 GNUNET_SCHEDULER_TaskIdentifier sd;
100 * Task run in monitor mode when the user presses CTRL-C to abort.
101 * Stops monitoring activity.
103 * @param cls Closure (unused).
104 * @param tc scheduler context
107 shutdown_task (void *cls,
108 const struct GNUNET_SCHEDULER_TaskContext *tc)
112 GNUNET_MESH_channel_destroy (ch);
117 GNUNET_MESH_disconnect (mh);
124 * Function called to notify a client about the connection
125 * begin ready to queue more data. "buf" will be
126 * NULL and "size" zero if the connection was closed for
127 * writing in the meantime.
132 * @param size number of bytes available in buf
133 * @param buf where the callee should write the message
134 * @return number of bytes written to buf
137 data_ready (void *cls, size_t size, void *buf)
139 struct GNUNET_MessageHeader *msg;
142 if (NULL == buf || 0 == size)
144 GNUNET_SCHEDULER_shutdown();
148 total_size = data_size + sizeof (struct GNUNET_MessageHeader);
149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending %u bytes\n", data_size);
150 GNUNET_assert (size >= total_size);
153 msg->size = htons (total_size);
154 msg->type = htons (GNUNET_MESSAGE_TYPE_MESH_CLI);
155 memcpy (&msg[1], cls, data_size);
163 * Task run in monitor mode when the user presses CTRL-C to abort.
164 * Stops monitoring activity.
166 * @param cls Closure (unused).
167 * @param tc scheduler context
170 read_stdio (void *cls,
171 const struct GNUNET_SCHEDULER_TaskContext *tc)
173 static char buf[60000];
175 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
180 data_size = read (0, buf, 60000);
181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stdio read %u bytes\n", data_size);
184 GNUNET_SCHEDULER_shutdown();
187 GNUNET_MESH_notify_transmit_ready (ch, GNUNET_NO,
188 GNUNET_TIME_UNIT_FOREVER_REL,
190 + sizeof (struct GNUNET_MessageHeader),
196 * Start listening to stdin
201 struct GNUNET_NETWORK_FDSet *rs;
203 rs = GNUNET_NETWORK_fdset_create ();
204 GNUNET_NETWORK_fdset_set_native (rs, 0);
205 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
206 GNUNET_TIME_UNIT_FOREVER_REL,
209 GNUNET_NETWORK_fdset_destroy (rs);
214 * Function called whenever a channel is destroyed. Should clean up
215 * any associated state.
217 * It must NOT call #GNUNET_MESH_channel_destroy on the channel.
219 * @param cls closure (set from #GNUNET_MESH_connect)
220 * @param channel connection to the other end (henceforth invalid)
221 * @param channel_ctx place where local state associated
222 * with the channel is stored
225 channel_ended (void *cls,
226 const struct GNUNET_MESH_Channel *channel,
229 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n");
230 GNUNET_break (channel == ch);
232 GNUNET_SCHEDULER_shutdown ();
237 * Method called whenever another peer has added us to a channel
238 * the other peer initiated.
239 * Only called (once) upon reception of data with a message type which was
240 * subscribed to in #GNUNET_MESH_connect.
242 * A call to #GNUNET_MESH_channel_destroy causes te channel to be ignored. In
243 * this case the handler MUST return NULL.
246 * @param channel new handle to the channel
247 * @param initiator peer that started the channel
248 * @param port Port this channel is for.
249 * @param options MeshOption flag field, with all active option bits set to 1.
251 * @return initial channel context for the channel
252 * (can be NULL -- that's not an error)
255 channel_incoming (void *cls,
256 struct GNUNET_MESH_Channel * channel,
257 const struct GNUNET_PeerIdentity * initiator,
258 uint32_t port, enum GNUNET_MESH_ChannelOption options)
260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
261 "Incoming channel %p on port %u\n",
265 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "A channel already exists\n");
268 if (0 == listen_port)
270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not listening to channels\n");
281 * Call MESH's monitor API, get info of one connection.
283 * @param cls Closure (unused).
284 * @param tc TaskContext
287 create_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
289 struct GNUNET_PeerIdentity pid;
290 enum GNUNET_MESH_ChannelOption opt;
292 GNUNET_assert (NULL == ch);
295 GNUNET_CRYPTO_eddsa_public_key_from_string (target_id,
300 _("Invalid target `%s'\n"),
302 GNUNET_SCHEDULER_shutdown ();
305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id);
306 opt = GNUNET_MESH_OPTION_DEFAULT | GNUNET_MESH_OPTION_RELIABLE;
307 ch = GNUNET_MESH_channel_create (mh, NULL, &pid, target_port, opt);
313 * Function called whenever a message is received.
315 * Each time the function must call #GNUNET_MESH_receive_done on the channel
316 * in order to receive the next message. This doesn't need to be immediate:
317 * can be delayed if some processing is done on the message.
319 * @param cls Closure (set from #GNUNET_MESH_connect).
320 * @param channel Connection to the other end.
321 * @param channel_ctx Place to store local state associated with the channel.
322 * @param message The actual message.
323 * @return #GNUNET_OK to keep the channel open,
324 * #GNUNET_SYSERR to close it (signal serious error).
327 data_callback (void *cls,
328 struct GNUNET_MESH_Channel *channel,
330 const struct GNUNET_MessageHeader *message)
336 GNUNET_break (ch == channel);
338 len = ntohs (message->size) - sizeof (*message);
339 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len);
340 buf = (const char *) &message[1];
344 done = write (1, &buf[off], len - off);
348 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
350 return GNUNET_SYSERR;
359 * Method called to retrieve information about each tunnel the mesh peer
362 * @param cls Closure.
363 * @param tunnel_number Tunnel number.
364 * @param origin that started the tunnel (owner).
365 * @param target other endpoint of the tunnel
367 void /* FIXME static */
368 tunnels_callback (void *cls,
369 uint32_t tunnel_number,
370 const struct GNUNET_PeerIdentity *origin,
371 const struct GNUNET_PeerIdentity *target)
373 FPRINTF (stdout, "Tunnel %s [%u]\n",
374 GNUNET_i2s_full (origin), tunnel_number);
375 FPRINTF (stdout, "\n");
380 * Method called to retrieve information about each tunnel the mesh peer
383 * @param cls Closure.
384 * @param peer Peer in the tunnel's tree.
385 * @param parent Parent of the current peer. All 0 when peer is root.
388 void /* FIXME static */
389 tunnel_callback (void *cls,
390 const struct GNUNET_PeerIdentity *peer,
391 const struct GNUNET_PeerIdentity *parent)
397 * Call MESH's monitor API, get all tunnels known to peer.
399 * @param cls Closure (unused).
400 * @param tc TaskContext
403 get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
405 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
409 // GNUNET_MESH_get_tunnels (mh, &tunnels_callback, NULL);
410 if (GNUNET_YES != monitor_connections)
412 GNUNET_SCHEDULER_shutdown();
418 * Call MESH's monitor API, get info of one tunnel.
420 * @param cls Closure (unused).
421 * @param tc TaskContext
424 show_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
426 struct GNUNET_PeerIdentity pid;
429 GNUNET_CRYPTO_eddsa_public_key_from_string (tunnel_id,
434 _("Invalid tunnel owner `%s'\n"),
436 GNUNET_SCHEDULER_shutdown();
439 // GNUNET_MESH_show_tunnel (mh, &pid, 0, tunnel_callback, NULL);
444 * Call MESH's monitor API, get info of one channel.
446 * @param cls Closure (unused).
447 * @param tc TaskContext
450 show_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
457 * Call MESH's monitor API, get info of one connection.
459 * @param cls Closure (unused).
460 * @param tc TaskContext
463 show_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
470 * Main function that will be run by the scheduler.
473 * @param args remaining command-line arguments
474 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
475 * @param cfg configuration
478 run (void *cls, char *const *args, const char *cfgfile,
479 const struct GNUNET_CONFIGURATION_Handle *cfg)
481 GNUNET_MESH_InboundChannelNotificationHandler *newch = NULL;
482 GNUNET_MESH_ChannelEndHandler *endch = NULL;
483 static const struct GNUNET_MESH_MessageHandler handlers[] = {
484 {&data_callback, GNUNET_MESSAGE_TYPE_MESH_CLI, 0},
485 {NULL, 0, 0} /* FIXME add option to monitor msg types */
487 static uint32_t *ports = NULL;
488 /* FIXME add option to monitor apps */
491 target_port = args[0] && args[1] ? atoi(args[1]) : 0;
493 || 0 != monitor_connections
496 || NULL != channel_id)
497 && target_id != NULL)
499 FPRINTF (stderr, _("You must NOT give a TARGET when using options\n"));
503 if (NULL != target_id)
505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
506 "Creating channel to %s\n",
508 GNUNET_SCHEDULER_add_now (&create_channel, NULL);
509 endch = &channel_ended;
511 else if (0 != listen_port)
513 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Listen\n");
514 newch = &channel_incoming;
515 endch = &channel_ended;
516 ports = GNUNET_malloc (sizeof (uint32_t) * 2);
517 ports[0] = listen_port;
519 else if (NULL != tunnel_id)
521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show tunnel\n");
522 GNUNET_SCHEDULER_add_now (&show_tunnel, NULL);
524 else if (NULL != channel_id)
526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show channel\n");
527 GNUNET_SCHEDULER_add_now (&show_channel, NULL);
529 else if (NULL != conn_id)
531 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n");
532 GNUNET_SCHEDULER_add_now (&show_connection, NULL);
534 else if (GNUNET_YES == get_info)
536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n");
537 GNUNET_SCHEDULER_add_now (&get_tunnels, NULL);
541 FPRINTF (stderr, "No action requested\n");
545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to mesh\n");
546 mh = GNUNET_MESH_connect (cfg,
548 newch, /* new channel */
552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done\n");
554 GNUNET_SCHEDULER_add_now (shutdown_task, NULL);
556 sd = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
557 shutdown_task, NULL);
563 * The main function to obtain peer information.
565 * @param argc number of arguments from the command line
566 * @param argv command line arguments
567 * @return 0 ok, 1 on error
570 main (int argc, char *const *argv)
573 const char helpstr[] = "Create channels and retreive info about meshs status.";
574 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
575 {'a', "channel", "TUNNEL_ID:CHANNEL_ID",
576 gettext_noop ("provide information about a particular channel"),
577 GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id},
578 {'b', "connection", "TUNNEL_ID:CONNECTION_ID",
579 gettext_noop ("provide information about a particular connection"),
580 GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id},
582 gettext_noop ("provide information about all tunnels"),
583 GNUNET_NO, &GNUNET_GETOPT_set_one, &get_info},
584 {'m', "monitor", NULL,
585 gettext_noop ("provide information about all tunnels (continuously) NOT IMPLEMENTED"), /* FIXME */
586 GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_connections},
588 gettext_noop ("port to listen to (default; 0)"),
589 GNUNET_YES, &GNUNET_GETOPT_set_uint, &listen_port},
590 {'t', "tunnel", "TUNNEL_ID",
591 gettext_noop ("provide information about a particular tunnel"),
592 GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id},
593 GNUNET_GETOPT_OPTION_END
596 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
599 res = GNUNET_PROGRAM_run (argc, argv, "gnunet-mesh (OPTIONS | TARGET PORT)",
600 gettext_noop (helpstr),
601 options, &run, NULL);
603 GNUNET_free ((void *) argv);
605 if (GNUNET_OK == res)
611 /* end of gnunet-mesh.c */