From 69e74943afe4f77a4be52542d4b9b2a47da911f5 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Thu, 18 Jun 2020 22:41:12 +0200 Subject: [PATCH] Monitor a PFROUTE socket on *BSD and macOS. Catta is not handling network changes correctly on *BSD and macOS. In particular, after the initial startup, interfaces that go up and down do not cause a callback to be generated, so MeshLink is not notified of the changes. To ensure MeshLink responds rapidly to network changes on these platforms, we open a PFROUTE socket and monitor it ourself. We only check the message type, and don't track exactly what addresses get added or removed. --- src/discovery.c | 72 +++++++++++++++++++++++++++++++++++++++++ src/meshlink_internal.h | 3 ++ 2 files changed, 75 insertions(+) diff --git a/src/discovery.c b/src/discovery.c index 2ac69b36..642c7e14 100644 --- a/src/discovery.c +++ b/src/discovery.c @@ -9,7 +9,12 @@ #include #include +#if defined(__APPLE__) || defined(__unix) && !defined(__linux) +#include +#endif + #include "meshlink_internal.h" +#include "event.h" #include "discovery.h" #include "sockaddr.h" #include "logger.h" @@ -482,6 +487,53 @@ fail: return NULL; } +#ifdef RTM_NEWADDR +static void pfroute_io_handler(event_loop_t *loop, void *data, int flags) { + (void)flags; + static time_t prev_update; + meshlink_handle_t *mesh = data; + + struct { + struct rt_msghdr rtm; + char data[2048]; + } msg; + + while(true) { + msg.rtm.rtm_version = 0; + ssize_t result = recv(mesh->pfroute_io.fd, &msg, sizeof(msg), MSG_DONTWAIT); + + if(result <= 0) { + if(result == 0 || errno == EAGAIN || errno == EINTR) { + break; + } + + logger(mesh, MESHLINK_ERROR, "Reading from PFROUTE socket failed: %s\n", strerror(errno)); + io_set(loop, &mesh->pfroute_io, 0); + } + + if(msg.rtm.rtm_version != RTM_VERSION) { + logger(mesh, MESHLINK_ERROR, "Invalid PFROUTE message version\n"); + break; + } + + switch(msg.rtm.rtm_type) { + case RTM_IFINFO: + case RTM_NEWADDR: + case RTM_DELADDR: + if(loop->now.tv_sec > prev_update + 5) { + prev_update = loop->now.tv_sec; + handle_network_change(mesh, 1); + } + + break; + + default: + break; + } + } +} +#endif + bool discovery_start(meshlink_handle_t *mesh) { logger(mesh, MESHLINK_DEBUG, "discovery_start called\n"); @@ -509,6 +561,17 @@ bool discovery_start(meshlink_handle_t *mesh) { mesh->discovery_threadstarted = true; +#ifdef RTM_NEWADDR + int sock = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC); + + if(sock != -1) { + io_add(&mesh->loop, &mesh->pfroute_io, pfroute_io_handler, mesh, sock, IO_READ); + } else { + logger(mesh, MESHLINK_WARNING, "Could not open PF_ROUTE socket: %s", strerror(errno)); + } + +#endif + return true; } @@ -517,6 +580,15 @@ void discovery_stop(meshlink_handle_t *mesh) { assert(mesh); +#ifdef RTM_NEWADDR + + if(mesh->pfroute_io.cb) { + close(mesh->pfroute_io.fd); + io_del(&mesh->loop, &mesh->pfroute_io); + } + +#endif + // Shut down if(mesh->catta_poll) { catta_simple_poll_quit(mesh->catta_poll); diff --git a/src/meshlink_internal.h b/src/meshlink_internal.h index d9000feb..a092e1b6 100644 --- a/src/meshlink_internal.h +++ b/src/meshlink_internal.h @@ -191,6 +191,9 @@ struct meshlink_handle { char *catta_servicetype; unsigned int catta_interfaces; + // PFROUTE + io_t pfroute_io; + // ADNS pthread_t adns_thread; pthread_cond_t adns_cond; -- 2.39.5