X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fmeshlink.c;h=91be6412f7eb9ad5e5a11c9bc1ba8fd3fd478fa8;hb=2d9dbeb8ecb2d6220e123564bbfe18ba7fe0a34b;hp=9b30a2a65e383a9f39a00c8e22df4b5796a48f9d;hpb=1819754598edc2e8b8a7d53dce367fad465ce549;p=meshlink diff --git a/src/meshlink.c b/src/meshlink.c index 9b30a2a6..91be6412 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -164,7 +164,7 @@ static int socket_in_netns(int domain, int type, int protocol, int netns) { // Find out what local address a socket would use if we connect to the given address. // We do this using connect() on a UDP socket, so the kernel has to resolve the address // of both endpoints, but this will actually not send any UDP packet. -static bool getlocaladdr(char *destaddr, struct sockaddr *sn, socklen_t *sl, int netns) { +static bool getlocaladdr(char *destaddr, sockaddr_t *sa, socklen_t *salen, int netns) { struct addrinfo *rai = NULL; const struct addrinfo hint = { .ai_family = AF_UNSPEC, @@ -191,7 +191,7 @@ static bool getlocaladdr(char *destaddr, struct sockaddr *sn, socklen_t *sl, int freeaddrinfo(rai); - if(getsockname(sock, sn, sl)) { + if(getsockname(sock, &sa->sa, salen)) { closesocket(sock); return false; } @@ -201,14 +201,14 @@ static bool getlocaladdr(char *destaddr, struct sockaddr *sn, socklen_t *sl, int } static bool getlocaladdrname(char *destaddr, char *host, socklen_t hostlen, int netns) { - struct sockaddr_storage sn; - socklen_t sl = sizeof(sn); + sockaddr_t sa; + socklen_t salen = sizeof(sa); - if(!getlocaladdr(destaddr, (struct sockaddr *)&sn, &sl, netns)) { + if(!getlocaladdr(destaddr, &sa, &salen, netns)) { return false; } - if(getnameinfo((struct sockaddr *)&sn, sl, host, hostlen, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV)) { + if(getnameinfo(&sa.sa, salen, host, hostlen, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV)) { return false; } @@ -846,28 +846,40 @@ static struct timeval idle(event_loop_t *loop, void *data) { // Get our local address(es) by simulating connecting to an Internet host. static void add_local_addresses(meshlink_handle_t *mesh) { - struct sockaddr_storage sn; - sn.ss_family = AF_UNKNOWN; - socklen_t sl = sizeof(sn); + sockaddr_t sa; + sa.storage.ss_family = AF_UNKNOWN; + socklen_t salen = sizeof(sa); // IPv4 example.org - if(getlocaladdr("93.184.216.34", (struct sockaddr *)&sn, &sl, mesh->netns)) { - ((struct sockaddr_in *)&sn)->sin_port = ntohs(atoi(mesh->myport)); - meshlink_hint_address(mesh, (meshlink_node_t *)mesh->self, (struct sockaddr *)&sn); + if(getlocaladdr("93.184.216.34", &sa, &salen, mesh->netns)) { + sa.in.sin_port = ntohs(atoi(mesh->myport)); + node_add_recent_address(mesh, mesh->self, &sa); } // IPv6 example.org - sl = sizeof(sn); + salen = sizeof(sa); - if(getlocaladdr("2606:2800:220:1:248:1893:25c8:1946", (struct sockaddr *)&sn, &sl, mesh->netns)) { - ((struct sockaddr_in6 *)&sn)->sin6_port = ntohs(atoi(mesh->myport)); - meshlink_hint_address(mesh, (meshlink_node_t *)mesh->self, (struct sockaddr *)&sn); + if(getlocaladdr("2606:2800:220:1:248:1893:25c8:1946", &sa, &salen, mesh->netns)) { + sa.in6.sin6_port = ntohs(atoi(mesh->myport)); + node_add_recent_address(mesh, mesh->self, &sa); } } static bool meshlink_setup(meshlink_handle_t *mesh) { + if(!config_destroy(mesh->confbase, "new")) { + logger(mesh, MESHLINK_ERROR, "Could not delete configuration in %s/new: %s\n", mesh->confbase, strerror(errno)); + meshlink_errno = MESHLINK_ESTORAGE; + return false; + } + + if(!config_destroy(mesh->confbase, "old")) { + logger(mesh, MESHLINK_ERROR, "Could not delete configuration in %s/old: %s\n", mesh->confbase, strerror(errno)); + meshlink_errno = MESHLINK_ESTORAGE; + return false; + } + if(!config_init(mesh, "current")) { logger(mesh, MESHLINK_ERROR, "Could not set up configuration in %s/current: %s\n", mesh->confbase, strerror(errno)); meshlink_errno = MESHLINK_ESTORAGE; @@ -1501,6 +1513,8 @@ bool meshlink_start(meshlink_handle_t *mesh) { pthread_cond_wait(&mesh->cond, &mesh->mutex); mesh->threadstarted = true; + mesh->self->last_reachable = time(NULL); + mesh->self->status.dirty = true; pthread_mutex_unlock(&mesh->mutex); return true; @@ -1515,13 +1529,18 @@ void meshlink_stop(meshlink_handle_t *mesh) { pthread_mutex_lock(&mesh->mutex); logger(mesh, MESHLINK_DEBUG, "meshlink_stop called\n"); + if(mesh->self) { + mesh->self->last_unreachable = time(NULL); + mesh->self->status.dirty = true; + } + // Shut down the main thread event_loop_stop(&mesh->loop); // Send ourselves a UDP packet to kick the event loop for(int i = 0; i < mesh->listen_sockets; i++) { sockaddr_t sa; - socklen_t salen = sizeof(sa.sa); + socklen_t salen = sizeof(sa); if(getsockname(mesh->listen_socket[i].udp.fd, &sa.sa, &salen) == -1) { logger(mesh, MESHLINK_ERROR, "System call `%s' failed: %s", "getsockname", sockstrerror(sockerrno)); @@ -1676,7 +1695,6 @@ bool meshlink_destroy(const char *confbase) { fclose(lockfile); - /* TODO: do we need to remove confbase? Potential race condition? */ if(!sync_path(confbase)) { logger(NULL, MESHLINK_ERROR, "Cannot sync directory %s: %s\n", confbase, strerror(errno)); meshlink_errno = MESHLINK_ESTORAGE; @@ -2025,6 +2043,31 @@ static bool search_node_by_submesh(const node_t *node, const void *condition) { return false; } +struct time_range { + time_t start; + time_t end; +}; + +static bool search_node_by_last_reachable(const node_t *node, const void *condition) { + const struct time_range *range = condition; + time_t start = node->last_reachable; + time_t end = node->last_unreachable; + + if(end < start) { + end = time(NULL); + + if(end < start) { + start = end; + } + } + + if(range->end >= range->start) { + return start <= range->end && end >= range->start; + } else { + return start > range->start || end < range->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; @@ -2043,6 +2086,17 @@ meshlink_node_t **meshlink_get_all_nodes_by_submesh(meshlink_handle_t *mesh, mes return meshlink_get_all_nodes_by_condition(mesh, submesh, nodes, nmemb, search_node_by_submesh); } +meshlink_node_t **meshlink_get_all_nodes_by_last_reachable(meshlink_handle_t *mesh, time_t start, time_t end, meshlink_node_t **nodes, size_t *nmemb) { + if(!mesh || !nmemb) { + meshlink_errno = MESHLINK_EINVAL; + return NULL; + } + + struct time_range range = {start, end}; + + return meshlink_get_all_nodes_by_condition(mesh, &range, nodes, nmemb, search_node_by_last_reachable); +} + dev_class_t meshlink_get_node_dev_class(meshlink_handle_t *mesh, meshlink_node_t *node) { if(!mesh || !node) { meshlink_errno = MESHLINK_EINVAL; @@ -2700,7 +2754,7 @@ char *meshlink_export(meshlink_handle_t *mesh) { uint32_t count = 0; - for(uint32_t i = 0; i < 5; i++) { + for(uint32_t i = 0; i < MAX_RECENT; i++) { if(mesh->self->recent[i].sa.sa_family) { count++; } else { @@ -2714,6 +2768,9 @@ char *meshlink_export(meshlink_handle_t *mesh) { packmsg_add_sockaddr(&out, &mesh->self->recent[i]); } + packmsg_add_int64(&out, 0); + packmsg_add_int64(&out, 0); + pthread_mutex_unlock(&mesh->mutex); if(!packmsg_output_ok(&out)) { @@ -3063,11 +3120,11 @@ void meshlink_hint_address(meshlink_handle_t *mesh, meshlink_node_t *node, const pthread_mutex_lock(&mesh->mutex); node_t *n = (node_t *)node; - memmove(n->recent + 1, n->recent, 4 * sizeof(*n->recent)); - memcpy(n->recent, addr, SALEN(*addr)); - if(!node_write_config(mesh, n)) { - logger(mesh, MESHLINK_DEBUG, "Could not update %s\n", n->name); + if(node_add_recent_address(mesh, n, (sockaddr_t *)addr)) { + if(!node_write_config(mesh, n)) { + logger(mesh, MESHLINK_DEBUG, "Could not update %s\n", n->name); + } } pthread_mutex_unlock(&mesh->mutex);