]>
code.octet-stream.net Git - netwatcher/blob - src/watch_linux.rs
4e4049b8856ba87dece34d25677f1116c49ae7a5
1 use std
::os
::fd
::AsRawFd
;
2 use std
::os
::fd
::OwnedFd
;
4 use nix
::libc
::nlmsghdr
;
5 use nix
::libc
::RTMGRP_IPV4_IFADDR
;
6 use nix
::libc
::RTMGRP_IPV6_IFADDR
;
7 use nix
::libc
::RTMGRP_LINK
;
8 use nix
::sys
::socket
::bind
;
9 use nix
::sys
::socket
::recv
;
10 use nix
::sys
::socket
::socket
;
11 use nix
::sys
::socket
::AddressFamily
;
12 use nix
::sys
::socket
::MsgFlags
;
13 use nix
::sys
::socket
::NetlinkAddr
;
14 use nix
::sys
::socket
::SockFlag
;
15 use nix
::sys
::socket
::SockProtocol
;
16 use nix
::sys
::socket
::SockType
;
21 pub(crate) struct WatchHandle
{
22 // PROBLEM: close() doesn't cancel recv() for a netlink socket
26 pub(crate) fn watch_interfaces
<F
: FnMut(Update
) + '
static>(
28 ) -> Result
<WatchHandle
, Error
> {
29 let sockfd
= start_watcher_thread(callback
)?
;
30 Ok(WatchHandle
{ sockfd
})
33 fn start_watcher_thread
<F
: FnMut(Update
) + '
static>(callback
: F
) -> Result
<OwnedFd
, Error
> {
34 let sockfd
= socket(AddressFamily
::Netlink
, SockType
::Raw
, SockFlag
::empty(), Some(SockProtocol
::NetlinkRoute
))
35 .map_err(|_
| Error
::Internal
)?
; // TODO: proper errors
36 let sa_nl
= NetlinkAddr
::new(0, (RTMGRP_LINK
| RTMGRP_IPV4_IFADDR
| RTMGRP_IPV6_IFADDR
) as u32);
37 bind(sockfd
.as_raw_fd(), &sa_nl
).map_err(|_
| Error
::Internal
)?
; // TODO: proper errors
38 let fd
= sockfd
.as_raw_fd();
39 println
!("netlink socket on fd {}", fd
);
41 std
::thread
::spawn(move || {
42 println
!("watch thread running");
43 let mut buf
= [0u8; 4096];
45 while let Ok(n
) = recv(fd
, &mut buf
, MsgFlags
::empty()) {
46 println
!("something on the netlink socket: {} bytes", n
);
47 let nlmsg_ptr
= &buf
as *const _
as *const nlmsghdr
;
48 let nlmsg
= unsafe { &*nlmsg_ptr
};
49 // Right conventionally there's some trick here involving macros NLMSG_OK
50 // I can presumably do this using NetlinkGeneric too
51 // It's unclear whether this is worse or not - need to know what those macros do
53 println
!("netlink recv thread terminating");