]>
code.octet-stream.net Git - netwatcher/blob - src/watch_linux.rs
efc3842482207998e40f36e868e259af4bc44c72
   1 use std
::os
::fd
::AsRawFd
; 
   2 use std
::os
::fd
::OwnedFd
; 
   4 use nix
::libc
::RTMGRP_IPV4_IFADDR
; 
   5 use nix
::libc
::RTMGRP_IPV6_IFADDR
; 
   6 use nix
::libc
::RTMGRP_LINK
; 
   7 use nix
::sys
::socket
::bind
; 
   8 use nix
::sys
::socket
::recv
; 
   9 use nix
::sys
::socket
::socket
; 
  10 use nix
::sys
::socket
::AddressFamily
; 
  11 use nix
::sys
::socket
::MsgFlags
; 
  12 use nix
::sys
::socket
::NetlinkAddr
; 
  13 use nix
::sys
::socket
::SockFlag
; 
  14 use nix
::sys
::socket
::SockProtocol
; 
  15 use nix
::sys
::socket
::SockType
; 
  21 pub(crate) struct WatchHandle 
{ 
  22     // PROBLEM: close() doesn't cancel recv() for a netlink socket 
  23     // SOLUTION: open a pipe() and use poll() inside the thread to watch for cancellation too 
  27 pub(crate) fn watch_interfaces
<F
: FnMut(Update
) + Send 
+ '
static>( 
  29 ) -> Result
<WatchHandle
, Error
> { 
  30     let sockfd 
= start_watcher_thread(callback
)?
; 
  31     Ok(WatchHandle 
{ sockfd 
}) 
  34 fn start_watcher_thread
<F
: FnMut(Update
) + Send 
+ '
static>(mut callback
: F
) -> Result
<OwnedFd
, Error
> { 
  35     let sockfd 
= socket(AddressFamily
::Netlink
, SockType
::Raw
, SockFlag
::empty(), Some(SockProtocol
::NetlinkRoute
)) 
  36         .map_err(|_
| Error
::Internal
)?
; // TODO: proper errors 
  37     let sa_nl 
= NetlinkAddr
::new(0, (RTMGRP_LINK 
| RTMGRP_IPV4_IFADDR 
| RTMGRP_IPV6_IFADDR
) as u32); 
  38     bind(sockfd
.as_raw_fd(), &sa_nl
).map_err(|_
| Error
::Internal
)?
; // TODO: proper errors 
  39     let fd 
= sockfd
.as_raw_fd(); 
  40     println
!("netlink socket on fd {}", fd
); 
  42     std
::thread
::spawn(move || { 
  43         println
!("watch thread running"); 
  44         let mut prev_list 
= List
::default(); 
  45         let mut buf 
= [0u8; 4096]; 
  46         let mut handle_update 
= move |new_list
: List
| { 
  47             if new_list 
== prev_list 
{ 
  51                 interfaces
: new_list
.0.clone(), 
  52                 diff
: new_list
.diff_from(&prev_list
), 
  58         if let Ok(initial
) = crate::list
::list_interfaces() { 
  59             handle_update(initial
); 
  62         while let Ok(n
) = recv(fd
, &mut buf
, MsgFlags
::empty()) { 
  63             println
!("something on the netlink socket: {} bytes", n
); 
  64             let Ok(new_list
) = crate::list
::list_interfaces() else { 
  67             handle_update(new_list
); 
  69         println
!("netlink recv thread terminating");