X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fnet.c;h=7c600534e3a682488200bbfa9f4cf320e7fe11f3;hb=529b8fab8c21e7ae5af91d742ff202eab38e51f3;hp=348c9e343b34a14dae8b04a9b4a2902035d5d6df;hpb=53522b1c11222273c7b41f72b374e759d13b2165;p=meshlink diff --git a/src/net.c b/src/net.c index 348c9e34..7c600534 100644 --- a/src/net.c +++ b/src/net.c @@ -39,6 +39,9 @@ static inline int min(int a, int b) { } #endif +static const int default_timeout = 5; +static const int default_interval = 60; + /* Terminate a connection: - Mark it as inactive @@ -106,22 +109,31 @@ void terminate_connection(meshlink_handle_t *mesh, connection_t *c, bool report) and close the connection. */ static void timeout_handler(event_loop_t *loop, void *data) { + assert(data); + meshlink_handle_t *mesh = loop->data; logger(mesh, MESHLINK_DEBUG, "timeout_handler()"); for list_each(connection_t, c, mesh->connections) { + 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; + + if(c->outgoing && c->outgoing->timeout < 5) { + pingtimeout = 1; + } + // Also make sure that if outstanding key requests for the UDP counterpart of a connection has timed out, we restart it. if(c->node) { - if(c->node->status.waitingforkey && c->node->last_req_key + mesh->pingtimeout <= mesh->loop.now.tv_sec) { + if(c->node->status.waitingforkey && c->node->last_req_key + pingtimeout <= mesh->loop.now.tv_sec) { send_req_key(mesh, c->node); } } - if(c->last_ping_time + mesh->pingtimeout <= mesh->loop.now.tv_sec) { + if(c->last_ping_time + pingtimeout <= mesh->loop.now.tv_sec) { if(c->status.active) { if(c->status.pinged) { logger(mesh, MESHLINK_INFO, "%s didn't respond to PING in %ld seconds", c->name, (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 + pinginterval <= mesh->loop.now.tv_sec) { send_ping(mesh, c); continue; } else { @@ -140,7 +152,7 @@ static void timeout_handler(event_loop_t *loop, void *data) { } timeout_set(&mesh->loop, data, &(struct timeval) { - mesh->pingtimeout, rand() % 100000 + 1, prng(mesh, TIMER_FUDGE) }); } @@ -351,7 +363,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { mesh->contradicting_add_edge = 0; mesh->contradicting_del_edge = 0; - int timeout = 5; + int timeout = default_timeout; /* Check if we need to make or break connections. */ @@ -359,7 +371,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { logger(mesh, MESHLINK_DEBUG, "--- autoconnect begin ---"); - int retry_timeout = min(mesh->nodes->count * 5, 60); + 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); @@ -387,13 +399,12 @@ static void periodic_handler(event_loop_t *loop, void *data) { // get min_connects and max_connects - unsigned int min_connects = dev_class_traits[mesh->devclass].min_connects; - unsigned int max_connects = dev_class_traits[mesh->devclass].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) { @@ -402,7 +413,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { 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 || (time(NULL) - n->last_connect_try) > retry_timeout)) { + 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); } } @@ -416,7 +427,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { logger(mesh, MESHLINK_DEBUG, "* could not find node for initial connect"); } - splay_free_tree(nodes); + splay_delete_tree(nodes); } @@ -425,7 +436,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { if(!connect_to && min_connects <= cur_connects && cur_connects < max_connects) { unsigned int connects = 0; - for(int32_t devclass = 0; devclass <= mesh->devclass; ++devclass) { + 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; @@ -436,7 +447,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { 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 || (time(NULL) - n->last_connect_try) > retry_timeout)) { + 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); } } @@ -445,11 +456,11 @@ static void periodic_handler(event_loop_t *loop, void *data) { logger(mesh, MESHLINK_DEBUG, "* found better node"); connect_to = (node_t *)nodes->head->data; - splay_free_tree(nodes); + splay_delete_tree(nodes); break; } - splay_free_tree(nodes); + splay_delete_tree(nodes); } else { break; } @@ -467,7 +478,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { 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 || (time(NULL) - n->last_connect_try) > retry_timeout)) { + 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); } } @@ -479,14 +490,14 @@ static void periodic_handler(event_loop_t *loop, void *data) { logger(mesh, MESHLINK_DEBUG, "* could not find nodes for partition healing"); } - splay_free_tree(nodes); + splay_delete_tree(nodes); } // perform connect if(connect_to && !connect_to->connection) { - connect_to->last_connect_try = time(NULL); + 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 */ @@ -500,7 +511,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { } } - if(!node_read_public_key(mesh, connect_to)) { + 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; } @@ -520,7 +531,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { if(min_connects < cur_connects /*&& cur_connects <= max_connects*/) { unsigned int connects = 0; - for(int32_t devclass = 0; devclass <= mesh->devclass; ++devclass) { + 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; @@ -541,7 +552,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { disconnect_from = (node_t *)nodes->head->data; } - splay_free_tree(nodes); + splay_delete_tree(nodes); break; } } @@ -572,7 +583,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { logger(mesh, MESHLINK_DEBUG, "* no node we want to disconnect, even though we have too many connections"); } - splay_free_tree(nodes); + splay_delete_tree(nodes); } @@ -585,6 +596,10 @@ static void periodic_handler(event_loop_t *loop, void *data) { terminate_connection(mesh, disconnect_from->connection, disconnect_from->connection->status.active); } + // reduce timeout if we don't have enough connections + outgoings + if(cur_connects + mesh->outgoings->count < 3) { + timeout = 1; + } // done! @@ -593,13 +608,16 @@ static void periodic_handler(event_loop_t *loop, void *data) { for splay_each(node_t, n, mesh->nodes) { if(n->status.dirty) { - node_write_config(mesh, n); + if(node_write_config(mesh, n)) { + logger(mesh, MESHLINK_DEBUG, "Could not update %s", n->name); + } + n->status.dirty = false; } } timeout_set(&mesh->loop, data, &(struct timeval) { - timeout, rand() % 100000 + timeout, prng(mesh, TIMER_FUDGE) }); } @@ -621,13 +639,61 @@ void retry(meshlink_handle_t *mesh) { }); } - /* Check for outgoing connections that are in progress, and reset their ping timers */ +#ifdef HAVE_IFADDRS_H + struct ifaddrs *ifa = NULL; + getifaddrs(&ifa); +#endif + + /* 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) { - if(c->outgoing && !c->node) { + if(!c->status.active) { + continue; + } + + if(!c->status.pinged) { c->last_ping_time = 0; } + +#ifdef HAVE_IFADDRS_H + + if(!ifa) { + continue; + } + + sockaddr_t sa; + socklen_t salen = sizeof(sa); + + if(getsockname(c->socket, &sa.sa, &salen)) { + continue; + } + + bool found = false; + + for(struct ifaddrs *ifap = ifa; ifap; ifap = ifap->ifa_next) { + if(ifap->ifa_addr && !sockaddrcmp_noport(&sa, (sockaddr_t *)ifap->ifa_addr)) { + found = true; + break; + } + + } + + if(!found) { + logger(mesh, MESHLINK_DEBUG, "Local address for connection to %s no longer valid, terminating", c->name); + terminate_connection(mesh, c, c->status.active); + } + +#endif } +#ifdef HAVE_IFADDRS_H + + if(ifa) { + freeifaddrs(ifa); + } + +#endif + /* Kick the ping timeout handler */ timeout_set(&mesh->loop, &mesh->pingtimer, &(struct timeval) { 0, 0 @@ -637,9 +703,9 @@ void retry(meshlink_handle_t *mesh) { /* this is where it all happens... */ -int main_loop(meshlink_handle_t *mesh) { +void main_loop(meshlink_handle_t *mesh) { timeout_add(&mesh->loop, &mesh->pingtimer, timeout_handler, &mesh->pingtimer, &(struct timeval) { - mesh->pingtimeout, rand() % 100000 + 1, prng(mesh, TIMER_FUDGE) }); timeout_add(&mesh->loop, &mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timeval) { 0, 0 @@ -647,15 +713,14 @@ int main_loop(meshlink_handle_t *mesh) { //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, meshlink_send_from_queue, mesh, mesh->datafromapp.signum); - if(!event_loop_run(&(mesh->loop), &(mesh->mesh_mutex))) { + if(!event_loop_run(&mesh->loop, &mesh->mutex)) { logger(mesh, MESHLINK_ERROR, "Error while waiting for input: %s", strerror(errno)); - return 1; + call_error_cb(mesh, MESHLINK_ENETWORK); } + signal_del(&mesh->loop, &mesh->datafromapp); timeout_del(&mesh->loop, &mesh->periodictimer); timeout_del(&mesh->loop, &mesh->pingtimer); - - return 0; }