X-Git-Url: http://git.meshlink.io/?p=meshlink;a=blobdiff_plain;f=src%2Fnet.c;h=2ee8aee446bc1df899354fb1cb93c1373e7aa844;hp=ddfd2cf09aa828abc5a861742e60172e33b8fddb;hb=8c8b506da9ce578fe6e6e406a91bbd21af13f7a3;hpb=64720408e45d283eaaa5091957d949fab43087ef diff --git a/src/net.c b/src/net.c index ddfd2cf0..2ee8aee4 100644 --- a/src/net.c +++ b/src/net.c @@ -29,6 +29,7 @@ #include "net.h" #include "netutl.h" #include "protocol.h" +#include "sptps.h" #include "xalloc.h" #include @@ -39,6 +40,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 @@ -88,13 +92,6 @@ void terminate_connection(meshlink_handle_t *mesh, connection_t *c, bool report) if(outgoing) { do_outgoing_connection(mesh, outgoing); } - -#ifndef HAVE_MINGW - /* Clean up dead proxy processes */ - - while(waitpid(-1, NULL, WNOHANG) > 0); - -#endif } /* @@ -106,22 +103,41 @@ 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->status.active && c->last_key_renewal + 3600 < mesh->loop.now.tv_sec) { + if(!sptps_force_kex(&c->sptps)) { + logger(mesh, MESHLINK_ERROR, "SPTPS key renewal for connection with %s failed", c->name); + terminate_connection(mesh, c, true); + continue; + } else { + c->last_key_renewal = 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 { @@ -139,8 +155,8 @@ 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 timespec) { + 1, prng(mesh, TIMER_FUDGE) }); } @@ -334,7 +350,8 @@ static void periodic_handler(event_loop_t *loop, void *data) { if(mesh->contradicting_del_edge > 100 && mesh->contradicting_add_edge > 100) { logger(mesh, MESHLINK_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", mesh->sleeptime); - usleep(mesh->sleeptime * 1000000LL); + struct timespec ts = {mesh->sleeptime, 0}; + clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); mesh->sleeptime *= 2; if(mesh->sleeptime < 0) { @@ -351,7 +368,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 +376,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 +404,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 +418,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 +432,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 +441,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 +452,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 +461,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 +483,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 +495,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 */ @@ -520,7 +536,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 +557,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 +588,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); } @@ -597,13 +613,30 @@ 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; } + + if(n->status.validkey && n->last_req_key + 3600 < mesh->loop.now.tv_sec) { + logger(mesh, MESHLINK_DEBUG, "SPTPS key renewal for node %s", n->name); + + if(!sptps_force_kex(&n->sptps)) { + logger(mesh, MESHLINK_ERROR, "SPTPS key renewal for node %s failed", n->name); + n->status.validkey = false; + sptps_stop(&n->sptps); + n->status.waitingforkey = false; + n->last_req_key = 0; + } else { + n->last_req_key = mesh->loop.now.tv_sec; + } + } } - timeout_set(&mesh->loop, data, &(struct timeval) { - timeout, rand() % 100000 + timeout_set(&mesh->loop, data, &(struct timespec) { + timeout, prng(mesh, TIMER_FUDGE) }); } @@ -619,17 +652,13 @@ 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 - }); + if(outgoing->ev.cb) { + timeout_set(&mesh->loop, &outgoing->ev, &(struct timespec) { + 0, 0 + }); + } } -#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) { @@ -641,12 +670,6 @@ void retry(meshlink_handle_t *mesh) { c->last_ping_time = 0; } -#ifdef HAVE_IFADDRS_H - - if(!ifa) { - continue; - } - sockaddr_t sa; socklen_t salen = sizeof(sa); @@ -654,34 +677,35 @@ void retry(meshlink_handle_t *mesh) { continue; } - bool found = false; + switch(sa.sa.sa_family) { + case AF_INET: + sa.in.sin_port = 0; + break; - 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; - } + case AF_INET6: + sa.in6.sin6_port = 0; + break; + default: + continue; } - if(!found) { + int sock = socket(sa.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); + + if(sock != -1) { + continue; + } + + if(bind(sock, &sa.sa, salen) && errno == EADDRNOTAVAIL) { 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); + closesocket(sock); } -#endif - /* Kick the ping timeout handler */ - timeout_set(&mesh->loop, &mesh->pingtimer, &(struct timeval) { + timeout_set(&mesh->loop, &mesh->pingtimer, &(struct timespec) { 0, 0 }); } @@ -689,25 +713,24 @@ void retry(meshlink_handle_t *mesh) { /* 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 +void main_loop(meshlink_handle_t *mesh) { + timeout_add(&mesh->loop, &mesh->pingtimer, timeout_handler, &mesh->pingtimer, &(struct timespec) { + 1, prng(mesh, TIMER_FUDGE) }); - timeout_add(&mesh->loop, &mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timeval) { + timeout_add(&mesh->loop, &mesh->periodictimer, periodic_handler, &mesh->periodictimer, &(struct timespec) { 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, 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; }