X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fnet.c;h=1e04bc9ae685a9c0c100a18d6ac9ac2477cb6183;hb=89d675c474a6717d9daa8b5d9ff2c0f2c03666f9;hp=654a7813cee55fca752d9092458a9a0cd6bc9091;hpb=a021bf25db676353b8ea50740ce343962c3dddb9;p=meshlink diff --git a/src/net.c b/src/net.c index 654a7813..1e04bc9a 100644 --- a/src/net.c +++ b/src/net.c @@ -31,10 +31,13 @@ #include "protocol.h" #include "xalloc.h" +#include +#if !defined(min) static const int min(int a, int b) { return a < b ? a : b; } +#endif /* Terminate a connection: @@ -130,8 +133,8 @@ static void timeout_handler(event_loop_t *loop, void *data) { timeout_set(&mesh->loop, data, &(struct timeval){mesh->pingtimeout, rand() % 100000}); } -// devclass asc, last_connect_try desc -static int node_compare_devclass_asc_last_connect_try_desc(const void *a, const void *b) +// 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; @@ -141,30 +144,42 @@ static int node_compare_devclass_asc_last_connect_try_desc(const void *a, const if(na->devclass > nb->devclass) { return 1; } - if(na->last_connect_try == nb->last_connect_try) + if(na->last_successfull_connection == nb->last_successfull_connection) return 0; - if(nb->last_connect_try == 0 || na->last_connect_try < nb->last_connect_try) + 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->last_connect_try == 0 || na->last_connect_try > nb->last_connect_try) + if(na > nb) return 1; return 0; } -// last_connect_try desc -static int node_compare_last_connect_try_desc(const void *a, const void *b) +// 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_connect_try == nb->last_connect_try) + if(na->last_successfull_connection == nb->last_successfull_connection) return 0; - if(nb->last_connect_try == 0 || na->last_connect_try < nb->last_connect_try) + 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->last_connect_try == 0 || na->last_connect_try > nb->last_connect_try) + if(na > nb) return 1; return 0; @@ -181,10 +196,110 @@ static int node_compare_devclass_desc(const void *a, const void *b) 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; @@ -214,11 +329,15 @@ static void periodic_handler(event_loop_t *loop, void *data) { if(mesh->nodes->count > 1) { - logger(mesh, MESHLINK_INFO, "--- autoconnect begin ---"); - + logger(mesh, MESHLINK_DEBUG, "--- autoconnect begin ---"); int retry_timeout = min(mesh->nodes->count * 5, 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; @@ -231,43 +350,48 @@ static void periodic_handler(event_loop_t *loop, void *data) { for list_each(connection_t, c, mesh->connections) { - if(!c->status.remove_unused) + if(c->status.active) { cur_connects += 1; } } - logger(mesh, MESHLINK_INFO, "* cur_connects = %d", cur_connects); - + logger(mesh, MESHLINK_DEBUG, "* cur_connects = %d", cur_connects); + logger(mesh, MESHLINK_DEBUG, "* outgoings = %d", mesh->outgoings->count); // get min_connects and max_connects + assert(mesh->devclass >= 0 && mesh->devclass <= _DEV_CLASS_MAX); + int min_connects = dev_class_traits[mesh->devclass].min_connects; int max_connects = dev_class_traits[mesh->devclass].max_connects; - logger(mesh, MESHLINK_INFO, "* min_connects = %d", min_connects); - logger(mesh, MESHLINK_INFO, "* max_connects = %d", 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_last_connect_try_desc, NULL); + splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_asc_lsc_desc, NULL); for splay_each(node_t, n, mesh->nodes) { - if(n->devclass <= mesh->devclass && !n->connection && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout)) + logger(mesh, MESHLINK_DEBUG, "* n->devclass = %d", n->devclass); + if(n != mesh->self && n->devclass <= mesh->devclass && !n->connection && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout)) { splay_insert(nodes, n); } } if(nodes->head) { - logger(mesh, MESHLINK_INFO, "* found best one for initial connect"); + logger(mesh, MESHLINK_DEBUG, "* found best one for initial connect"); - timeout = 0; + //timeout = 0; connect_to = (node_t*)nodes->head->data; } + else + { logger(mesh, MESHLINK_DEBUG, "* could not find node for initial connect"); } splay_free_tree(nodes); } @@ -275,7 +399,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { // find better nodes to connect to - if(!connect_to && min_connects <= cur_connects < max_connects) + if(!connect_to && min_connects <= cur_connects && cur_connects < max_connects) { unsigned int connects = 0; @@ -283,23 +407,23 @@ static void periodic_handler(event_loop_t *loop, void *data) { { for list_each(connection_t, c, mesh->connections) { - if(!c->status.remove_unused && c->node && c->node->devclass == devclass) + 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_last_connect_try_desc, NULL); + splay_tree_t *nodes = splay_alloc_tree(node_compare_lsc_desc, NULL); for splay_each(node_t, n, mesh->nodes) { - if(n->devclass == devclass && !n->connection && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout)) + if(n != mesh->self && n->devclass == devclass && !n->connection && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout)) { splay_insert(nodes, n); } } if(nodes->head) { - logger(mesh, MESHLINK_INFO, "* found better node"); + logger(mesh, MESHLINK_DEBUG, "* found better node"); connect_to = (node_t*)nodes->head->data; splay_free_tree(nodes); @@ -311,26 +435,31 @@ static void periodic_handler(event_loop_t *loop, void *data) { else { break; } } + + if(!connect_to) + { logger(mesh, MESHLINK_DEBUG, "* could not find better nodes"); } } // heal partitions - if(!connect_to && min_connects <= cur_connects < max_connects) + if(!connect_to && min_connects <= cur_connects && cur_connects < max_connects) { - splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_asc_last_connect_try_desc, NULL); + splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_asc_lsc_desc, NULL); for splay_each(node_t, n, mesh->nodes) { - if(n->devclass <= mesh->devclass && !n->status.reachable && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout)) + if(n != mesh->self && n->devclass <= mesh->devclass && !n->status.reachable && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout)) { splay_insert(nodes, n); } } if(nodes->head) { - logger(mesh, MESHLINK_INFO, "* try to heal partition"); + 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_free_tree(nodes); } @@ -340,18 +469,36 @@ static void periodic_handler(event_loop_t *loop, void *data) { if(connect_to && !connect_to->connection) { - logger(mesh, MESHLINK_INFO, "Autoconnecting to %s", connect_to->name); - outgoing_t *outgoing = xzalloc(sizeof(outgoing_t)); - outgoing->mesh = mesh; - outgoing->name = xstrdup(connect_to->name); - list_insert_tail(mesh->outgoings, outgoing); - setup_outgoing_connection(mesh, outgoing); + connect_to->last_connect_try = time(NULL); + + /* check if there is already a connection attempt to this node */ + bool found = false; + for list_each(outgoing_t, outgoing, mesh->outgoings) + { + if(!strcmp(outgoing->name, connect_to->name)) + { + found = true; + break; + } + } + + if(!found) + { + logger(mesh, MESHLINK_DEBUG, "Autoconnecting to %s", connect_to->name); + outgoing_t *outgoing = xzalloc(sizeof(outgoing_t)); + outgoing->mesh = mesh; + outgoing->name = xstrdup(connect_to->name); + list_insert_tail(mesh->outgoings, outgoing); + setup_outgoing_connection(mesh, outgoing); + } + else + { logger(mesh, MESHLINK_DEBUG, "* skip autoconnect since it is an outgoing connection already"); } } // disconnect suboptimal outgoing connections - if(min_connects < cur_connects <= max_connects) + if(min_connects < cur_connects /*&& cur_connects <= max_connects*/) { unsigned int connects = 0; @@ -359,7 +506,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { { for list_each(connection_t, c, mesh->connections) { - if(!c->status.remove_unused && c->node && c->node->devclass == devclass) + if(c->status.active && c->node && c->node->devclass == devclass) { connects += 1; } } @@ -369,13 +516,13 @@ static void periodic_handler(event_loop_t *loop, void *data) { for list_each(connection_t, c, mesh->connections) { - if(!c->status.remove_unused && c->outgoing && c->node && c->node->devclass >= devclass) + if(c->outgoing && c->node && c->node->devclass >= devclass) { splay_insert(nodes, c->node); } } if(nodes->head) { - logger(mesh, MESHLINK_INFO, "* disconnect suboptimal outgoing connection"); + logger(mesh, MESHLINK_DEBUG, "* disconnect suboptimal outgoing connection"); disconnect_from = (node_t*)nodes->head->data; } @@ -383,6 +530,9 @@ static void periodic_handler(event_loop_t *loop, void *data) { break; } } + + if(!disconnect_from) + { logger(mesh, MESHLINK_DEBUG, "* no suboptimal outgoing connections"); } } @@ -394,17 +544,19 @@ static void periodic_handler(event_loop_t *loop, void *data) { for list_each(connection_t, c, mesh->connections) { - if(!c->status.remove_unused && c->node) + if(c->status.active && c->node) { splay_insert(nodes, c->node); } } if(nodes->head) { - logger(mesh, MESHLINK_INFO, "* disconnect connection (too many connections"); + logger(mesh, MESHLINK_DEBUG, "* disconnect connection (too many connections)"); - timeout = 0; + //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_free_tree(nodes); } @@ -414,7 +566,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { if(disconnect_from && disconnect_from->connection) { - logger(mesh, MESHLINK_INFO, "Autodisconnecting from %s", disconnect_from->connection->name); + 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); @@ -423,7 +575,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { // done! - logger(mesh, MESHLINK_INFO, "--- autoconnect end ---"); + logger(mesh, MESHLINK_DEBUG, "--- autoconnect end ---"); } timeout_set(&mesh->loop, data, &(struct timeval){timeout, rand() % 100000}); @@ -465,7 +617,7 @@ int main_loop(meshlink_handle_t *mesh) { mesh->datafromapp.signum = 0; signal_add(&(mesh->loop),&(mesh->datafromapp), (signal_cb_t)meshlink_send_from_queue,mesh, mesh->datafromapp.signum); - if(!event_loop_run(&mesh->loop)) { + if(!event_loop_run(&(mesh->loop), &(mesh->mesh_mutex))) { logger(mesh, MESHLINK_ERROR, "Error while waiting for input: %s", strerror(errno)); return 1; }