}
}
-static meshlink_node_t **nodes;
-static size_t nnodes;
-
static void parse_command(meshlink_handle_t *mesh, char *buf) {
char *arg = strchr(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);
#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) {
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;
}
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) {
}
// 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");
}
// 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
}
}
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);
}
// 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;
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.
*/
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);
void handle_network_change(meshlink_handle_t *mesh, bool online) {
(void)online;
- if(!mesh->connections || !mesh->loop.running) {
+ if(!mesh->loop.running) {
return;
}
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;
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);
}
}
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;
});
}
-// 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;
/* 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);
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) {
/* 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;
}
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);
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:
/* 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);
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;
}
}
#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) {
}
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) {
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;
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 */
}
/* 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
});
}