netwatcher 0.6.0

List network interfaces and watch for changes efficiently
Documentation
use std::os::fd::{AsRawFd, BorrowedFd, OwnedFd};

use nix::errno::Errno;
use nix::libc::{fcntl, F_GETFL, F_SETFL, O_NONBLOCK};
use nix::sys::socket::{recv, socket, AddressFamily, MsgFlags, SockFlag, SockType};

pub(crate) use crate::watch_fd::{AsyncWatch, BlockingWatch, WatchHandle};
use crate::{Error, Update};

const EVENT_SOCKET_OPS: crate::watch_fd::EventSocketOps = crate::watch_fd::EventSocketOps {
    open: open_event_socket,
    drain: drain_event_socket,
};

pub(crate) fn watch_interfaces_with_callback<F: FnMut(Update) + Send + 'static>(
    callback: F,
) -> Result<WatchHandle, Error> {
    crate::watch_fd::watch_interfaces_with_callback(callback, EVENT_SOCKET_OPS)
}

pub(crate) fn watch_interfaces_async<A: crate::async_adapter::AsyncFdAdapter>(
) -> Result<AsyncWatch, Error> {
    crate::watch_fd::watch_interfaces_async::<A>(EVENT_SOCKET_OPS)
}

pub(crate) fn watch_interfaces_blocking() -> Result<BlockingWatch, Error> {
    crate::watch_fd::watch_interfaces_blocking(EVENT_SOCKET_OPS)
}

pub(crate) fn open_event_socket() -> Result<OwnedFd, Error> {
    let sockfd = socket(AddressFamily::Route, SockType::Raw, SockFlag::empty(), None)
        .map_err(|e| Error::CreateSocket(e.to_string()))?;

    let flags = unsafe { fcntl(sockfd.as_raw_fd(), F_GETFL) };
    if flags == -1 {
        return Err(Error::CreateSocket(
            std::io::Error::last_os_error().to_string(),
        ));
    }

    let set_status = unsafe { fcntl(sockfd.as_raw_fd(), F_SETFL, flags | O_NONBLOCK) };
    if set_status == -1 {
        return Err(Error::CreateSocket(
            std::io::Error::last_os_error().to_string(),
        ));
    }

    Ok(sockfd)
}

pub(crate) fn drain_event_socket(fd: BorrowedFd<'_>) {
    let mut buf = [0u8; 8192];
    loop {
        match recv(fd.as_raw_fd(), &mut buf, MsgFlags::empty()) {
            Ok(0) => break,
            Ok(_) => continue,
            Err(Errno::EAGAIN) => break,
            Err(_) => break,
        }
    }
}