From 664466227602b6aabd4f601cf57183bbfa45bc08 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sat, 19 Jun 2021 22:43:17 +0200 Subject: [PATCH] Remove support for multiple connections. --- examples/chat.c | 27 --- src/connection.c | 25 +-- src/meshlink.c | 269 ++----------------------- src/meshlink_internal.h | 7 +- src/meta.c | 6 +- src/net.c | 430 +--------------------------------------- src/net_setup.c | 10 +- src/net_socket.c | 43 ++-- src/node.c | 41 ++-- src/protocol_auth.c | 36 ---- src/protocol_key.c | 8 +- 11 files changed, 97 insertions(+), 805 deletions(-) diff --git a/examples/chat.c b/examples/chat.c index bf31709..5d06538 100644 --- a/examples/chat.c +++ b/examples/chat.c @@ -41,9 +41,6 @@ static void node_status(meshlink_handle_t *mesh, meshlink_node_t *node, bool rea } } -static meshlink_node_t **nodes; -static size_t nnodes; - static void parse_command(meshlink_handle_t *mesh, char *buf) { char *arg = strchr(buf, ' '); @@ -69,30 +66,6 @@ static void parse_command(meshlink_handle_t *mesh, char *buf) { fprintf(stderr, "Could not restart MeshLink: %s\n", meshlink_strerror(meshlink_errno)); exit(1); } - } else if(!strcasecmp(buf, "who")) { - if(!arg) { - nodes = meshlink_get_all_nodes(mesh, nodes, &nnodes); - - if(!nnodes) { - fprintf(stderr, "Could not get list of nodes: %s\n", meshlink_strerror(meshlink_errno)); - } else { - printf("%zu known nodes:", nnodes); - - for(size_t i = 0; i < nnodes; i++) { - printf(" %s", nodes[i]->name); - } - - printf("\n"); - } - } else { - meshlink_node_t *node = meshlink_get_node(mesh, arg); - - if(!node) { - fprintf(stderr, "Error looking up '%s': %s\n", arg, meshlink_strerror(meshlink_errno)); - } else { - printf("Node %s found\n", arg); - } - } } else if(!strcasecmp(buf, "quit")) { printf("Bye!\n"); fclose(stdin); diff --git a/src/connection.c b/src/connection.c index 9cc6491..97e3918 100644 --- a/src/connection.c +++ b/src/connection.c @@ -29,25 +29,15 @@ #include "xalloc.h" void init_connections(meshlink_handle_t *mesh) { - assert(!mesh->connections); - assert(!mesh->everyone); - - mesh->connections = list_alloc((list_action_t) free_connection); - mesh->everyone = new_connection(); - mesh->everyone->name = xstrdup("mesh->everyone"); + assert(!mesh->connection); } void exit_connections(meshlink_handle_t *mesh) { - if(mesh->connections) { - list_delete_list(mesh->connections); - } - - if(mesh->everyone) { - free_connection(mesh->everyone); + if(mesh->connection) { + free_connection(mesh->connection); } - mesh->connections = NULL; - mesh->everyone = NULL; + mesh->connection = NULL; } connection_t *new_connection(void) { @@ -78,14 +68,17 @@ void free_connection(connection_t *c) { void connection_add(meshlink_handle_t *mesh, connection_t *c) { assert(c); + assert(!mesh->connection); c->mesh = mesh; - list_insert_tail(mesh->connections, c); + mesh->connection = c; } void connection_del(meshlink_handle_t *mesh, connection_t *c) { assert(c); + assert(mesh->connection == c); io_del(&mesh->loop, &c->io); - list_delete(mesh->connections, c); + free(mesh->connection); + mesh->connection = NULL; } diff --git a/src/meshlink.c b/src/meshlink.c index 8b3b841..19d9fdc 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -488,32 +488,17 @@ static bool ecdsa_keygen(meshlink_handle_t *mesh) { return true; } -static bool timespec_lt(const struct timespec *a, const struct timespec *b) { - if(a->tv_sec == b->tv_sec) { - return a->tv_nsec < b->tv_nsec; - } else { - return a->tv_sec < b->tv_sec; - } -} - static struct timespec idle(event_loop_t *loop, void *data) { (void)loop; meshlink_handle_t *mesh = data; - struct timespec t, tmin = {3600, 0}; - - for splay_each(node_t, n, mesh->nodes) { - if(!n->utcp) { - continue; - } - t = utcp_timeout(n->utcp); - - if(timespec_lt(&t, &tmin)) { - tmin = t; - } + if(mesh->peer && mesh->peer->utcp) { + return utcp_timeout(mesh->peer->utcp); + } else { + return (struct timespec) { + 3600, 0 + }; } - - return tmin; } static bool meshlink_setup(meshlink_handle_t *mesh) { @@ -1156,11 +1141,10 @@ bool meshlink_start(meshlink_handle_t *mesh) { } // Reset node connection timers - for splay_each(node_t, n, mesh->nodes) { - n->last_connect_try = 0; + if(mesh->peer) { + mesh->peer->last_connect_try = 0; } - //Check that a valid name is set if(!mesh->name) { logger(mesh, MESHLINK_ERROR, "No name given!\n"); @@ -1229,25 +1213,17 @@ void meshlink_stop(meshlink_handle_t *mesh) { } // Close all metaconnections - if(mesh->connections) { - for(list_node_t *node = mesh->connections->head, *next; node; node = next) { - next = node->next; - connection_t *c = node->data; - c->outgoing = NULL; - terminate_connection(mesh, c, false); - } + if(mesh->connection) { + mesh->connection->outgoing = NULL; + terminate_connection(mesh, mesh->connection, false); } exit_outgoings(mesh); // Try to write out any changed node config files, ignore errors at this point. - if(mesh->nodes) { - for splay_each(node_t, n, mesh->nodes) { - if(n->status.dirty) { - if(!node_write_config(mesh, n, false)) { - // ignore - } - } + if(mesh->peer && mesh->peer->status.dirty) { + if(!node_write_config(mesh, mesh->peer, false)) { + // ignore } } @@ -1703,149 +1679,6 @@ meshlink_node_t *meshlink_get_node(meshlink_handle_t *mesh, const char *name) { return (meshlink_node_t *)n; } -meshlink_node_t **meshlink_get_all_nodes(meshlink_handle_t *mesh, meshlink_node_t **nodes, size_t *nmemb) { - if(!mesh || !nmemb || (*nmemb && !nodes)) { - meshlink_errno = MESHLINK_EINVAL; - return NULL; - } - - meshlink_node_t **result; - - //lock mesh->nodes - if(pthread_mutex_lock(&mesh->mutex) != 0) { - abort(); - } - - *nmemb = mesh->nodes->count; - result = realloc(nodes, *nmemb * sizeof(*nodes)); - - if(result) { - meshlink_node_t **p = result; - - for splay_each(node_t, n, mesh->nodes) { - *p++ = (meshlink_node_t *)n; - } - } else { - *nmemb = 0; - free(nodes); - meshlink_errno = MESHLINK_ENOMEM; - } - - pthread_mutex_unlock(&mesh->mutex); - - return result; -} - -static meshlink_node_t **meshlink_get_all_nodes_by_condition(meshlink_handle_t *mesh, const void *condition, meshlink_node_t **nodes, size_t *nmemb, search_node_by_condition_t search_node) { - meshlink_node_t **result; - - if(pthread_mutex_lock(&mesh->mutex) != 0) { - abort(); - } - - *nmemb = 0; - - for splay_each(node_t, n, mesh->nodes) { - if(search_node(n, condition)) { - ++*nmemb; - } - } - - if(*nmemb == 0) { - free(nodes); - pthread_mutex_unlock(&mesh->mutex); - return NULL; - } - - result = realloc(nodes, *nmemb * sizeof(*nodes)); - - if(result) { - meshlink_node_t **p = result; - - for splay_each(node_t, n, mesh->nodes) { - if(search_node(n, condition)) { - *p++ = (meshlink_node_t *)n; - } - } - } else { - *nmemb = 0; - free(nodes); - meshlink_errno = MESHLINK_ENOMEM; - } - - pthread_mutex_unlock(&mesh->mutex); - - return result; -} - -static bool search_node_by_dev_class(const node_t *node, const void *condition) { - dev_class_t *devclass = (dev_class_t *)condition; - - if(*devclass == (dev_class_t)node->devclass) { - return true; - } - - return false; -} - - -struct time_range { - time_t start; - time_t end; -}; - -meshlink_node_t **meshlink_get_all_nodes_by_dev_class(meshlink_handle_t *mesh, dev_class_t devclass, meshlink_node_t **nodes, size_t *nmemb) { - if(!mesh || devclass < 0 || devclass >= DEV_CLASS_COUNT || !nmemb) { - meshlink_errno = MESHLINK_EINVAL; - return NULL; - } - - return meshlink_get_all_nodes_by_condition(mesh, &devclass, nodes, nmemb, search_node_by_dev_class); -} - -dev_class_t meshlink_get_node_dev_class(meshlink_handle_t *mesh, meshlink_node_t *node) { - if(!mesh || !node) { - meshlink_errno = MESHLINK_EINVAL; - return -1; - } - - dev_class_t devclass; - - if(pthread_mutex_lock(&mesh->mutex) != 0) { - abort(); - } - - devclass = ((node_t *)node)->devclass; - - pthread_mutex_unlock(&mesh->mutex); - - return devclass; -} - -bool meshlink_get_node_reachability(struct meshlink_handle *mesh, struct meshlink_node *node, time_t *last_reachable, time_t *last_unreachable) { - if(!mesh || !node) { - meshlink_errno = MESHLINK_EINVAL; - return NULL; - } - - node_t *n = (node_t *)node; - bool reachable; - - if(pthread_mutex_lock(&mesh->mutex) != 0) { - abort(); - } - - reachable = n->status.reachable && !n->status.blacklisted; - - // TODO: handle reachable times? - (void)last_reachable; - (void)last_unreachable; - - pthread_mutex_unlock(&mesh->mutex); - - return reachable; -} - bool meshlink_sign(meshlink_handle_t *mesh, const void *data, size_t len, void *signature, size_t *siglen) { logger(mesh, MESHLINK_DEBUG, "meshlink_sign(%p, %zu, %p, %p)", data, len, signature, (void *)siglen); @@ -2017,7 +1850,7 @@ bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) { } // Refuse to join a mesh if we are already part of one. We are part of one if we know at least one other node. - if(mesh->nodes->count > 1) { + if(mesh->peer) { logger(mesh, MESHLINK_ERROR, "Already part of an existing mesh\n"); meshlink_errno = MESHLINK_EINVAL; goto exit; @@ -2429,66 +2262,6 @@ bool meshlink_import(meshlink_handle_t *mesh, const char *data) { return true; } -bool meshlink_forget_node(meshlink_handle_t *mesh, meshlink_node_t *node) { - logger(mesh, MESHLINK_DEBUG, "meshlink_forget_node(%s)", node ? node->name : "(null)"); - - if(!mesh || !node) { - meshlink_errno = MESHLINK_EINVAL; - return false; - } - - node_t *n = (node_t *)node; - - if(pthread_mutex_lock(&mesh->mutex) != 0) { - abort(); - } - - /* Check that the node is not reachable */ - if(n->status.reachable || n->connection) { - pthread_mutex_unlock(&mesh->mutex); - logger(mesh, MESHLINK_WARNING, "Could not forget %s: still reachable", n->name); - return false; - } - - /* Check that we don't have any active UTCP connections */ - if(n->utcp && utcp_is_active(n->utcp)) { - pthread_mutex_unlock(&mesh->mutex); - logger(mesh, MESHLINK_WARNING, "Could not forget %s: active UTCP connections", n->name); - return false; - } - - /* Check that we have no active connections to this node */ - for list_each(connection_t, c, mesh->connections) { - if(c->node == n) { - pthread_mutex_unlock(&mesh->mutex); - logger(mesh, MESHLINK_WARNING, "Could not forget %s: active connection", n->name); - return false; - } - } - - /* Remove any pending outgoings to this node */ - if(mesh->outgoings) { - for list_each(outgoing_t, outgoing, mesh->outgoings) { - if(outgoing->node == n) { - list_delete_node(mesh->outgoings, list_node); - } - } - } - - /* Delete the config file for this node */ - if(!config_delete(mesh, "current", n->name)) { - pthread_mutex_unlock(&mesh->mutex); - return false; - } - - /* Delete the node struct and any remaining edges referencing this node */ - node_del(mesh, n); - - pthread_mutex_unlock(&mesh->mutex); - - return config_sync(mesh, "current"); -} - /* Hint that a hostname may be found at an address * See header file for detailed comment. */ @@ -2863,12 +2636,10 @@ void meshlink_set_channel_accept_cb(meshlink_handle_t *mesh, meshlink_channel_ac mesh->channel_accept_cb = cb; mesh->receive_cb = channel_receive; - for splay_each(node_t, n, mesh->nodes) { - if(!n->utcp && n != mesh->self) { - n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n); - utcp_set_mtu(n->utcp, n->mtu - sizeof(meshlink_packethdr_t)); - utcp_set_retransmit_cb(n->utcp, channel_retransmit); - } + if(mesh->peer) { + mesh->peer->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, mesh->peer); + utcp_set_mtu(mesh->peer->utcp, mesh->peer->mtu - sizeof(meshlink_packethdr_t)); + utcp_set_retransmit_cb(mesh->peer->utcp, channel_retransmit); } pthread_mutex_unlock(&mesh->mutex); @@ -3514,7 +3285,7 @@ void meshlink_set_storage_policy(struct meshlink_handle *mesh, meshlink_storage_ void handle_network_change(meshlink_handle_t *mesh, bool online) { (void)online; - if(!mesh->connections || !mesh->loop.running) { + if(!mesh->loop.running) { return; } diff --git a/src/meshlink_internal.h b/src/meshlink_internal.h index b1caa0a..fc4683e 100644 --- a/src/meshlink_internal.h +++ b/src/meshlink_internal.h @@ -93,10 +93,9 @@ struct meshlink_handle { meshlink_queue_t outpacketqueue; signal_t datafromapp; - struct splay_tree_t *nodes; - - struct list_t *connections; - struct list_t *outgoings; + struct node_t *peer; + struct connection_t *connection; + struct outgoing_t *outgoing; // Meta-connection-related members struct splay_tree_t *past_request_tree; diff --git a/src/meta.c b/src/meta.c index d79dc6e..32e3de2 100644 --- a/src/meta.c +++ b/src/meta.c @@ -64,9 +64,9 @@ void broadcast_meta(meshlink_handle_t *mesh, connection_t *from, const char *buf assert(buffer); assert(length); - for list_each(connection_t, c, mesh->connections) - if(c != from && c->status.active) { - send_meta(mesh, c, buffer, length); + if(mesh->connection) + if(mesh->connection != from && mesh->connection->status.active) { + send_meta(mesh, mesh->connection, buffer, length); } } diff --git a/src/net.c b/src/net.c index 60c16cb..c05baf7 100644 --- a/src/net.c +++ b/src/net.c @@ -90,7 +90,7 @@ static void timeout_handler(event_loop_t *loop, void *data) { meshlink_handle_t *mesh = loop->data; logger(mesh, MESHLINK_DEBUG, "timeout_handler()"); - for list_each(connection_t, c, mesh->connections) { + for(connection_t *c = mesh->connection; c; c = NULL) { int pingtimeout = c->node ? mesh->dev_class_traits[c->node->devclass].pingtimeout : default_timeout; int pinginterval = c->node ? mesh->dev_class_traits[c->node->devclass].pinginterval : default_interval; @@ -144,186 +144,6 @@ static void timeout_handler(event_loop_t *loop, void *data) { }); } -// devclass asc, last_successfull_connection desc -static int node_compare_devclass_asc_lsc_desc(const void *a, const void *b) { - const node_t *na = a, *nb = b; - - if(na->devclass < nb->devclass) { - return -1; - } - - if(na->devclass > nb->devclass) { - return 1; - } - - if(na->last_successfull_connection == nb->last_successfull_connection) { - return 0; - } - - if(na->last_successfull_connection == 0 || na->last_successfull_connection > nb->last_successfull_connection) { - return -1; - } - - if(nb->last_successfull_connection == 0 || na->last_successfull_connection < nb->last_successfull_connection) { - return 1; - } - - if(na < nb) { - return -1; - } - - if(na > nb) { - return 1; - } - - return 0; -} - -// last_successfull_connection desc -static int node_compare_lsc_desc(const void *a, const void *b) { - const node_t *na = a, *nb = b; - - if(na->last_successfull_connection == nb->last_successfull_connection) { - return 0; - } - - if(na->last_successfull_connection == 0 || na->last_successfull_connection > nb->last_successfull_connection) { - return -1; - } - - if(nb->last_successfull_connection == 0 || na->last_successfull_connection < nb->last_successfull_connection) { - return 1; - } - - if(na < nb) { - return -1; - } - - if(na > nb) { - return 1; - } - - return 0; -} - -// devclass desc -static int node_compare_devclass_desc(const void *a, const void *b) { - const node_t *na = a, *nb = b; - - if(na->devclass < nb->devclass) { - return -1; - } - - if(na->devclass > nb->devclass) { - return 1; - } - - if(na < nb) { - return -1; - } - - if(na > nb) { - return 1; - } - - return 0; -} - - -/* - -autoconnect() -{ - timeout = 5 - - // find the best one for initial connect - - if cur < min - newcon = - first from nodes - where dclass <= my.dclass and !connection and (timestamp - last_retry) > retry_timeout - order by dclass asc, last_connection desc - if newcon - timeout = 0 - goto connect - - - // find better nodes to connect to: in case we have less than min connections within [BACKBONE, i] and there are nodes which we are not connected to within the range - - if min <= cur < max - j = 0 - for i = BACKBONE to my.dclass - j += count(from connections where node.dclass = i) - if j < min - newcon = - first from nodes - where dclass = i and !connection and (timestamp - last_retry) > retry_timeout - order by last_connection desc - if newcon - goto connect - else - break - - - // heal partitions - - if min <= cur < max - newcon = - first from nodes - where dclass <= my.dclass and !reachable and (timestamp - last_retry) > retry_timeout - order by dclass asc, last_connection desc - if newcon - goto connect - - - // connect - -connect: - if newcon - connect newcon - - - // disconnect outgoing connections in case we have more than min connections within [BACKBONE, i] and there are nodes which we are connected to within the range [i, PORTABLE] - - if min < cur <= max - j = 0 - for i = BACKBONE to my.dclass - j += count(from connections where node.dclass = i) - if min < j - delcon = - first from nodes - where dclass >= i and outgoing_connection - order by dclass desc - if disconnect - goto disconnect - else - break - - - // disconnect connections in case we have more than enough connections - - if max < cur - delcon = - first from nodes - where outgoing_connection - order by dclass desc - goto disconnect - - // disconnect - -disconnect - if delcon - disconnect delcon - - - // next iteration - next (timeout, autoconnect) - -} - -*/ - - static void periodic_handler(event_loop_t *loop, void *data) { meshlink_handle_t *mesh = loop->data; @@ -356,246 +176,14 @@ static void periodic_handler(event_loop_t *loop, void *data) { /* Check if we need to make or break connections. */ - if(mesh->nodes->count > 1) { - - logger(mesh, MESHLINK_DEBUG, "--- autoconnect begin ---"); - - int retry_timeout = min(mesh->nodes->count * default_timeout, 60); - - logger(mesh, MESHLINK_DEBUG, "* devclass = %d", mesh->devclass); - logger(mesh, MESHLINK_DEBUG, "* nodes = %d", mesh->nodes->count); - logger(mesh, MESHLINK_DEBUG, "* retry_timeout = %d", retry_timeout); - - - // connect disconnect nodes - - node_t *connect_to = NULL; - node_t *disconnect_from = NULL; - - - // get cur_connects - - unsigned int cur_connects = 0; - - for list_each(connection_t, c, mesh->connections) { - if(c->status.active) { - cur_connects += 1; - } - } - - logger(mesh, MESHLINK_DEBUG, "* cur_connects = %d", cur_connects); - logger(mesh, MESHLINK_DEBUG, "* outgoings = %d", mesh->outgoings->count); - - // get min_connects and max_connects - - unsigned int min_connects = mesh->dev_class_traits[mesh->devclass].min_connects; - unsigned int max_connects = mesh->dev_class_traits[mesh->devclass].max_connects; - - logger(mesh, MESHLINK_DEBUG, "* min_connects = %d", min_connects); - logger(mesh, MESHLINK_DEBUG, "* max_connects = %d", max_connects); - - // find the best one for initial connect - - if(cur_connects < min_connects) { - splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_asc_lsc_desc, NULL); - - for splay_each(node_t, n, mesh->nodes) { - logger(mesh, MESHLINK_DEBUG, "* %s->devclass = %d", n->name, n->devclass); - - if(n != mesh->self && n->devclass <= mesh->devclass && !n->connection && !n->status.blacklisted && (n->last_connect_try == 0 || (mesh->loop.now.tv_sec - n->last_connect_try) > retry_timeout)) { - splay_insert(nodes, n); - } - } - - if(nodes->head) { - //timeout = 0; - connect_to = (node_t *)nodes->head->data; - - logger(mesh, MESHLINK_DEBUG, "* found best one for initial connect: %s", connect_to->name); - } else { - logger(mesh, MESHLINK_DEBUG, "* could not find node for initial connect"); - } - - splay_delete_tree(nodes); - } - - - // find better nodes to connect to - - if(!connect_to && min_connects <= cur_connects && cur_connects < max_connects) { - unsigned int connects = 0; - - for(dev_class_t devclass = 0; devclass <= mesh->devclass; ++devclass) { - for list_each(connection_t, c, mesh->connections) { - if(c->status.active && c->node && c->node->devclass == devclass) { - connects += 1; - } - } - - if(connects < min_connects) { - splay_tree_t *nodes = splay_alloc_tree(node_compare_lsc_desc, NULL); - - for splay_each(node_t, n, mesh->nodes) { - if(n != mesh->self && n->devclass == devclass && !n->connection && !n->status.blacklisted && (n->last_connect_try == 0 || (mesh->loop.now.tv_sec - n->last_connect_try) > retry_timeout)) { - splay_insert(nodes, n); - } - } - - if(nodes->head) { - logger(mesh, MESHLINK_DEBUG, "* found better node"); - connect_to = (node_t *)nodes->head->data; - - splay_delete_tree(nodes); - break; - } - - splay_delete_tree(nodes); - } else { - break; - } - } - - if(!connect_to) { - logger(mesh, MESHLINK_DEBUG, "* could not find better nodes"); - } - } - - - // heal partitions - - if(!connect_to && min_connects <= cur_connects && cur_connects < max_connects) { - splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_asc_lsc_desc, NULL); - - for splay_each(node_t, n, mesh->nodes) { - if(n != mesh->self && n->devclass <= mesh->devclass && !n->status.reachable && !n->status.blacklisted && (n->last_connect_try == 0 || (mesh->loop.now.tv_sec - n->last_connect_try) > retry_timeout)) { - splay_insert(nodes, n); - } - } - - if(nodes->head) { - logger(mesh, MESHLINK_DEBUG, "* try to heal partition"); - connect_to = (node_t *)nodes->head->data; - } else { - logger(mesh, MESHLINK_DEBUG, "* could not find nodes for partition healing"); - } - - splay_delete_tree(nodes); - } - - - // perform connect - - if(connect_to && !connect_to->connection) { - connect_to->last_connect_try = mesh->loop.now.tv_sec; - logger(mesh, MESHLINK_DEBUG, "Autoconnect trying to connect to %s", connect_to->name); - - /* check if there is already a connection attempt to this node */ - bool skip = false; - - for list_each(outgoing_t, outgoing, mesh->outgoings) { - if(outgoing->node == connect_to) { - logger(mesh, MESHLINK_DEBUG, "* skip autoconnect since it is an outgoing connection already"); - skip = true; - break; - } - } - - if(!connect_to->status.reachable && !node_read_public_key(mesh, connect_to)) { - logger(mesh, MESHLINK_DEBUG, "* skip autoconnect since we don't know this node's public key"); - skip = true; - } - - if(!skip) { - logger(mesh, MESHLINK_DEBUG, "Autoconnecting to %s", connect_to->name); - outgoing_t *outgoing = xzalloc(sizeof(outgoing_t)); - outgoing->node = connect_to; - list_insert_tail(mesh->outgoings, outgoing); - setup_outgoing_connection(mesh, outgoing); - } - } - - - // disconnect suboptimal outgoing connections - - if(min_connects < cur_connects /*&& cur_connects <= max_connects*/) { - unsigned int connects = 0; - - for(dev_class_t devclass = 0; devclass <= mesh->devclass; ++devclass) { - for list_each(connection_t, c, mesh->connections) { - if(c->status.active && c->node && c->node->devclass == devclass) { - connects += 1; - } - } - - if(min_connects < connects) { - splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_desc, NULL); - - for list_each(connection_t, c, mesh->connections) { - if(c->outgoing && c->node && c->node->devclass >= devclass) { - splay_insert(nodes, c->node); - } - } - - if(nodes->head) { - logger(mesh, MESHLINK_DEBUG, "* disconnect suboptimal outgoing connection"); - disconnect_from = (node_t *)nodes->head->data; - } - - splay_delete_tree(nodes); - break; - } - } - - if(!disconnect_from) { - logger(mesh, MESHLINK_DEBUG, "* no suboptimal outgoing connections"); - } - } - - - // disconnect connections (too many connections) - - if(!disconnect_from && max_connects < cur_connects) { - splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_desc, NULL); - - for list_each(connection_t, c, mesh->connections) { - if(c->status.active && c->node) { - splay_insert(nodes, c->node); - } - } - - if(nodes->head) { - logger(mesh, MESHLINK_DEBUG, "* disconnect connection (too many connections)"); - - //timeout = 0; - disconnect_from = (node_t *)nodes->head->data; - } else { - logger(mesh, MESHLINK_DEBUG, "* no node we want to disconnect, even though we have too many connections"); - } - - splay_delete_tree(nodes); - } - - - // perform disconnect - - if(disconnect_from && disconnect_from->connection) { - logger(mesh, MESHLINK_DEBUG, "Autodisconnecting from %s", disconnect_from->connection->name); - list_delete(mesh->outgoings, disconnect_from->connection->outgoing); - disconnect_from->connection->outgoing = NULL; - 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! - - logger(mesh, MESHLINK_DEBUG, "--- autoconnect end ---"); + if(mesh->peer && !mesh->connection && !mesh->outgoing) { + logger(mesh, MESHLINK_DEBUG, "Autoconnecting to %s", mesh->peer->name); + mesh->outgoing = xzalloc(sizeof(outgoing_t)); + mesh->outgoing->node = mesh->peer; + setup_outgoing_connection(mesh, mesh->outgoing); } - for splay_each(node_t, n, mesh->nodes) { + for(node_t *n = mesh->peer; n; n = NULL) { if(n->status.dirty) { if(!node_write_config(mesh, n, false)) { logger(mesh, MESHLINK_DEBUG, "Could not update %s", n->name); @@ -632,7 +220,7 @@ void handle_meta_connection_data(meshlink_handle_t *mesh, connection_t *c) { void retry(meshlink_handle_t *mesh) { /* Reset the reconnection timers for all outgoing connections */ - for list_each(outgoing_t, outgoing, mesh->outgoings) { + for(outgoing_t *outgoing = mesh->outgoing; outgoing; outgoing = NULL) { outgoing->timeout = 0; if(outgoing->ev.cb) { @@ -644,7 +232,7 @@ void retry(meshlink_handle_t *mesh) { /* For active connections, check if their addresses are still valid. * If yes, reset their ping timers, otherwise terminate them. */ - for list_each(connection_t, c, mesh->connections) { + for(connection_t *c = mesh->connection; c; c = NULL) { if(!c->status.active) { continue; } diff --git a/src/net_setup.c b/src/net_setup.c index 4369692..9639280 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -355,13 +355,9 @@ bool setup_network(meshlink_handle_t *mesh) { close all open network connections */ void close_network_connections(meshlink_handle_t *mesh) { - if(mesh->connections) { - for(list_node_t *node = mesh->connections->head, *next; node; node = next) { - next = node->next; - connection_t *c = node->data; - c->outgoing = NULL; - terminate_connection(mesh, c, false); - } + if(mesh->connection) { + mesh->connection->outgoing = NULL; + terminate_connection(mesh, mesh->connection, false); } exit_requests(mesh); diff --git a/src/net_socket.c b/src/net_socket.c index fe7bf3a..d4b6208 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -289,6 +289,22 @@ static bool get_next_outgoing_address(meshlink_handle_t *mesh, outgoing_t *outgo return false; } +static void free_outgoing(outgoing_t *outgoing) { + meshlink_handle_t *mesh = outgoing->node->mesh; + + timeout_del(&mesh->loop, &outgoing->ev); + + if(outgoing->ai) { + if(outgoing->state == OUTGOING_RECENT || outgoing->state == OUTGOING_KNOWN) { + free_known_addresses(outgoing->ai); + } else { + freeaddrinfo(outgoing->ai); + } + } + + free(outgoing); +} + void do_outgoing_connection(meshlink_handle_t *mesh, outgoing_t *outgoing) { begin: @@ -297,7 +313,8 @@ begin: /* We are waiting for a callback from the ADNS thread */ } else if(outgoing->state == OUTGOING_NO_KNOWN_ADDRESSES) { logger(mesh, MESHLINK_ERROR, "No known addresses for %s", outgoing->node->name); - list_delete(mesh->outgoings, outgoing); + free_outgoing(outgoing); + mesh->outgoing = NULL; } else { logger(mesh, MESHLINK_ERROR, "Could not set up a meta connection to %s", outgoing->node->name); retry_outgoing(mesh, outgoing); @@ -409,29 +426,13 @@ void setup_outgoing_connection(meshlink_handle_t *mesh, outgoing_t *outgoing) { do_outgoing_connection(mesh, outgoing); } -static void free_outgoing(outgoing_t *outgoing) { - meshlink_handle_t *mesh = outgoing->node->mesh; - - timeout_del(&mesh->loop, &outgoing->ev); - - if(outgoing->ai) { - if(outgoing->state == OUTGOING_RECENT || outgoing->state == OUTGOING_KNOWN) { - free_known_addresses(outgoing->ai); - } else { - freeaddrinfo(outgoing->ai); - } - } - - free(outgoing); -} - void init_outgoings(meshlink_handle_t *mesh) { - mesh->outgoings = list_alloc((list_action_t)free_outgoing); + mesh->outgoing = NULL; } void exit_outgoings(meshlink_handle_t *mesh) { - if(mesh->outgoings) { - list_delete_list(mesh->outgoings); - mesh->outgoings = NULL; + if(mesh->outgoing) { + free_outgoing(mesh->outgoing); + mesh->outgoing = NULL; } } diff --git a/src/node.c b/src/node.c index 160bcb3..1c1c864 100644 --- a/src/node.c +++ b/src/node.c @@ -25,24 +25,19 @@ #include "net.h" #include "netutl.h" #include "node.h" -#include "splay_tree.h" #include "utils.h" #include "xalloc.h" -static int node_compare(const node_t *a, const node_t *b) { - return strcmp(a->name, b->name); -} - void init_nodes(meshlink_handle_t *mesh) { - mesh->nodes = splay_alloc_tree((splay_compare_t) node_compare, (splay_action_t) free_node); + mesh->peer = NULL; } void exit_nodes(meshlink_handle_t *mesh) { - if(mesh->nodes) { - splay_delete_tree(mesh->nodes); + if(mesh->peer) { + free_node(mesh->peer); } - mesh->nodes = NULL; + mesh->peer = NULL; } node_t *new_node(void) { @@ -76,22 +71,34 @@ void free_node(node_t *n) { } void node_add(meshlink_handle_t *mesh, node_t *n) { + if(n == mesh->self) { + return; + } + + assert(!mesh->peer); n->mesh = mesh; - splay_insert(mesh->nodes, n); + mesh->peer = n; } void node_del(meshlink_handle_t *mesh, node_t *n) { + if(n == mesh->self) { + return; + } + + assert(mesh->peer && mesh->peer == n); timeout_del(&mesh->loop, &n->mtutimeout); - splay_delete(mesh->nodes, n); + free_node(n); + mesh->peer = NULL; } node_t *lookup_node(meshlink_handle_t *mesh, const char *name) { - const node_t n = {.name = (char *)name}; - node_t *result; - - result = splay_search(mesh->nodes, &n); - - return result; + if(mesh->peer && !strcmp(name, mesh->peer->name)) { + return mesh->peer; + } else if(!strcmp(name, mesh->self->name)) { + return mesh->self; + } else { + return NULL; + } } bool node_add_recent_address(meshlink_handle_t *mesh, node_t *n, const sockaddr_t *sa) { diff --git a/src/protocol_auth.c b/src/protocol_auth.c index f46a4f4..5ee7a5f 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -173,23 +173,6 @@ bool ack_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { n = new_node(); n->name = xstrdup(c->name); node_add(mesh, n); - } else { - if(n->connection) { - /* Oh dear, we already have a connection to this node. */ - logger(mesh, MESHLINK_INFO, "Established a second connection with %s, closing old connection", n->connection->name); - - if(n->connection->outgoing) { - if(c->outgoing) { - logger(mesh, MESHLINK_WARNING, "Two outgoing connections to the same node!"); - } else { - c->outgoing = n->connection->outgoing; - } - - n->connection->outgoing = NULL; - } - - terminate_connection(mesh, n->connection, false); - } } n->devclass = devclass; @@ -213,25 +196,6 @@ bool ack_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { mesh->meta_status_cb(mesh, (meshlink_node_t *)n, true); } - /* Terminate any connections to this node that are not activated yet */ - - for list_each(connection_t, other, mesh->connections) { - if(!other->status.active && !strcmp(other->name, c->name)) { - if(other->outgoing) { - if(c->outgoing) { - logger(mesh, MESHLINK_WARNING, "Two outgoing connections to the same node!"); - } else { - c->outgoing = other->outgoing; - } - - other->outgoing = NULL; - } - - logger(mesh, MESHLINK_DEBUG, "Terminating pending second connection with %s", n->name); - terminate_connection(mesh, other, false); - } - } - /* TODO: Create an edge_t for this connection, send it */ /* Request a session key to jump start UDP traffic */ diff --git a/src/protocol_key.c b/src/protocol_key.c index de6b1e5..e89f8ec 100644 --- a/src/protocol_key.c +++ b/src/protocol_key.c @@ -182,10 +182,10 @@ static bool req_key_ext_h(meshlink_handle_t *mesh, connection_t *c, const char * } /* 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 timespec) { + if(mesh->outgoing) { + if(mesh->outgoing->node == from && mesh->outgoing->ev.cb) { + mesh->outgoing->timeout = 0; + timeout_set(&mesh->loop, &mesh->outgoing->ev, &(struct timespec) { 0, 0 }); } -- 2.39.2