From: Thomas Karpiniec Date: Fri, 14 Jun 2024 21:08:38 +0000 (+0100) Subject: Make watching work on Linux X-Git-Tag: v0.1.0~16 X-Git-Url: https://code.octet-stream.net/netwatcher/commitdiff_plain/4abfa61b20e567fdd69ac3ca47a9c218971a30ff Make watching work on Linux --- diff --git a/src/lib.rs b/src/lib.rs index 7a8298e..69de586 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -145,6 +145,6 @@ pub fn list_interfaces() -> Result, Error> { /// /// The callback will fire once immediately with an initial interface list, and a diff as if /// there were originally no interfaces present. -pub fn watch_interfaces(callback: F) -> Result { +pub fn watch_interfaces(callback: F) -> Result { watch::watch_interfaces(callback).map(|handle| WatchHandle { _inner: handle }) } diff --git a/src/watch_linux.rs b/src/watch_linux.rs index 4e4049b..efc3842 100644 --- a/src/watch_linux.rs +++ b/src/watch_linux.rs @@ -1,7 +1,6 @@ use std::os::fd::AsRawFd; use std::os::fd::OwnedFd; -use nix::libc::nlmsghdr; use nix::libc::RTMGRP_IPV4_IFADDR; use nix::libc::RTMGRP_IPV6_IFADDR; use nix::libc::RTMGRP_LINK; @@ -16,21 +15,23 @@ use nix::sys::socket::SockProtocol; use nix::sys::socket::SockType; use crate::Error; +use crate::List; use crate::Update; pub(crate) struct WatchHandle { // PROBLEM: close() doesn't cancel recv() for a netlink socket + // SOLUTION: open a pipe() and use poll() inside the thread to watch for cancellation too sockfd: OwnedFd, } -pub(crate) fn watch_interfaces( +pub(crate) fn watch_interfaces( callback: F, ) -> Result { let sockfd = start_watcher_thread(callback)?; Ok(WatchHandle { sockfd }) } -fn start_watcher_thread(callback: F) -> Result { +fn start_watcher_thread(mut callback: F) -> Result { let sockfd = socket(AddressFamily::Netlink, SockType::Raw, SockFlag::empty(), Some(SockProtocol::NetlinkRoute)) .map_err(|_| Error::Internal)?; // TODO: proper errors let sa_nl = NetlinkAddr::new(0, (RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR) as u32); @@ -40,15 +41,30 @@ fn start_watcher_thread(callback: F) -> Result, + cb: Box, } pub(crate) struct WatchHandle { @@ -39,7 +39,7 @@ impl Drop for WatchHandle { } } -pub(crate) fn watch_interfaces( +pub(crate) fn watch_interfaces( callback: F, ) -> Result { let state = Box::pin(Mutex::new(WatchState {