From 6354733cc5044c5226c430d97262c06ab4cd0d5e Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Thu, 30 May 2019 23:34:35 +0200 Subject: [PATCH] Speed up initial autoconnect after joining a mesh. When we just joined a mesh, we quickly want to establish redundant connections. We do this by resetting the outgoing timer if we receive a public key for a node that we are trying to connect to, and by speeding up the autoconnect algorithm if we don't have 3 connections (in progress) yet. --- src/net.c | 4 ++ src/protocol_key.c | 11 ++++ test/Makefile.am | 9 +++- test/trio2.c | 132 +++++++++++++++++++++++++++++++++++++++++++++ test/trio2.test | 4 ++ 5 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 test/trio2.c create mode 100755 test/trio2.test diff --git a/src/net.c b/src/net.c index a1cccbdf..a42d933b 100644 --- a/src/net.c +++ b/src/net.c @@ -585,6 +585,10 @@ static void periodic_handler(event_loop_t *loop, void *data) { terminate_connection(mesh, disconnect_from->connection, disconnect_from->connection->status.active); } + // reduce timeout if we don't have enough connections + outgoings + if(cur_connects + mesh->outgoings->count < 3) { + timeout = 1; + } // done! diff --git a/src/protocol_key.c b/src/protocol_key.c index c1ffe322..64a0ce8f 100644 --- a/src/protocol_key.c +++ b/src/protocol_key.c @@ -133,6 +133,17 @@ static bool req_key_ext_h(meshlink_handle_t *mesh, connection_t *c, const char * logger(mesh, MESHLINK_INFO, "Learned ECDSA public key from %s", from->name); from->status.dirty = true; + + /* If we are trying to form an outgoing connection to this node, retry immediately */ + for list_each(outgoing_t, outgoing, mesh->outgoings) { + if(outgoing->node == from && outgoing->ev.cb) { + outgoing->timeout = 0; + timeout_set(&mesh->loop, &outgoing->ev, &(struct timeval) { + 0, 0 + }); + } + } + return true; } diff --git a/test/Makefile.am b/test/Makefile.am index 45ad064c..edeb1a55 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -10,7 +10,8 @@ TESTS = \ import-export.test \ invite-join.test \ sign-verify.test \ - trio.test + trio.test \ + trio2.test if BLACKBOX_TESTS SUBDIRS = blackbox @@ -34,7 +35,8 @@ check_PROGRAMS = \ import-export \ invite-join \ sign-verify \ - trio + trio \ + trio2 if INSTALL_TESTS bin_PROGRAMS = $(check_PROGRAMS) @@ -78,3 +80,6 @@ sign_verify_LDADD = ../src/libmeshlink.la trio_SOURCES = trio.c trio_LDADD = ../src/libmeshlink.la + +trio2_SOURCES = trio2.c +trio2_LDADD = ../src/libmeshlink.la diff --git a/test/trio2.c b/test/trio2.c new file mode 100644 index 00000000..d9b3a0f9 --- /dev/null +++ b/test/trio2.c @@ -0,0 +1,132 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#include "meshlink.h" +#include "devtools.h" +#include "utils.h" + +static void log_cb(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *text) { + (void)mesh; + + static struct timeval tv0; + struct timeval tv; + + if(tv0.tv_sec == 0) { + gettimeofday(&tv0, NULL); + } + + gettimeofday(&tv, NULL); + fprintf(stderr, "%u.%.03u ", (unsigned int)(tv.tv_sec - tv0.tv_sec), (unsigned int)tv.tv_usec / 1000); + + if(mesh) { + fprintf(stderr, "(%s) ", mesh->name); + } + + fprintf(stderr, "[%d] %s\n", level, text); +} + +static bool received = false; + +static void receive_cb(meshlink_handle_t *mesh, meshlink_node_t *source, const void *data, size_t len) { + (void)mesh; + (void)source; + + fprintf(stderr, "RECEIVED SOMETHING\n"); + + if(len == 5 && !memcmp(data, "Hello", 5)) { + received = true; + } +} + +int main() { + // Create three instances. + + const char *name[3] = {"foo", "bar", "baz"}; + meshlink_handle_t *mesh[3]; + char *data[3]; + + for(int i = 0; i < 3; i++) { + char *path; + int ret_val; + (void)ret_val; + ret_val = asprintf(&path, "trio2_conf.%d", i); + assert(path); + + mesh[i] = meshlink_open(path, name[i], "trio2", DEV_CLASS_BACKBONE); + assert(mesh[i]); + + meshlink_add_address(mesh[i], "localhost"); + + data[i] = meshlink_export(mesh[i]); + assert(data[i]); + } + + meshlink_set_log_cb(mesh[1], MESHLINK_DEBUG, log_cb); + + // first node knows the two other nodes + + for(int i = 1; i < 3; i++) { + assert(meshlink_import(mesh[i], data[0])); + assert(meshlink_import(mesh[0], data[i])); + + assert(meshlink_get_node(mesh[i], name[0])); + assert(meshlink_get_node(mesh[0], name[i])); + } + + // second and third node should not know each other yet + + assert(!meshlink_get_node(mesh[1], name[2])); + assert(!meshlink_get_node(mesh[2], name[1])); + + // start the nodes + + for(int i = 0; i < 3; i++) { + assert(meshlink_start(mesh[i])); + } + + // the nodes should now learn about each other + + assert_after(meshlink_get_node(mesh[1], name[2]), 5); + assert_after(meshlink_get_node(mesh[2], name[1]), 5); + + // Check that the second and third node autoconnect to each other + + devtool_edge_t *edges = NULL; + size_t nedges = 0; + assert_after((edges = devtool_get_all_edges(mesh[1], edges, &nedges), nedges == 3), 15); + + // Stop the nodes nodes + + for(int i = 0; i < 3; i++) { + meshlink_stop(mesh[i]); + } + + // Start just the other two nodes + + meshlink_set_log_cb(mesh[1], MESHLINK_DEBUG, log_cb); + + for(int i = 1; i < 3; i++) { + assert(meshlink_start(mesh[i])); + } + + assert(meshlink_get_node(mesh[1], name[2])); + assert(meshlink_get_node(mesh[2], name[1])); + + // Communication should still be possible + + received = false; + meshlink_set_receive_cb(mesh[1], receive_cb); + assert_after((meshlink_send(mesh[2], meshlink_get_node(mesh[2], name[1]), "Hello", 5), received), 25); + + // Clean up. + + for(int i = 0; i < 3; i++) { + meshlink_close(mesh[i]); + } +} diff --git a/test/trio2.test b/test/trio2.test new file mode 100755 index 00000000..426ba501 --- /dev/null +++ b/test/trio2.test @@ -0,0 +1,4 @@ +#!/bin/sh + +rm -Rf trio2_conf.* +./trio2 -- 2.39.2