X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=inline;f=src%2Fmesh%2Fgnunet-mesh.c;h=7677b244f85e853b57e030e608a30a52625a51ce;hb=1fdcd4fa20f76fa8266e77567d12ce4b627c3d71;hp=7450d8dc3e66bd367dc611782aebb0521cfc9f0b;hpb=1bf79006d9c303944d1edf640e98131505c2ec17;p=oweals%2Fgnunet.git diff --git a/src/mesh/gnunet-mesh.c b/src/mesh/gnunet-mesh.c index 7450d8dc3..7677b244f 100644 --- a/src/mesh/gnunet-mesh.c +++ b/src/mesh/gnunet-mesh.c @@ -26,6 +26,7 @@ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_mesh_service.h" +#include "mesh.h" /** @@ -34,9 +35,14 @@ static int monitor_connections; /** - * Option -i. + * Option -P. */ -static int get_info; +static int request_peers; + +/** + * Option -T. + */ +static int request_tunnels; /** * Option --tunnel @@ -58,6 +64,21 @@ static char *channel_id; */ static uint32_t listen_port; +/** + * Request echo service + */ +int echo; + +/** + * Time of last echo request. + */ +struct GNUNET_TIME_Absolute echo_time; + +/** + * Task for next echo request. + */ +GNUNET_SCHEDULER_TaskIdentifier echo_task; + /** * Peer to connect to. */ @@ -68,16 +89,34 @@ static char *target_id; */ static uint32_t target_port; +/** + * Data pending in netcat mode. + */ +size_t data_size; + + /** * Mesh handle. */ static struct GNUNET_MESH_Handle *mh; +/** + * Channel handle. + */ +static struct GNUNET_MESH_Channel *ch; + /** * Shutdown task handle. */ GNUNET_SCHEDULER_TaskIdentifier sd; + + +static void +listen_stdio (void); + + + /** * Task run in monitor mode when the user presses CTRL-C to abort. * Stops monitoring activity. @@ -89,6 +128,12 @@ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n"); + if (NULL != ch) + { + GNUNET_MESH_channel_destroy (ch); + ch = NULL; + } if (NULL != mh) { GNUNET_MESH_disconnect (mh); @@ -97,6 +142,103 @@ shutdown_task (void *cls, } +/** + * Function called to notify a client about the connection + * begin ready to queue more data. "buf" will be + * NULL and "size" zero if the connection was closed for + * writing in the meantime. + * + * FIXME + * + * @param cls closure + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf + */ +size_t +data_ready (void *cls, size_t size, void *buf) +{ + struct GNUNET_MessageHeader *msg; + size_t total_size; + + if (NULL == buf || 0 == size) + { + GNUNET_SCHEDULER_shutdown(); + return 0; + } + + total_size = data_size + sizeof (struct GNUNET_MessageHeader); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending %u bytes\n", data_size); + GNUNET_assert (size >= total_size); + + msg = buf; + msg->size = htons (total_size); + msg->type = htons (GNUNET_MESSAGE_TYPE_MESH_CLI); + memcpy (&msg[1], cls, data_size); + if (GNUNET_NO == echo) + { + listen_stdio (); + } + else + { + echo_time = GNUNET_TIME_absolute_get (); + } + + return total_size; +} + + +/** + * Task run in monitor mode when the user presses CTRL-C to abort. + * Stops monitoring activity. + * + * @param cls Closure (unused). + * @param tc scheduler context + */ +static void +read_stdio (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + static char buf[60000]; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + return; + } + + data_size = read (0, buf, 60000); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stdio read %u bytes\n", data_size); + if (data_size < 1) + { + GNUNET_SCHEDULER_shutdown(); + return; + } + GNUNET_MESH_notify_transmit_ready (ch, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + data_size + + sizeof (struct GNUNET_MessageHeader), + &data_ready, buf); +} + + +/** + * Start listening to stdin + */ +static void +listen_stdio (void) +{ + struct GNUNET_NETWORK_FDSet *rs; + + rs = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_set_native (rs, 0); + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_TIME_UNIT_FOREVER_REL, + rs, NULL, + &read_stdio, NULL); + GNUNET_NETWORK_fdset_destroy (rs); +} + + /** * Function called whenever a channel is destroyed. Should clean up * any associated state. @@ -113,7 +255,10 @@ channel_ended (void *cls, const struct GNUNET_MESH_Channel *channel, void *channel_ctx) { - FPRINTF (stdout, "Channel ended!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel ended!\n"); + GNUNET_break (channel == ch); + ch = NULL; + GNUNET_SCHEDULER_shutdown (); } @@ -135,16 +280,50 @@ channel_ended (void *cls, * @return initial channel context for the channel * (can be NULL -- that's not an error) */ -void * +static void * channel_incoming (void *cls, struct GNUNET_MESH_Channel * channel, const struct GNUNET_PeerIdentity * initiator, - uint32_t port, enum MeshOption options) + uint32_t port, enum GNUNET_MESH_ChannelOption options) { - FPRINTF (stdout, "Incoming channel!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Incoming channel %p on port %u\n", + channel, port); + if (NULL != ch) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "A channel already exists\n"); + return NULL; + } + if (0 == listen_port) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not listening to channels\n"); + return NULL; + } + ch = channel; + if (GNUNET_NO == echo) + { + listen_stdio (); + return NULL; + } + data_size = 0; return NULL; } +/** + * @brief Send an echo request to the remote peer. + * + * @param cls Closure (NULL). + * @param tc Task context. + */ +static void +send_echo (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_MESH_notify_transmit_ready (ch, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + sizeof (struct GNUNET_MessageHeader), + &data_ready, NULL); +} + /** @@ -157,6 +336,9 @@ static void create_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_PeerIdentity pid; + enum GNUNET_MESH_ChannelOption opt; + + GNUNET_assert (NULL == ch); if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (target_id, @@ -166,69 +348,228 @@ create_channel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) FPRINTF (stderr, _("Invalid target `%s'\n"), target_id); - GNUNET_SCHEDULER_shutdown(); + GNUNET_SCHEDULER_shutdown (); return; } -// GNUNET_MESH_channel_create () + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to `%s'\n", target_id); + opt = GNUNET_MESH_OPTION_DEFAULT | GNUNET_MESH_OPTION_RELIABLE; + ch = GNUNET_MESH_channel_create (mh, NULL, &pid, target_port, opt); + if (GNUNET_NO == echo) + listen_stdio (); + else + GNUNET_SCHEDULER_add_now (send_echo, NULL); } /** - * Method called to retrieve information about each tunnel the mesh peer - * is aware of. + * Function called whenever a message is received. + * + * Each time the function must call #GNUNET_MESH_receive_done on the channel + * in order to receive the next message. This doesn't need to be immediate: + * can be delayed if some processing is done on the message. + * + * @param cls Closure (set from #GNUNET_MESH_connect). + * @param channel Connection to the other end. + * @param channel_ctx Place to store local state associated with the channel. + * @param message The actual message. + * @return #GNUNET_OK to keep the channel open, + * #GNUNET_SYSERR to close it (signal serious error). + */ +static int +data_callback (void *cls, + struct GNUNET_MESH_Channel *channel, + void **channel_ctx, + const struct GNUNET_MessageHeader *message) +{ + uint16_t len; + ssize_t done; + uint16_t off; + const char *buf; + GNUNET_break (ch == channel); + + if (GNUNET_YES == echo) + { + if (0 != listen_port) + { + /* Just listening to echo incoming messages*/ + GNUNET_MESH_notify_transmit_ready (channel, GNUNET_NO, + GNUNET_TIME_UNIT_FOREVER_REL, + sizeof (struct GNUNET_MessageHeader), + &data_ready, NULL); + return GNUNET_OK; + } + else + { + struct GNUNET_TIME_Relative latency; + + latency = GNUNET_TIME_absolute_get_duration (echo_time); + echo_time = GNUNET_TIME_UNIT_FOREVER_ABS; + FPRINTF (stdout, "time: %s\n", + GNUNET_STRINGS_relative_time_to_string (latency, GNUNET_NO)); + echo_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &send_echo, NULL); + } + } + + len = ntohs (message->size) - sizeof (*message); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes\n", len); + buf = (const char *) &message[1]; + off = 0; + while (off < len) + { + done = write (1, &buf[off], len - off); + if (done <= 0) + { + if (-1 == done) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "write"); + return GNUNET_SYSERR; + } + off += done; + } + return GNUNET_OK; +} + + +/** + * Method called to retrieve information about all peers in MESH, called + * once per peer. + * + * After last peer has been reported, an additional call with NULL is done. * * @param cls Closure. - * @param tunnel_number Tunnel number. - * @param origin that started the tunnel (owner). - * @param target other endpoint of the tunnel + * @param peer Peer, or NULL on "EOF". + * @param tunnel Do we have a tunnel towards this peer? + * @param n_paths Number of known paths towards this peer. + * @param best_path How long is the best path? + * (0 = unknown, 1 = ourselves, 2 = neighbor) */ -void /* FIXME static */ -tunnels_callback (void *cls, - uint32_t tunnel_number, - const struct GNUNET_PeerIdentity *origin, - const struct GNUNET_PeerIdentity *target) +static void +peers_callback (void *cls, const struct GNUNET_PeerIdentity *peer, + int tunnel, unsigned int n_paths, unsigned int best_path) { - fprintf (stdout, "Tunnel %s [%u]\n", - GNUNET_i2s_full (origin), tunnel_number); - fprintf (stdout, "\n"); + if (NULL == peer) + { + if (GNUNET_YES != monitor_connections) + { + GNUNET_SCHEDULER_shutdown(); + } + return; + } + FPRINTF (stdout, "%s tunnel: %c, paths: %u\n", + GNUNET_i2s_full (peer), tunnel ? 'Y' : 'N', n_paths); } /** - * Method called to retrieve information about each tunnel the mesh peer - * is aware of. + * Method called to retrieve information about all tunnels in MESH. * * @param cls Closure. - * @param peer Peer in the tunnel's tree. - * @param parent Parent of the current peer. All 0 when peer is root. + * @param peer Destination peer. + * @param channels Number of channels. + * @param connections Number of connections. + * @param estate Encryption state. + * @param cstate Connectivity state. + */ +void +tunnels_callback (void *cls, + const struct GNUNET_PeerIdentity *peer, + unsigned int channels, + unsigned int connections, + uint16_t estate, + uint16_t cstate) +{ + if (NULL == peer) + { + if (GNUNET_YES != monitor_connections) + { + GNUNET_SCHEDULER_shutdown(); + } + return; + } + FPRINTF (stdout, "%s [ENC: %u, CON: %u] CHs: %u, CONNs: %u\n", + GNUNET_i2s_full (peer), estate, cstate, channels, connections); +} + + +/** + * Method called to retrieve information about a specific tunnel the mesh peer + * has established, o`r is trying to establish. * + * @param cls Closure. + * @param peer Peer towards whom the tunnel is directed. + * @param n_channels Number of channels. + * @param n_connections Number of connections. + * @param channels Channels. + * @param connections Connections. + * @param estate Encryption status. + * @param cstate Connectivity status. */ -void /* FIXME static */ +void tunnel_callback (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_PeerIdentity *parent) + unsigned int n_channels, + unsigned int n_connections, + uint32_t *channels, + struct GNUNET_MeshHash *connections, + unsigned int estate, + unsigned int cstate) { + unsigned int i; + + if (NULL != peer) + { + FPRINTF (stdout, "Tunnel %s\n", GNUNET_i2s_full (peer)); + FPRINTF (stdout, "- %u channels\n", n_channels); + for (i = 0; i < n_channels; i++) + FPRINTF (stdout, " %u\n", channels[i]); + FPRINTF (stdout, "- %u connections\n", n_connections); + for (i = 0; i < n_connections; i++) + FPRINTF (stdout, " %s\n", GM_h2s (&connections[i])); + FPRINTF (stdout, "- enc state: %u\n", estate); + FPRINTF (stdout, "- con state: %u\n", cstate); + } + if (GNUNET_YES != monitor_connections) + { + GNUNET_SCHEDULER_shutdown(); + } + return; + } /** - * Call MESH's monitor API, get all tunnels known to peer. + * Call MESH's meta API, get all peers known to a peer. * * @param cls Closure (unused). * @param tc TaskContext */ static void -get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +get_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n"); return; } -// GNUNET_MESH_get_tunnels (mh, &tunnels_callback, NULL); - if (GNUNET_YES != monitor_connections) + GNUNET_MESH_get_peers (mh, &peers_callback, NULL); +} + +/** + * Call MESH's meta API, get all tunnels known to a peer. + * + * @param cls Closure (unused). + * @param tc TaskContext + */ +static void +get_tunnels (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { - GNUNET_SCHEDULER_shutdown(); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown\n"); + return; } + GNUNET_MESH_get_tunnels (mh, &tunnels_callback, NULL); } @@ -254,7 +595,7 @@ show_tunnel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_SCHEDULER_shutdown(); return; } -// GNUNET_MESH_show_tunnel (mh, &pid, 0, tunnel_callback, NULL); + GNUNET_MESH_get_tunnel (mh, &pid, tunnel_callback, NULL); } @@ -296,21 +637,27 @@ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { + GNUNET_MESH_InboundChannelNotificationHandler *newch = NULL; + GNUNET_MESH_ChannelEndHandler *endch = NULL; static const struct GNUNET_MESH_MessageHandler handlers[] = { + {&data_callback, GNUNET_MESSAGE_TYPE_MESH_CLI, 0}, {NULL, 0, 0} /* FIXME add option to monitor msg types */ }; + static uint32_t *ports = NULL; /* FIXME add option to monitor apps */ target_id = args[0]; target_port = args[0] && args[1] ? atoi(args[1]) : 0; - if ( (0 != get_info + if ( (0 != (request_peers | request_tunnels) || 0 != monitor_connections || NULL != tunnel_id || NULL != conn_id || NULL != channel_id) && target_id != NULL) { - FPRINTF (stderr, _("You must NOT give a TARGET when using options\n")); + FPRINTF (stderr, + _("You must NOT give a TARGET" + "when using 'request all' options\n")); return; } @@ -320,6 +667,15 @@ run (void *cls, char *const *args, const char *cfgfile, "Creating channel to %s\n", target_id); GNUNET_SCHEDULER_add_now (&create_channel, NULL); + endch = &channel_ended; + } + else if (0 != listen_port) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Listen\n"); + newch = &channel_incoming; + endch = &channel_ended; + ports = GNUNET_malloc (sizeof (uint32_t) * 2); + ports[0] = listen_port; } else if (NULL != tunnel_id) { @@ -336,7 +692,12 @@ run (void *cls, char *const *args, const char *cfgfile, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show connection\n"); GNUNET_SCHEDULER_add_now (&show_connection, NULL); } - else if (GNUNET_YES == get_info) + else if (GNUNET_YES == request_peers) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all peers\n"); + GNUNET_SCHEDULER_add_now (&get_peers, NULL); + } + else if (GNUNET_YES == request_tunnels) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Show all tunnels\n"); GNUNET_SCHEDULER_add_now (&get_tunnels, NULL); @@ -350,11 +711,11 @@ run (void *cls, char *const *args, const char *cfgfile, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to mesh\n"); mh = GNUNET_MESH_connect (cfg, NULL, /* cls */ - NULL, /* new tunnel */ - NULL, /* cleaner */ + newch, /* new channel */ + endch, /* cleaner */ handlers, - NULL); - FPRINTF (stdout, "Done\n"); + ports); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done\n"); if (NULL == mh) GNUNET_SCHEDULER_add_now (shutdown_task, NULL); else @@ -375,35 +736,44 @@ int main (int argc, char *const *argv) { int res; + const char helpstr[] = "Create channels and retreive info about meshs status."; static const struct GNUNET_GETOPT_CommandLineOption options[] = { - {'a', "channel", "TUNNEL_ID:CHANNEL_ID", - gettext_noop ("provide information about a particular channel"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id}, - {'b', "connection", "TUNNEL_ID:CONNECTION_ID", +// {'a', "channel", "TUNNEL_ID:CHANNEL_ID", +// gettext_noop ("provide information about a particular channel"), +// GNUNET_YES, &GNUNET_GETOPT_set_string, &channel_id}, + {'C', "connection", "CONNECTION_ID", gettext_noop ("provide information about a particular connection"), GNUNET_YES, &GNUNET_GETOPT_set_string, &conn_id}, - {'i', "info", NULL, - gettext_noop ("provide information about all tunnels"), - GNUNET_NO, &GNUNET_GETOPT_set_one, &get_info}, - {'m', "monitor", NULL, - gettext_noop ("provide information about all tunnels (continuously) NOT IMPLEMENTED"), /* FIXME */ - GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_connections}, + {'e', "echo", NULL, + gettext_noop ("activate echo mode"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &echo}, +// {'m', "monitor", NULL, +// gettext_noop ("provide information about all tunnels (continuously) NOT IMPLEMENTED"), /* FIXME */ +// GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor_connections}, {'p', "port", NULL, gettext_noop ("port to listen to (default; 0)"), GNUNET_YES, &GNUNET_GETOPT_set_uint, &listen_port}, + {'P', "peers", NULL, + gettext_noop ("provide information about all peers"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &request_peers}, {'t', "tunnel", "TUNNEL_ID", gettext_noop ("provide information about a particular tunnel"), GNUNET_YES, &GNUNET_GETOPT_set_string, &tunnel_id}, + {'T', "tunnels", NULL, + gettext_noop ("provide information about all tunnels"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &request_tunnels}, + GNUNET_GETOPT_OPTION_END }; + monitor_connections = GNUNET_NO; + if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) return 2; res = GNUNET_PROGRAM_run (argc, argv, "gnunet-mesh (OPTIONS | TARGET PORT)", - gettext_noop - ("Create channels and retreive info about meshs status."), - options, &run, NULL); + gettext_noop (helpstr), + options, &run, NULL); GNUNET_free ((void *) argv);