X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fnet.c;h=45a9abbfea363c37e9d099b9307fc2085fecdc7b;hb=0bdce44687a22c8825695cba185b845f5ea5e060;hp=c33c69c3062beeddbbc882464302111683ad4d59;hpb=eab78f4d460ec17b44978ce4cca02daadacca9c0;p=meshlink diff --git a/src/net.c b/src/net.c index c33c69c3..45a9abbf 100644 --- a/src/net.c +++ b/src/net.c @@ -33,9 +33,11 @@ #include +#if !defined(min) static const int min(int a, int b) { return a < b ? a : b; } +#endif /* Terminate a connection: @@ -110,14 +112,13 @@ static void timeout_handler(event_loop_t *loop, void *data) { } if(c->last_ping_time + mesh->pingtimeout <= mesh->loop.now.tv_sec) { if(c->status.active) { - if(c->status.pinged) { + if(c->status.pinged) logger(mesh, MESHLINK_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)mesh->loop.now.tv_sec - c->last_ping_time); - } else if(c->last_ping_time + mesh->pinginterval <= mesh->loop.now.tv_sec) { + else if(c->last_ping_time + mesh->pinginterval <= mesh->loop.now.tv_sec) { send_ping(mesh, c); continue; - } else { + } else continue; - } } else { if(c->status.connecting) logger(mesh, MESHLINK_WARNING, "Timeout while connecting to %s (%s)", c->name, c->hostname); @@ -128,59 +129,76 @@ static void timeout_handler(event_loop_t *loop, void *data) { } } - timeout_set(&mesh->loop, data, &(struct timeval){mesh->pingtimeout, rand() % 100000}); + 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; if(na->devclass < nb->devclass) - { return -1; } + return -1; if(na->devclass > nb->devclass) - { return 1; } + 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(na->last_connect_try == 0 || na->last_connect_try > nb->last_connect_try) + 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_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; } // devclass desc -static int node_compare_devclass_desc(const void *a, const void *b) -{ +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; } + return -1; if(na->devclass > nb->devclass) - { return 1; } + return 1; + + if(na < nb) + return -1; + + if(na > nb) + return 1; return 0; } @@ -188,98 +206,96 @@ static int node_compare_devclass_desc(const void *a, const void *b) /* - autoconnect() { - timeout = 5 + timeout = 5 - // find the best one for initial connect + // 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 + 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 + // 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 + 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 + // 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 + 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 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 + 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 connections in case we have more than enough connections - // disconnect + if max < cur + delcon = + first from nodes + where outgoing_connection + order by dclass desc + goto disconnect + + // disconnect disconnect - if delcon - disconnect delcon + if delcon + disconnect delcon - // next iteration - next (timeout, autoconnect) + // next iteration + next (timeout, autoconnect) } - - */ +*/ static void periodic_handler(event_loop_t *loop, void *data) { @@ -311,31 +327,32 @@ 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; - node_t* disconnect_from = NULL; + node_t *connect_to = NULL; + node_t *disconnect_from = NULL; // get cur_connects int cur_connects = 0; - for list_each(connection_t, c, mesh->connections) - { - if(!c->status.remove_unused) - { + for list_each(connection_t, c, mesh->connections) { + 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 @@ -344,29 +361,28 @@ static void periodic_handler(event_loop_t *loop, void *data) { 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); + 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) - { - if(n->devclass <= mesh->devclass && !n->connection && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout)) - { splay_insert(nodes, n); } + for splay_each(node_t, n, mesh->nodes) { + 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"); + if(nodes->head) { + logger(mesh, MESHLINK_DEBUG, "* found best one for initial connect"); //timeout = 0; - connect_to = (node_t*)nodes->head->data; - } + connect_to = (node_t *)nodes->head->data; + } else + logger(mesh, MESHLINK_DEBUG, "* could not find node for initial connect"); splay_free_tree(nodes); } @@ -374,62 +390,56 @@ static void periodic_handler(event_loop_t *loop, void *data) { // find better nodes to connect to - if(!connect_to && min_connects <= cur_connects && cur_connects < max_connects) - { + if(!connect_to && min_connects <= cur_connects && cur_connects < max_connects) { unsigned int connects = 0; - for(int devclass = 0; devclass <= mesh->devclass; ++devclass) - { - for list_each(connection_t, c, mesh->connections) - { - if(!c->status.remove_unused && c->node && c->node->devclass == devclass) - { connects += 1; } + for(int 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_last_connect_try_desc, NULL); + 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->devclass == devclass && !n->connection && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout)) - { splay_insert(nodes, n); } + for splay_each(node_t, n, mesh->nodes) { + 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"); - connect_to = (node_t*)nodes->head->data; + if(nodes->head) { + logger(mesh, MESHLINK_DEBUG, "* found better node"); + connect_to = (node_t *)nodes->head->data; splay_free_tree(nodes); break; } splay_free_tree(nodes); - } - else - { break; } + } 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_last_connect_try_desc, NULL); + 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->devclass <= mesh->devclass && !n->status.reachable && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout)) - { splay_insert(nodes, n); } + for splay_each(node_t, n, mesh->nodes) { + 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"); - connect_to = (node_t*)nodes->head->data; - } + 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_free_tree(nodes); } @@ -437,8 +447,9 @@ static void periodic_handler(event_loop_t *loop, void *data) { // perform connect - if(connect_to && !connect_to->connection) - { + if(connect_to && !connect_to->connection) { + 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) { @@ -448,74 +459,69 @@ static void periodic_handler(event_loop_t *loop, void *data) { } } - if(!found) - { - logger(mesh, MESHLINK_INFO, "Autoconnecting to %s", connect_to->name); + 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); - } + 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 && cur_connects <= max_connects) - { + if(min_connects < cur_connects /*&& cur_connects <= max_connects*/) { unsigned int connects = 0; - for(int devclass = 0; devclass <= mesh->devclass; ++devclass) - { - for list_each(connection_t, c, mesh->connections) - { - if(!c->status.remove_unused && c->node && c->node->devclass == devclass) - { connects += 1; } + for(int 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 ) - { + 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->status.remove_unused && c->outgoing && c->node && c->node->devclass >= devclass) - { splay_insert(nodes, c->node); } + 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_INFO, "* disconnect suboptimal outgoing connection"); - disconnect_from = (node_t*)nodes->head->data; + if(nodes->head) { + logger(mesh, MESHLINK_DEBUG, "* disconnect suboptimal outgoing connection"); + disconnect_from = (node_t *)nodes->head->data; } splay_free_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) - { + 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.remove_unused && c->node) - { splay_insert(nodes, c->node); } + 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_INFO, "* disconnect connection (too many connections"); + if(nodes->head) { + logger(mesh, MESHLINK_DEBUG, "* disconnect connection (too many connections)"); //timeout = 0; - disconnect_from = (node_t*)nodes->head->data; - } + 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); } @@ -523,9 +529,8 @@ static void periodic_handler(event_loop_t *loop, void *data) { // perform disconnect - if(disconnect_from && disconnect_from->connection) - { - logger(mesh, MESHLINK_INFO, "Autodisconnecting from %s", disconnect_from->connection->name); + 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); @@ -534,14 +539,16 @@ 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}); + timeout_set(&mesh->loop, data, &(struct timeval) { + timeout, rand() % 100000 + }); } void handle_meta_connection_data(meshlink_handle_t *mesh, connection_t *c) { - if (!receive_meta(mesh, c)) { + if(!receive_meta(mesh, c)) { terminate_connection(mesh, c, c->status.active); return; } @@ -552,7 +559,9 @@ void retry(meshlink_handle_t *mesh) { for list_each(outgoing_t, outgoing, mesh->outgoings) { outgoing->timeout = 0; if(outgoing->ev.cb) - timeout_set(&mesh->loop, &outgoing->ev, &(struct timeval){0, 0}); + timeout_set(&mesh->loop, &outgoing->ev, &(struct timeval) { + 0, 0 + }); } /* Check for outgoing connections that are in progress, and reset their ping timers */ @@ -562,21 +571,27 @@ void retry(meshlink_handle_t *mesh) { } /* Kick the ping timeout handler */ - timeout_set(&mesh->loop, &mesh->pingtimer, &(struct timeval){0, 0}); + timeout_set(&mesh->loop, &mesh->pingtimer, &(struct timeval) { + 0, 0 + }); } /* this is where it all happens... */ int main_loop(meshlink_handle_t *mesh) { - timeout_add(&mesh->loop, &mesh->pingtimer, timeout_handler, &mesh->pingtimer, &(struct timeval){mesh->pingtimeout, rand() % 100000}); - timeout_add(&mesh->loop, &mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timeval){0, 0}); + timeout_add(&mesh->loop, &mesh->pingtimer, timeout_handler, &mesh->pingtimer, &(struct timeval) { + mesh->pingtimeout, rand() % 100000 + }); + timeout_add(&mesh->loop, &mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timeval) { + 0, 0 + }); //Add signal handler mesh->datafromapp.signum = 0; - signal_add(&(mesh->loop),&(mesh->datafromapp), (signal_cb_t)meshlink_send_from_queue,mesh, mesh->datafromapp.signum); + 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; }