diff --git a/Cargo.toml b/Cargo.toml index 17fc6b0..817d2c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,5 +8,16 @@ keywords = ["asynchronous", "routing"] [dependencies] libc = "0.2.66" +[target.'cfg(unix)'.dependencies] +async-io = "1.2.0" + [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3.8", features = ["netioapi", "ntdef", "ws2def"] } +futures-lite = "1.11.2" +if-addrs = "0.6.5" +winapi = { version = "0.3.8", features = ["netioapi", "ntdef", "winerror", "ws2def"] } + +[target.'cfg(windows)'.dev-dependencies] +winapi = { version = "0.3.8", features = ["processthreadsapi", "synchapi"] } + +[dev-dependencies] +futures-lite = "1.11.2" diff --git a/bindgen.sh b/bindgen.sh deleted file mode 100755 index 900b54a..0000000 --- a/bindgen.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -- -set -euo pipefail -unset path -case $0 in - /*) path=${0%/*};; - */*) path=$PWD/${0%/*};; - *) path=$PWD;; -esac -mingw_include=/usr/x86_64-w64-mingw32/sys-root/mingw/include - -# sudo dnf install mingw{32,64}-headers -bindgen \ - --impl-debug \ - --impl-partialeq \ - --whitelist-type '[_P]?MIB_IPFORWARD_ROW2' \ - --whitelist-var 'NO_ERROR|AF_UNSPEC' \ - --whitelist-function NotifyRouteChange2 \ - --whitelist-function CancelMibChangeNotify2 \ - --whitelist-function SleepEx \ - --whitelist-function GetCurrentThreadId \ - --no-rustfmt-bindings \ - --with-derive-eq \ - --with-derive-ord \ - --with-derive-hash \ - "$mingw_include/netioapi.h" \ - -- \ - --target=i686-w64-mingw32 \ - -include "$mingw_include/error.h" \ - -include "$mingw_include/winsock2.h" \ - -include "$mingw_include/winternl.h" | - rustup run nightly rustfmt > src/windows/bindings.rs diff --git a/examples/ip_watch.rs b/examples/ip_watch.rs new file mode 100644 index 0000000..db59ff9 --- /dev/null +++ b/examples/ip_watch.rs @@ -0,0 +1,10 @@ +use ip_watch::AddrSet; + +fn main() { + futures_lite::future::block_on(async { + let mut set = AddrSet::new().await.unwrap(); + loop { + println!("Got event {:?}", set.next().await); + } + }); +} diff --git a/src/lib.rs b/src/lib.rs index e3175ef..f1258e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ //! limited to synchronous operation. #![deny( - exceeding_bitshifts, + arithmetic_overflow, invalid_type_param_default, missing_fragment_specifier, mutable_transmutes, @@ -72,15 +72,36 @@ pub enum Event { Delete(std::net::IpAddr), } -#[cfg(all(test, not(windows)))] +#[cfg(test)] mod tests { use super::*; + use futures_lite::future::poll_fn; + use std::{future::Future, pin::Pin, task::Poll}; + + #[test] + fn test_ip_watch() { + futures_lite::future::block_on(async { + let mut set = AddrSet::new().await.unwrap(); + poll_fn(|cx| loop { + let next = set.next(); + futures_lite::pin!(next); + if let Poll::Ready(Ok(ev)) = Pin::new(&mut next).poll(cx) { + println!("Got event {:?}", ev); + continue + } + return Poll::Ready(()) + }) + .await; + }); + } + #[test] - fn it_works() { - let set = AddrSet::new(); - println!("Got event {:?}", set); - for i in set.unwrap() { - println!("Got event {:?}", i.unwrap()) - } + fn test_is_send() { + futures_lite::future::block_on(async { + fn is_send(_: T) {} + is_send(AddrSet::new()); + is_send(AddrSet::new().await.unwrap()); + is_send(AddrSet::new().await.unwrap().next()); + }); } } diff --git a/src/unix.rs b/src/unix.rs index aba704c..3384707 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -44,12 +44,12 @@ pub struct AddrSet { impl AddrSet { /// Create a watcher - pub fn new() -> std::io::Result { + pub async fn new() -> std::io::Result { let mut hash = HashSet::new(); let mut watcher = Watcher::new()?; let mut buf = Vec::with_capacity(1 << 16); let mut queue = VecDeque::new(); - watcher.resync(&mut buf, &mut queue, &mut hash)?; + watcher.resync(&mut buf, &mut queue, &mut hash).await?; Ok(Self { hash, watcher, @@ -57,12 +57,9 @@ impl AddrSet { queue, }) } -} - -impl Iterator for AddrSet { - type Item = std::io::Result; - fn next(&mut self) -> Option { + /// Returns a future for the next event. + pub async fn next(&mut self) -> std::io::Result { let Self { watcher, buf, @@ -70,22 +67,22 @@ impl Iterator for AddrSet { queue, } = self; if let Some(event) = queue.pop_front() { - return Some(Ok(event)) + return Ok(event) } loop { - match watcher.next(buf, queue, hash) { - Status::IO(e) => return Some(Err(e)), + match watcher.next(buf, queue, hash).await { + Status::IO(e) => return Err(e), Status::Desync => { if buf.capacity() < 1 << 19 { buf.reserve(buf.capacity() * 2); } - if watcher.resync(buf, queue, hash).is_err() { + if watcher.resync(buf, queue, hash).await.is_err() { continue } } Status::Data(()) => { if let Some(event) = queue.pop_front() { - return Some(Ok(event)) + return Ok(event) } } } diff --git a/src/unix/fd.rs b/src/unix/fd.rs index 7d0b5a2..e73c24e 100644 --- a/src/unix/fd.rs +++ b/src/unix/fd.rs @@ -19,7 +19,7 @@ impl Fd { #[cfg(target_os = "linux")] let fd = unsafe { socket(libc::PF_NETLINK, FLAGS, libc::NETLINK_ROUTE) }; #[cfg(not(target_os = "linux"))] - let fd = unsafe { socket(libc::PF_ROUTE, FLAGS | libc::SOCK_NONBLOCK, libc::AF_UNSPEC) }; + let fd = unsafe { socket(libc::PF_ROUTE, FLAGS, libc::AF_UNSPEC) }; if fd < 0 { Err(std::io::Error::last_os_error()) } else { diff --git a/src/unix/linux.rs b/src/unix/linux.rs index 7d1a77b..d342b90 100644 --- a/src/unix/linux.rs +++ b/src/unix/linux.rs @@ -1,4 +1,5 @@ #![allow(unsafe_code)] +use async_io::Async; use std::{collections::{HashSet, VecDeque}, io::{Error, Result}, mem::MaybeUninit, @@ -21,7 +22,7 @@ struct sockaddr_nl { #[derive(Debug)] pub(crate) struct NetlinkSocket { - fd: RoutingSocket, + fd: Async, address: sockaddr_nl, seqnum: u32, pid: u32, @@ -35,7 +36,7 @@ const SOCKADDR_NL_SIZE: libc::socklen_t = size_of!(sockaddr_nl) as _; impl NetlinkSocket { pub(crate) fn new() -> Result { - let fd = RoutingSocket::new()?; + let fd = Async::new(RoutingSocket::new()?)?; unsafe { let _: [u8; SOCKADDR_NL_SIZE as usize - size_of!(libc::sockaddr_nl)] = []; let mut address: sockaddr_nl = std::mem::zeroed(); @@ -63,7 +64,7 @@ impl NetlinkSocket { } } - pub(crate) fn send(&mut self) -> Result<()> { + pub(crate) async fn send(&mut self) -> Result<()> { #[repr(C)] struct Nlmsg { hdr: libc::nlmsghdr, @@ -94,86 +95,102 @@ impl NetlinkSocket { rtm_flags: libc::RTM_F_NOTIFY, }, }; - let msg: *const _ = &msg; - let address: *const _ = &self.address; - let status = unsafe { - libc::sendto( - self.fd.as_raw_fd(), - msg as *const _, - size_of!(Nlmsg), - libc::MSG_NOSIGNAL, - address as _, - std::mem::size_of_val(&self.address) as _, - ) - }; - if status == size_of!(Nlmsg) as _ { - Ok(()) - } else if status == -1 { - Err(std::io::Error::last_os_error()) - } else { - unreachable!("datagram sockets do not send partial messages") - } + self.fd + .write_with(|fd| { + let msg: *const _ = &msg; + let address: *const _ = &self.address; + let status = unsafe { + libc::sendto( + fd.as_raw_fd(), + msg as *const _, + size_of!(Nlmsg), + libc::MSG_NOSIGNAL, + address as _, + std::mem::size_of_val(&self.address) as _, + ) + }; + + if status == size_of!(Nlmsg) as _ { + Ok(()) + } else if status == -1 { + Err(std::io::Error::last_os_error()) + } else { + unreachable!("datagram sockets do not send partial messages") + } + }) + .await } - fn recv(&self, buf: &mut Vec, flags: libc::c_int) -> Status> { - let mut address = MaybeUninit::::uninit(); - let mut iovec = libc::iovec { - iov_base: buf.as_mut_ptr() as *mut _, - iov_len: buf.capacity() * size_of!(u64), - }; + async fn recv(&self, buf: &mut Vec, flags: libc::c_int) -> Status> { + loop { + let res = self + .fd + .read_with(|fd| { + let mut address = MaybeUninit::::uninit(); + let mut iovec = libc::iovec { + iov_base: buf.as_mut_ptr() as *mut _, + iov_len: buf.capacity() * size_of!(u64), + }; + let mut msghdr = libc::msghdr { + msg_name: address.as_mut_ptr() as _, + msg_namelen: size_of!(libc::sockaddr_nl) as u32, + msg_iov: &mut iovec, + msg_iovlen: 1, + msg_control: std::ptr::null_mut(), + msg_controllen: 0, + msg_flags: 0, + }; - let mut msghdr = libc::msghdr { - msg_name: address.as_mut_ptr() as _, - msg_namelen: size_of!(libc::sockaddr_nl) as u32, - msg_iov: &mut iovec, - msg_iovlen: 1, - msg_control: std::ptr::null_mut(), - msg_controllen: 0, - msg_flags: 0, - }; + let status = unsafe { libc::recvmsg(fd.as_raw_fd(), &mut msghdr, flags) }; + if status < 0 { + return Ok(Some(match unsafe { *libc::__errno_location() } { + libc::ENOBUFS => Status::Desync, + libc::EAGAIN => { + return Err(std::io::Error::from_raw_os_error(libc::EAGAIN)) + } + errno => Status::IO(std::io::Error::from_raw_os_error(errno)), + })) + } - loop { - let status = unsafe { libc::recvmsg(self.as_raw_fd(), &mut msghdr, flags) }; - if status < 0 { - return match unsafe { *libc::__errno_location() } { - libc::ENOBUFS => Status::Desync, - errno => Status::IO(std::io::Error::from_raw_os_error(errno)), - } - } - if msghdr.msg_namelen as usize != size_of!(libc::sockaddr_nl) - || msghdr.msg_flags & (libc::MSG_TRUNC | libc::MSG_CTRUNC) != 0 - { - return Status::Desync - } - // SAFETY: we just checked that the kernel filled in the right size - // of address - let address = unsafe { address.assume_init() }; - if address.nl_family != libc::AF_NETLINK as u16 { - // wrong address family? - return Status::Desync - } - if address.nl_pid != 0 { - // message not from kernel - continue + if msghdr.msg_namelen as usize != size_of!(libc::sockaddr_nl) + || msghdr.msg_flags & (libc::MSG_TRUNC | libc::MSG_CTRUNC) != 0 + { + return Ok(Some(Status::Desync)) + } + // SAFETY: we just checked that the kernel filled in the right size + // of address + let address = unsafe { address.assume_init() }; + if address.nl_family != libc::AF_NETLINK as u16 { + // wrong address family? + return Ok(Some(Status::Desync)) + } + if address.nl_pid != 0 { + // message not from kernel + return Ok(None) + } + Ok(Some(Status::Data(unsafe { + NetlinkIterator::new(core::slice::from_raw_parts( + iovec.iov_base as _, + status as _, + )) + }))) + }) + .await; + if let Ok(Some(status)) = res { + return status } - break Status::Data(unsafe { - NetlinkIterator::new(core::slice::from_raw_parts( - iovec.iov_base as _, - status as _, - )) - }) } } - pub(super) fn next( + pub(super) async fn next( &mut self, buf: &mut Vec, queue: &mut VecDeque, hash: &mut HashSet, ) -> Status<()> { let flags = libc::MSG_TRUNC | libc::MSG_CMSG_CLOEXEC; - match self.recv(buf, flags) { + match self.recv(buf, flags).await { Status::Data(iter) => { dump_iterator(queue, 0, iter, hash, self.pid); Status::Data(()) @@ -183,16 +200,16 @@ impl NetlinkSocket { } } - pub(crate) fn resync( + pub(crate) async fn resync( &mut self, buf: &mut Vec, queue: &mut VecDeque, hash: &mut HashSet, ) -> Result<()> { let flags = libc::MSG_TRUNC | libc::MSG_CMSG_CLOEXEC; - self.send()?; + self.send().await?; loop { - match self.recv(buf, flags) { + match self.recv(buf, flags).await { Status::IO(e) => return Err(e), Status::Desync => { queue.clear(); @@ -264,81 +281,86 @@ impl AsRawFd for NetlinkSocket { #[cfg(test)] mod tests { use super::*; + #[test] fn it_works() { - let mut sock = NetlinkSocket::new().unwrap(); - let flags = libc::MSG_TRUNC | libc::MSG_CMSG_CLOEXEC | libc::MSG_DONTWAIT; + async_io::block_on(async { + let mut sock = NetlinkSocket::new().unwrap(); + let flags = libc::MSG_TRUNC | libc::MSG_CMSG_CLOEXEC | libc::MSG_DONTWAIT; - sock.send().unwrap(); - unsafe { - let mut s: MaybeUninit = std::mem::MaybeUninit::uninit(); - std::ptr::write((s.as_mut_ptr() as *mut u16).offset(1), 0xFFFFu16); - let mut l: libc::socklen_t = size_of!(libc::sockaddr_nl) as _; - assert_eq!( - libc::getsockname(sock.as_raw_fd(), s.as_mut_ptr() as _, &mut l), - 0 - ); - assert_eq!(l, size_of!(libc::sockaddr_nl) as libc::socklen_t); - assert_eq!(size_of!(libc::sockaddr_nl), 12); - assert_eq!(size_of!(libc::sa_family_t), 2); - assert_eq!(std::ptr::read((s.as_ptr() as *const u16).offset(1)), 0); - let s = s.assume_init(); - assert_eq!(s.nl_family, libc::AF_NETLINK as libc::sa_family_t); - println!("Bound to PID {} and groups {}", s.nl_pid, s.nl_groups); - } - let mut buf = Vec::with_capacity(8192); - loop { - let iter = match sock.recv(&mut buf, flags) { - Status::Data(e) => e, - _ => panic!(), - }; - for (hdr, mut body) in iter { - let flags = hdr.nlmsg_flags; - if hdr.nlmsg_seq != 0 && hdr.nlmsg_seq != sock.seqnum { - continue - } - match hdr.nlmsg_type as i32 { - libc::NLMSG_NOOP => continue, - libc::NLMSG_ERROR => panic!("we got an error!"), - libc::NLMSG_OVERRUN => panic!("buffer overrun!"), - libc::NLMSG_DONE => return, - RTM_NEWROUTE | RTM_DELROUTE => { - let mut the_ip = None; - let (hdr, iter) = - rtnetlink::read_rtmsg(&mut body).expect("bad message from kernel"); - match (hdr.rtm_family as i32, hdr.rtm_table, hdr.rtm_type) { - (libc::AF_INET, libc::RT_TABLE_LOCAL, libc::RTN_LOCAL) => {} - (libc::AF_INET6, libc::RT_TABLE_LOCAL, libc::RTN_LOCAL) => {} - (libc::AF_INET, ..) => continue, - (libc::AF_INET6, ..) => continue, - _ => unreachable!(), - } - for i in iter.filter_map(|e| match e { - rtnetlink::RtaMessage::IPAddr(e) => Some(e), - rtnetlink::RtaMessage::Other => None, - }) { - assert!(std::mem::replace(&mut the_ip, Some(i.clone())).is_none()); - assert_eq!(hdr.rtm_src_len, 0); - match i { - std::net::IpAddr::V4(_) => { - assert_eq!(hdr.rtm_scope, libc::RT_SCOPE_HOST); - assert_eq!(hdr.rtm_family as i32, libc::AF_INET); - } - std::net::IpAddr::V6(_) => { - assert_eq!(hdr.rtm_scope, libc::RT_SCOPE_UNIVERSE); - assert_eq!(hdr.rtm_family as i32, libc::AF_INET6); + sock.send().await.unwrap(); + unsafe { + let mut s: MaybeUninit = std::mem::MaybeUninit::uninit(); + std::ptr::write((s.as_mut_ptr() as *mut u16).offset(1), 0xFFFFu16); + let mut l: libc::socklen_t = size_of!(libc::sockaddr_nl) as _; + assert_eq!( + libc::getsockname(sock.as_raw_fd(), s.as_mut_ptr() as _, &mut l), + 0 + ); + assert_eq!(l, size_of!(libc::sockaddr_nl) as libc::socklen_t); + assert_eq!(size_of!(libc::sockaddr_nl), 12); + assert_eq!(size_of!(libc::sa_family_t), 2); + assert_eq!(std::ptr::read((s.as_ptr() as *const u16).offset(1)), 0); + let s = s.assume_init(); + assert_eq!(s.nl_family, libc::AF_NETLINK as libc::sa_family_t); + // println!("Bound to PID {} and groups {}", s.nl_pid, + // s.nl_groups); + } + let mut buf = Vec::with_capacity(8192); + loop { + let iter = match sock.recv(&mut buf, flags).await { + Status::Data(e) => e, + _ => panic!(), + }; + for (hdr, mut body) in iter { + let flags = hdr.nlmsg_flags; + if hdr.nlmsg_seq != 0 && hdr.nlmsg_seq != sock.seqnum { + continue + } + match hdr.nlmsg_type as i32 { + libc::NLMSG_NOOP => continue, + libc::NLMSG_ERROR => panic!("we got an error!"), + libc::NLMSG_OVERRUN => panic!("buffer overrun!"), + libc::NLMSG_DONE => return, + RTM_NEWROUTE | RTM_DELROUTE => { + let mut the_ip = None; + let (hdr, iter) = + rtnetlink::read_rtmsg(&mut body).expect("bad message from kernel"); + match (hdr.rtm_family as i32, hdr.rtm_table, hdr.rtm_type) { + (libc::AF_INET, libc::RT_TABLE_LOCAL, libc::RTN_LOCAL) => {} + (libc::AF_INET6, libc::RT_TABLE_LOCAL, libc::RTN_LOCAL) => {} + (libc::AF_INET, ..) => continue, + (libc::AF_INET6, ..) => continue, + _ => unreachable!(), + } + for i in iter.filter_map(|e| match e { + rtnetlink::RtaMessage::IPAddr(e) => Some(e), + rtnetlink::RtaMessage::Other => None, + }) { + assert!(std::mem::replace(&mut the_ip, Some(i.clone())).is_none()); + assert_eq!(hdr.rtm_src_len, 0); + match i { + std::net::IpAddr::V4(_) => { + assert_eq!(hdr.rtm_scope, libc::RT_SCOPE_HOST); + assert_eq!(hdr.rtm_family as i32, libc::AF_INET); + } + std::net::IpAddr::V6(_) => { + assert_eq!(hdr.rtm_scope, libc::RT_SCOPE_UNIVERSE); + assert_eq!(hdr.rtm_family as i32, libc::AF_INET6); + } } + // println!("IP address {}/{}", i, + // hdr.rtm_dst_len) } - println!("IP address {}/{}", i, hdr.rtm_dst_len) + assert!(the_ip.is_some()); } - assert!(the_ip.is_some()); + _ => panic!("bad messge from kernel: type {:?}", hdr.nlmsg_type), + } + if flags & libc::NLM_F_MULTI as u16 == 0 { + break } - _ => panic!("bad messge from kernel: type {:?}", hdr.nlmsg_type), - } - if flags & libc::NLM_F_MULTI as u16 == 0 { - break } } - } + }); } } diff --git a/src/windows.rs b/src/windows.rs index 2a64cc0..36e03fe 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -2,68 +2,117 @@ #[cfg(not(windows))] compile_error!("this module only supports Windows!"); -#[allow( - nonstandard_style, - trivial_numeric_casts, - trivial_casts, - unsafe_code, - unused, - unreachable_pub, - missing_docs -)] -mod bindings; -use bindings::*; +use crate::Event; +use futures_lite::future::poll_fn; +use std::{collections::{HashSet, VecDeque}, + net::IpAddr, + sync::{atomic::{AtomicBool, Ordering}, + Arc}, + task::{Poll, Waker}}; +use winapi::shared::{netioapi::{CancelMibChangeNotify2, NotifyIpInterfaceChange, + MIB_IPINTERFACE_ROW, MIB_NOTIFICATION_TYPE}, + ntdef::{HANDLE, PVOID}, + winerror::NO_ERROR, + ws2def::AF_UNSPEC}; -#[link(name = "iphlpapi")] -extern "C" {} +/// An address set/watcher +#[derive(Debug)] +pub struct AddrSet { + addrs: HashSet, + queue: VecDeque, + waker: Option, + notif: RouteChangeNotification, + resync: Arc, +} + +impl AddrSet { + /// Create a watcher + pub async fn new() -> std::io::Result { + let resync = Arc::new(AtomicBool::new(true)); + Ok(Self { + addrs: Default::default(), + queue: Default::default(), + waker: Default::default(), + resync: resync.clone(), + notif: RouteChangeNotification::new(Box::new(move |_, _| { + resync.store(true, Ordering::SeqCst); + }))?, + }) + } + + fn resync(&mut self) -> std::io::Result<()> { + let addrs = if_addrs::get_if_addrs()?; + for old_addr in self.addrs.clone() { + if addrs.iter().find(|addr| addr.ip() == old_addr).is_none() { + self.addrs.remove(&old_addr); + self.queue.push_back(Event::Delete(old_addr)); + } + } + for new_addr in addrs { + let ip = new_addr.ip(); + if self.addrs.insert(ip) { + self.queue.push_back(Event::New(ip)); + } + } + if let Some(waker) = self.waker.take() { + waker.wake(); + } + Ok(()) + } + + /// Returns a future for the next event. + pub async fn next(&mut self) -> std::io::Result { + poll_fn(|cx| { + self.waker = Some(cx.waker().clone()); + if self.resync.load(Ordering::SeqCst) { + if let Err(error) = self.resync() { + return Poll::Ready(Err(error)) + } + } + if let Some(event) = self.queue.pop_front() { + Poll::Ready(Ok(event)) + } else { + Poll::Pending + } + }) + .await + } +} /// Route change notifications -#[allow(missing_debug_implementations)] -pub struct RouteChangeNotification { +#[derive(Debug)] +struct RouteChangeNotification { handle: HANDLE, callback: *mut RouteChangeCallback, // actual callback follows } -#[cfg(any())] -fn align_to() -> Option<(Layout, usize)> { - let layout_t = Layout::new::(); - let layout_u = Layout::new::(); - assert!(layout_t.size() >= layout_t.align()); - let align = std::cmp::max(layout_t.size(), layout_u.align()); - if (usize::MAX >> 1).checked_sub(layout_u.size())? < align { - None - } else { - unsafe { Layout::from_size_align_unchecked(align + layout_u.size(), align) } - } -} - /// The type of route change callbacks -pub type RouteChangeCallback = Box; +type RouteChangeCallback = Box; impl RouteChangeNotification { /// Register for route change notifications - pub fn new(cb: RouteChangeCallback) -> Result { + fn new(cb: RouteChangeCallback) -> std::io::Result { #[allow(non_snake_case)] - unsafe extern "stdcall" fn global_callback( + unsafe extern "system" fn global_callback( CallerContext: PVOID, - Row: PMIB_IPFORWARD_ROW2, + Row: *mut MIB_IPINTERFACE_ROW, NotificationType: MIB_NOTIFICATION_TYPE, ) { - (**(CallerContext as *mut RouteChangeCallback))(&*Row, NotificationType) + (**(CallerContext as *const RouteChangeCallback))(&*Row, NotificationType) } let mut handle = core::ptr::null_mut(); let callback = Box::into_raw(Box::new(cb)); if unsafe { - NotifyRouteChange2( + NotifyIpInterfaceChange( AF_UNSPEC as _, Some(global_callback), callback as _, 0, &mut handle, ) - } != NO_ERROR as _ + } != NO_ERROR { - Err(()) + Err(std::io::Error::last_os_error()) } else { Ok(Self { callback, handle }) } @@ -79,9 +128,13 @@ impl Drop for RouteChangeNotification { } } +unsafe impl Send for RouteChangeNotification {} + #[cfg(test)] mod tests { use super::*; + use winapi::{shared::minwindef::DWORD, + um::{processthreadsapi::GetCurrentThreadId, synchapi::SleepEx}}; fn get_current_thread_id() -> DWORD { unsafe { GetCurrentThreadId() } } #[test] diff --git a/src/windows/bindings.rs b/src/windows/bindings.rs deleted file mode 100644 index e7376be..0000000 --- a/src/windows/bindings.rs +++ /dev/null @@ -1,1269 +0,0 @@ -// automatically generated by rust-bindgen - -#[repr(C)] -#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct __BindgenBitfieldUnit { - storage: Storage, - align: [Align; 0], -} -impl __BindgenBitfieldUnit { - #[inline] - pub const fn new(storage: Storage) -> Self { Self { storage, align: [] } } -} -impl __BindgenBitfieldUnit -where - Storage: AsRef<[u8]> + AsMut<[u8]>, -{ - #[inline] - pub fn get_bit(&self, index: usize) -> bool { - debug_assert!(index / 8 < self.storage.as_ref().len()); - let byte_index = index / 8; - let byte = self.storage.as_ref()[byte_index]; - let bit_index = if cfg!(target_endian = "big") { - 7 - (index % 8) - } else { - index % 8 - }; - let mask = 1 << bit_index; - byte & mask == mask - } - - #[inline] - pub fn set_bit(&mut self, index: usize, val: bool) { - debug_assert!(index / 8 < self.storage.as_ref().len()); - let byte_index = index / 8; - let byte = &mut self.storage.as_mut()[byte_index]; - let bit_index = if cfg!(target_endian = "big") { - 7 - (index % 8) - } else { - index % 8 - }; - let mask = 1 << bit_index; - if val { - *byte |= mask; - } else { - *byte &= !mask; - } - } - - #[inline] - pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { - debug_assert!(bit_width <= 64); - debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); - debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); - let mut val = 0; - for i in 0..(bit_width as usize) { - if self.get_bit(i + bit_offset) { - let index = if cfg!(target_endian = "big") { - bit_width as usize - 1 - i - } else { - i - }; - val |= 1 << index; - } - } - val - } - - #[inline] - pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { - debug_assert!(bit_width <= 64); - debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); - debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); - for i in 0..(bit_width as usize) { - let mask = 1 << i; - let val_bit_is_set = val & mask == mask; - let index = if cfg!(target_endian = "big") { - bit_width as usize - 1 - i - } else { - i - }; - self.set_bit(index + bit_offset, val_bit_is_set); - } - } -} -pub const NO_ERROR: u32 = 0; -pub const AF_UNSPEC: u32 = 0; -pub type ULONG = ::std::os::raw::c_ulong; -pub type UCHAR = ::std::os::raw::c_uchar; -pub type WINBOOL = ::std::os::raw::c_int; -pub type BYTE = ::std::os::raw::c_uchar; -pub type DWORD = ::std::os::raw::c_ulong; -pub type UINT8 = ::std::os::raw::c_uchar; -pub type ULONG64 = ::std::os::raw::c_ulonglong; -pub type PVOID = *mut ::std::os::raw::c_void; -pub type LONG = ::std::os::raw::c_long; -pub type HANDLE = *mut ::std::os::raw::c_void; -pub type BOOLEAN = BYTE; -extern "stdcall" { - pub fn GetCurrentThreadId() -> DWORD; -} -extern "stdcall" { - pub fn SleepEx(dwMilliseconds: DWORD, bAlertable: WINBOOL) -> DWORD; -} -pub type NTSTATUS = LONG; -pub type u_char = ::std::os::raw::c_uchar; -pub type u_short = ::std::os::raw::c_ushort; -pub type u_long = ::std::os::raw::c_ulong; -#[repr(C)] -#[derive(Copy, Clone)] -pub struct in_addr { - pub S_un: in_addr__bindgen_ty_1, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union in_addr__bindgen_ty_1 { - pub S_un_b: in_addr__bindgen_ty_1__bindgen_ty_1, - pub S_un_w: in_addr__bindgen_ty_1__bindgen_ty_2, - pub S_addr: u_long, - _bindgen_union_align: u32, -} -#[repr(C)] -#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] -pub struct in_addr__bindgen_ty_1__bindgen_ty_1 { - pub s_b1: u_char, - pub s_b2: u_char, - pub s_b3: u_char, - pub s_b4: u_char, -} -#[test] -fn bindgen_test_layout_in_addr__bindgen_ty_1__bindgen_ty_1() { - assert_eq!( - ::std::mem::size_of::(), - 4usize, - concat!("Size of: ", stringify!(in_addr__bindgen_ty_1__bindgen_ty_1)) - ); - assert_eq!( - ::std::mem::align_of::(), - 1usize, - concat!( - "Alignment of ", - stringify!(in_addr__bindgen_ty_1__bindgen_ty_1) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::())).s_b1 as *const _ - as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(in_addr__bindgen_ty_1__bindgen_ty_1), - "::", - stringify!(s_b1) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::())).s_b2 as *const _ - as usize - }, - 1usize, - concat!( - "Offset of field: ", - stringify!(in_addr__bindgen_ty_1__bindgen_ty_1), - "::", - stringify!(s_b2) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::())).s_b3 as *const _ - as usize - }, - 2usize, - concat!( - "Offset of field: ", - stringify!(in_addr__bindgen_ty_1__bindgen_ty_1), - "::", - stringify!(s_b3) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::())).s_b4 as *const _ - as usize - }, - 3usize, - concat!( - "Offset of field: ", - stringify!(in_addr__bindgen_ty_1__bindgen_ty_1), - "::", - stringify!(s_b4) - ) - ); -} -#[repr(C)] -#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] -pub struct in_addr__bindgen_ty_1__bindgen_ty_2 { - pub s_w1: u_short, - pub s_w2: u_short, -} -#[test] -fn bindgen_test_layout_in_addr__bindgen_ty_1__bindgen_ty_2() { - assert_eq!( - ::std::mem::size_of::(), - 4usize, - concat!("Size of: ", stringify!(in_addr__bindgen_ty_1__bindgen_ty_2)) - ); - assert_eq!( - ::std::mem::align_of::(), - 2usize, - concat!( - "Alignment of ", - stringify!(in_addr__bindgen_ty_1__bindgen_ty_2) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::())).s_w1 as *const _ - as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(in_addr__bindgen_ty_1__bindgen_ty_2), - "::", - stringify!(s_w1) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::())).s_w2 as *const _ - as usize - }, - 2usize, - concat!( - "Offset of field: ", - stringify!(in_addr__bindgen_ty_1__bindgen_ty_2), - "::", - stringify!(s_w2) - ) - ); -} -#[test] -fn bindgen_test_layout_in_addr__bindgen_ty_1() { - assert_eq!( - ::std::mem::size_of::(), - 4usize, - concat!("Size of: ", stringify!(in_addr__bindgen_ty_1)) - ); - assert_eq!( - ::std::mem::align_of::(), - 4usize, - concat!("Alignment of ", stringify!(in_addr__bindgen_ty_1)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).S_un_b as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(in_addr__bindgen_ty_1), - "::", - stringify!(S_un_b) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).S_un_w as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(in_addr__bindgen_ty_1), - "::", - stringify!(S_un_w) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).S_addr as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(in_addr__bindgen_ty_1), - "::", - stringify!(S_addr) - ) - ); -} -impl ::std::fmt::Debug for in_addr__bindgen_ty_1 { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "in_addr__bindgen_ty_1 {{ union }}") - } -} -#[test] -fn bindgen_test_layout_in_addr() { - assert_eq!( - ::std::mem::size_of::(), - 4usize, - concat!("Size of: ", stringify!(in_addr)) - ); - assert_eq!( - ::std::mem::align_of::(), - 4usize, - concat!("Alignment of ", stringify!(in_addr)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).S_un as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(in_addr), - "::", - stringify!(S_un) - ) - ); -} -impl ::std::fmt::Debug for in_addr { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "in_addr {{ S_un: {:?} }}", self.S_un) - } -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct sockaddr_in { - pub sin_family: ::std::os::raw::c_short, - pub sin_port: u_short, - pub sin_addr: in_addr, - pub sin_zero: [::std::os::raw::c_char; 8usize], -} -#[test] -fn bindgen_test_layout_sockaddr_in() { - assert_eq!( - ::std::mem::size_of::(), - 16usize, - concat!("Size of: ", stringify!(sockaddr_in)) - ); - assert_eq!( - ::std::mem::align_of::(), - 4usize, - concat!("Alignment of ", stringify!(sockaddr_in)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).sin_family as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(sockaddr_in), - "::", - stringify!(sin_family) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).sin_port as *const _ as usize }, - 2usize, - concat!( - "Offset of field: ", - stringify!(sockaddr_in), - "::", - stringify!(sin_port) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).sin_addr as *const _ as usize }, - 4usize, - concat!( - "Offset of field: ", - stringify!(sockaddr_in), - "::", - stringify!(sin_addr) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).sin_zero as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(sockaddr_in), - "::", - stringify!(sin_zero) - ) - ); -} -impl ::std::fmt::Debug for sockaddr_in { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!( - f, - "sockaddr_in {{ sin_family: {:?}, sin_port: {:?}, sin_addr: {:?}, sin_zero: {:?} }}", - self.sin_family, self.sin_port, self.sin_addr, self.sin_zero - ) - } -} -pub type SOCKADDR_IN = sockaddr_in; -#[repr(C)] -#[derive(Copy, Clone)] -pub struct _SCOPE_ID { - pub __bindgen_anon_1: _SCOPE_ID__bindgen_ty_1, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union _SCOPE_ID__bindgen_ty_1 { - pub __bindgen_anon_1: _SCOPE_ID__bindgen_ty_1__bindgen_ty_1, - pub Value: ULONG, - _bindgen_union_align: u32, -} -#[repr(C)] -#[repr(align(4))] -#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] -pub struct _SCOPE_ID__bindgen_ty_1__bindgen_ty_1 { - pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize], u32>, -} -#[test] -fn bindgen_test_layout__SCOPE_ID__bindgen_ty_1__bindgen_ty_1() { - assert_eq!( - ::std::mem::size_of::<_SCOPE_ID__bindgen_ty_1__bindgen_ty_1>(), - 4usize, - concat!( - "Size of: ", - stringify!(_SCOPE_ID__bindgen_ty_1__bindgen_ty_1) - ) - ); - assert_eq!( - ::std::mem::align_of::<_SCOPE_ID__bindgen_ty_1__bindgen_ty_1>(), - 4usize, - concat!( - "Alignment of ", - stringify!(_SCOPE_ID__bindgen_ty_1__bindgen_ty_1) - ) - ); -} -impl _SCOPE_ID__bindgen_ty_1__bindgen_ty_1 { - #[inline] - pub fn Zone(&self) -> ULONG { - unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 28u8) as u32) } - } - - #[inline] - pub fn set_Zone(&mut self, val: ULONG) { - unsafe { - let val: u32 = ::std::mem::transmute(val); - self._bitfield_1.set(0usize, 28u8, val as u64) - } - } - - #[inline] - pub fn Level(&self) -> ULONG { - unsafe { ::std::mem::transmute(self._bitfield_1.get(28usize, 4u8) as u32) } - } - - #[inline] - pub fn set_Level(&mut self, val: ULONG) { - unsafe { - let val: u32 = ::std::mem::transmute(val); - self._bitfield_1.set(28usize, 4u8, val as u64) - } - } - - #[inline] - pub fn new_bitfield_1(Zone: ULONG, Level: ULONG) -> __BindgenBitfieldUnit<[u8; 4usize], u32> { - let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 4usize], u32> = - Default::default(); - __bindgen_bitfield_unit.set(0usize, 28u8, { - let Zone: u32 = unsafe { ::std::mem::transmute(Zone) }; - Zone as u64 - }); - __bindgen_bitfield_unit.set(28usize, 4u8, { - let Level: u32 = unsafe { ::std::mem::transmute(Level) }; - Level as u64 - }); - __bindgen_bitfield_unit - } -} -#[test] -fn bindgen_test_layout__SCOPE_ID__bindgen_ty_1() { - assert_eq!( - ::std::mem::size_of::<_SCOPE_ID__bindgen_ty_1>(), - 4usize, - concat!("Size of: ", stringify!(_SCOPE_ID__bindgen_ty_1)) - ); - assert_eq!( - ::std::mem::align_of::<_SCOPE_ID__bindgen_ty_1>(), - 4usize, - concat!("Alignment of ", stringify!(_SCOPE_ID__bindgen_ty_1)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_SCOPE_ID__bindgen_ty_1>())).Value as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_SCOPE_ID__bindgen_ty_1), - "::", - stringify!(Value) - ) - ); -} -impl ::std::fmt::Debug for _SCOPE_ID__bindgen_ty_1 { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "_SCOPE_ID__bindgen_ty_1 {{ union }}") - } -} -#[test] -fn bindgen_test_layout__SCOPE_ID() { - assert_eq!( - ::std::mem::size_of::<_SCOPE_ID>(), - 4usize, - concat!("Size of: ", stringify!(_SCOPE_ID)) - ); - assert_eq!( - ::std::mem::align_of::<_SCOPE_ID>(), - 4usize, - concat!("Alignment of ", stringify!(_SCOPE_ID)) - ); -} -impl ::std::fmt::Debug for _SCOPE_ID { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!( - f, - "_SCOPE_ID {{ __bindgen_anon_1: {:?} }}", - self.__bindgen_anon_1 - ) - } -} -pub type SCOPE_ID = _SCOPE_ID; -pub type ADDRESS_FAMILY = u_short; -#[repr(C)] -#[derive(Copy, Clone)] -pub struct in6_addr { - pub u: in6_addr__bindgen_ty_1, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union in6_addr__bindgen_ty_1 { - pub Byte: [u_char; 16usize], - pub Word: [u_short; 8usize], - _bindgen_union_align: [u16; 8usize], -} -#[test] -fn bindgen_test_layout_in6_addr__bindgen_ty_1() { - assert_eq!( - ::std::mem::size_of::(), - 16usize, - concat!("Size of: ", stringify!(in6_addr__bindgen_ty_1)) - ); - assert_eq!( - ::std::mem::align_of::(), - 2usize, - concat!("Alignment of ", stringify!(in6_addr__bindgen_ty_1)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).Byte as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(in6_addr__bindgen_ty_1), - "::", - stringify!(Byte) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).Word as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(in6_addr__bindgen_ty_1), - "::", - stringify!(Word) - ) - ); -} -impl ::std::fmt::Debug for in6_addr__bindgen_ty_1 { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "in6_addr__bindgen_ty_1 {{ union }}") - } -} -#[test] -fn bindgen_test_layout_in6_addr() { - assert_eq!( - ::std::mem::size_of::(), - 16usize, - concat!("Size of: ", stringify!(in6_addr)) - ); - assert_eq!( - ::std::mem::align_of::(), - 2usize, - concat!("Alignment of ", stringify!(in6_addr)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).u as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(in6_addr), - "::", - stringify!(u) - ) - ); -} -impl ::std::fmt::Debug for in6_addr { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "in6_addr {{ u: {:?} }}", self.u) - } -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct sockaddr_in6 { - pub sin6_family: ::std::os::raw::c_short, - pub sin6_port: u_short, - pub sin6_flowinfo: u_long, - pub sin6_addr: in6_addr, - pub __bindgen_anon_1: sockaddr_in6__bindgen_ty_1, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union sockaddr_in6__bindgen_ty_1 { - pub sin6_scope_id: u_long, - pub sin6_scope_struct: SCOPE_ID, - _bindgen_union_align: u32, -} -#[test] -fn bindgen_test_layout_sockaddr_in6__bindgen_ty_1() { - assert_eq!( - ::std::mem::size_of::(), - 4usize, - concat!("Size of: ", stringify!(sockaddr_in6__bindgen_ty_1)) - ); - assert_eq!( - ::std::mem::align_of::(), - 4usize, - concat!("Alignment of ", stringify!(sockaddr_in6__bindgen_ty_1)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::())).sin6_scope_id as *const _ - as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(sockaddr_in6__bindgen_ty_1), - "::", - stringify!(sin6_scope_id) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::())).sin6_scope_struct as *const _ - as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(sockaddr_in6__bindgen_ty_1), - "::", - stringify!(sin6_scope_struct) - ) - ); -} -impl ::std::fmt::Debug for sockaddr_in6__bindgen_ty_1 { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "sockaddr_in6__bindgen_ty_1 {{ union }}") - } -} -#[test] -fn bindgen_test_layout_sockaddr_in6() { - assert_eq!( - ::std::mem::size_of::(), - 28usize, - concat!("Size of: ", stringify!(sockaddr_in6)) - ); - assert_eq!( - ::std::mem::align_of::(), - 4usize, - concat!("Alignment of ", stringify!(sockaddr_in6)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).sin6_family as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(sockaddr_in6), - "::", - stringify!(sin6_family) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).sin6_port as *const _ as usize }, - 2usize, - concat!( - "Offset of field: ", - stringify!(sockaddr_in6), - "::", - stringify!(sin6_port) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).sin6_flowinfo as *const _ as usize }, - 4usize, - concat!( - "Offset of field: ", - stringify!(sockaddr_in6), - "::", - stringify!(sin6_flowinfo) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::())).sin6_addr as *const _ as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(sockaddr_in6), - "::", - stringify!(sin6_addr) - ) - ); -} -impl ::std::fmt::Debug for sockaddr_in6 { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!( - f, - "sockaddr_in6 {{ sin6_family: {:?}, sin6_port: {:?}, sin6_flowinfo: {:?}, sin6_addr: \ - {:?}, __bindgen_anon_1: {:?} }}", - self.sin6_family, - self.sin6_port, - self.sin6_flowinfo, - self.sin6_addr, - self.__bindgen_anon_1 - ) - } -} -pub type SOCKADDR_IN6 = sockaddr_in6; -#[repr(C)] -#[derive(Copy, Clone)] -pub union _SOCKADDR_INET { - pub Ipv4: SOCKADDR_IN, - pub Ipv6: SOCKADDR_IN6, - pub si_family: ADDRESS_FAMILY, - _bindgen_union_align: [u32; 7usize], -} -#[test] -fn bindgen_test_layout__SOCKADDR_INET() { - assert_eq!( - ::std::mem::size_of::<_SOCKADDR_INET>(), - 28usize, - concat!("Size of: ", stringify!(_SOCKADDR_INET)) - ); - assert_eq!( - ::std::mem::align_of::<_SOCKADDR_INET>(), - 4usize, - concat!("Alignment of ", stringify!(_SOCKADDR_INET)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_SOCKADDR_INET>())).Ipv4 as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_SOCKADDR_INET), - "::", - stringify!(Ipv4) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_SOCKADDR_INET>())).Ipv6 as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_SOCKADDR_INET), - "::", - stringify!(Ipv6) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_SOCKADDR_INET>())).si_family as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_SOCKADDR_INET), - "::", - stringify!(si_family) - ) - ); -} -impl ::std::fmt::Debug for _SOCKADDR_INET { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "_SOCKADDR_INET {{ union }}") - } -} -pub type SOCKADDR_INET = _SOCKADDR_INET; -pub const NL_ROUTE_PROTOCOL_RouteProtocolOther: NL_ROUTE_PROTOCOL = 1; -pub const NL_ROUTE_PROTOCOL_RouteProtocolLocal: NL_ROUTE_PROTOCOL = 2; -pub const NL_ROUTE_PROTOCOL_RouteProtocolNetMgmt: NL_ROUTE_PROTOCOL = 3; -pub const NL_ROUTE_PROTOCOL_RouteProtocolIcmp: NL_ROUTE_PROTOCOL = 4; -pub const NL_ROUTE_PROTOCOL_RouteProtocolEgp: NL_ROUTE_PROTOCOL = 5; -pub const NL_ROUTE_PROTOCOL_RouteProtocolGgp: NL_ROUTE_PROTOCOL = 6; -pub const NL_ROUTE_PROTOCOL_RouteProtocolHello: NL_ROUTE_PROTOCOL = 7; -pub const NL_ROUTE_PROTOCOL_RouteProtocolRip: NL_ROUTE_PROTOCOL = 8; -pub const NL_ROUTE_PROTOCOL_RouteProtocolIsIs: NL_ROUTE_PROTOCOL = 9; -pub const NL_ROUTE_PROTOCOL_RouteProtocolEsIs: NL_ROUTE_PROTOCOL = 10; -pub const NL_ROUTE_PROTOCOL_RouteProtocolCisco: NL_ROUTE_PROTOCOL = 11; -pub const NL_ROUTE_PROTOCOL_RouteProtocolBbn: NL_ROUTE_PROTOCOL = 12; -pub const NL_ROUTE_PROTOCOL_RouteProtocolOspf: NL_ROUTE_PROTOCOL = 13; -pub const NL_ROUTE_PROTOCOL_RouteProtocolBgp: NL_ROUTE_PROTOCOL = 14; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_OTHER: NL_ROUTE_PROTOCOL = 1; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_OTHER: NL_ROUTE_PROTOCOL = 1; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_LOCAL: NL_ROUTE_PROTOCOL = 2; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_LOCAL: NL_ROUTE_PROTOCOL = 2; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_NETMGMT: NL_ROUTE_PROTOCOL = 3; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_NETMGMT: NL_ROUTE_PROTOCOL = 3; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_ICMP: NL_ROUTE_PROTOCOL = 4; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_ICMP: NL_ROUTE_PROTOCOL = 4; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_EGP: NL_ROUTE_PROTOCOL = 5; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_EGP: NL_ROUTE_PROTOCOL = 5; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_GGP: NL_ROUTE_PROTOCOL = 6; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_GGP: NL_ROUTE_PROTOCOL = 6; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_HELLO: NL_ROUTE_PROTOCOL = 7; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_HELLO: NL_ROUTE_PROTOCOL = 7; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_RIP: NL_ROUTE_PROTOCOL = 8; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_RIP: NL_ROUTE_PROTOCOL = 8; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_IS_IS: NL_ROUTE_PROTOCOL = 9; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_IS_IS: NL_ROUTE_PROTOCOL = 9; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_ES_IS: NL_ROUTE_PROTOCOL = 10; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_ES_IS: NL_ROUTE_PROTOCOL = 10; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_CISCO: NL_ROUTE_PROTOCOL = 11; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_CISCO: NL_ROUTE_PROTOCOL = 11; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_BBN: NL_ROUTE_PROTOCOL = 12; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_BBN: NL_ROUTE_PROTOCOL = 12; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_OSPF: NL_ROUTE_PROTOCOL = 13; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_OSPF: NL_ROUTE_PROTOCOL = 13; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_BGP: NL_ROUTE_PROTOCOL = 14; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_BGP: NL_ROUTE_PROTOCOL = 14; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_NT_AUTOSTATIC: NL_ROUTE_PROTOCOL = 10002; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_NT_AUTOSTATIC: NL_ROUTE_PROTOCOL = 10002; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_NT_STATIC: NL_ROUTE_PROTOCOL = 10006; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_NT_STATIC: NL_ROUTE_PROTOCOL = 10006; -pub const NL_ROUTE_PROTOCOL_MIB_IPPROTO_NT_STATIC_NON_DOD: NL_ROUTE_PROTOCOL = 10007; -pub const NL_ROUTE_PROTOCOL_PROTO_IP_NT_STATIC_NON_DOD: NL_ROUTE_PROTOCOL = 10007; -pub type NL_ROUTE_PROTOCOL = u32; -pub const _NL_ROUTE_ORIGIN_NlroManual: _NL_ROUTE_ORIGIN = 0; -pub const _NL_ROUTE_ORIGIN_NlroWellKnown: _NL_ROUTE_ORIGIN = 1; -pub const _NL_ROUTE_ORIGIN_NlroDHCP: _NL_ROUTE_ORIGIN = 2; -pub const _NL_ROUTE_ORIGIN_NlroRouterAdvertisement: _NL_ROUTE_ORIGIN = 3; -pub const _NL_ROUTE_ORIGIN_Nlro6to4: _NL_ROUTE_ORIGIN = 4; -pub type _NL_ROUTE_ORIGIN = u32; -pub use self::_NL_ROUTE_ORIGIN as NL_ROUTE_ORIGIN; -pub type NET_IFINDEX = ULONG; -#[repr(C)] -#[derive(Copy, Clone)] -pub union _NET_LUID { - pub Value: ULONG64, - pub Info: _NET_LUID__bindgen_ty_1, - _bindgen_union_align: u64, -} -#[repr(C)] -#[repr(align(8))] -#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] -pub struct _NET_LUID__bindgen_ty_1 { - pub _bitfield_1: __BindgenBitfieldUnit<[u8; 8usize], u32>, -} -#[test] -fn bindgen_test_layout__NET_LUID__bindgen_ty_1() { - assert_eq!( - ::std::mem::size_of::<_NET_LUID__bindgen_ty_1>(), - 8usize, - concat!("Size of: ", stringify!(_NET_LUID__bindgen_ty_1)) - ); - assert_eq!( - ::std::mem::align_of::<_NET_LUID__bindgen_ty_1>(), - 8usize, - concat!("Alignment of ", stringify!(_NET_LUID__bindgen_ty_1)) - ); -} -impl _NET_LUID__bindgen_ty_1 { - #[inline] - pub fn Reserved(&self) -> ULONG64 { - unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 24u8) as u64) } - } - - #[inline] - pub fn set_Reserved(&mut self, val: ULONG64) { - unsafe { - let val: u64 = ::std::mem::transmute(val); - self._bitfield_1.set(0usize, 24u8, val as u64) - } - } - - #[inline] - pub fn NetLuidIndex(&self) -> ULONG64 { - unsafe { ::std::mem::transmute(self._bitfield_1.get(24usize, 24u8) as u64) } - } - - #[inline] - pub fn set_NetLuidIndex(&mut self, val: ULONG64) { - unsafe { - let val: u64 = ::std::mem::transmute(val); - self._bitfield_1.set(24usize, 24u8, val as u64) - } - } - - #[inline] - pub fn IfType(&self) -> ULONG64 { - unsafe { ::std::mem::transmute(self._bitfield_1.get(48usize, 16u8) as u64) } - } - - #[inline] - pub fn set_IfType(&mut self, val: ULONG64) { - unsafe { - let val: u64 = ::std::mem::transmute(val); - self._bitfield_1.set(48usize, 16u8, val as u64) - } - } - - #[inline] - pub fn new_bitfield_1( - Reserved: ULONG64, - NetLuidIndex: ULONG64, - IfType: ULONG64, - ) -> __BindgenBitfieldUnit<[u8; 8usize], u32> { - let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 8usize], u32> = - Default::default(); - __bindgen_bitfield_unit.set(0usize, 24u8, { - let Reserved: u64 = unsafe { ::std::mem::transmute(Reserved) }; - Reserved as u64 - }); - __bindgen_bitfield_unit.set(24usize, 24u8, { - let NetLuidIndex: u64 = unsafe { ::std::mem::transmute(NetLuidIndex) }; - NetLuidIndex as u64 - }); - __bindgen_bitfield_unit.set(48usize, 16u8, { - let IfType: u64 = unsafe { ::std::mem::transmute(IfType) }; - IfType as u64 - }); - __bindgen_bitfield_unit - } -} -#[test] -fn bindgen_test_layout__NET_LUID() { - assert_eq!( - ::std::mem::size_of::<_NET_LUID>(), - 8usize, - concat!("Size of: ", stringify!(_NET_LUID)) - ); - assert_eq!( - ::std::mem::align_of::<_NET_LUID>(), - 8usize, - concat!("Alignment of ", stringify!(_NET_LUID)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_NET_LUID>())).Value as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_NET_LUID), - "::", - stringify!(Value) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_NET_LUID>())).Info as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_NET_LUID), - "::", - stringify!(Info) - ) - ); -} -impl ::std::fmt::Debug for _NET_LUID { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "_NET_LUID {{ union }}") - } -} -pub type NET_LUID = _NET_LUID; -pub const _MIB_NOTIFICATION_TYPE_MibParameterNotification: _MIB_NOTIFICATION_TYPE = 0; -pub const _MIB_NOTIFICATION_TYPE_MibAddInstance: _MIB_NOTIFICATION_TYPE = 1; -pub const _MIB_NOTIFICATION_TYPE_MibDeleteInstance: _MIB_NOTIFICATION_TYPE = 2; -pub const _MIB_NOTIFICATION_TYPE_MibInitialNotification: _MIB_NOTIFICATION_TYPE = 3; -pub type _MIB_NOTIFICATION_TYPE = u32; -pub use self::_MIB_NOTIFICATION_TYPE as MIB_NOTIFICATION_TYPE; -#[repr(C)] -#[derive(Copy, Clone)] -pub struct _IP_ADDRESS_PREFIX { - pub Prefix: SOCKADDR_INET, - pub PrefixLength: UINT8, -} -#[test] -fn bindgen_test_layout__IP_ADDRESS_PREFIX() { - assert_eq!( - ::std::mem::size_of::<_IP_ADDRESS_PREFIX>(), - 32usize, - concat!("Size of: ", stringify!(_IP_ADDRESS_PREFIX)) - ); - assert_eq!( - ::std::mem::align_of::<_IP_ADDRESS_PREFIX>(), - 4usize, - concat!("Alignment of ", stringify!(_IP_ADDRESS_PREFIX)) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_IP_ADDRESS_PREFIX>())).Prefix as *const _ as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_IP_ADDRESS_PREFIX), - "::", - stringify!(Prefix) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_IP_ADDRESS_PREFIX>())).PrefixLength as *const _ as usize }, - 28usize, - concat!( - "Offset of field: ", - stringify!(_IP_ADDRESS_PREFIX), - "::", - stringify!(PrefixLength) - ) - ); -} -impl ::std::fmt::Debug for _IP_ADDRESS_PREFIX { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!( - f, - "_IP_ADDRESS_PREFIX {{ Prefix: {:?}, PrefixLength: {:?} }}", - self.Prefix, self.PrefixLength - ) - } -} -pub type IP_ADDRESS_PREFIX = _IP_ADDRESS_PREFIX; -#[repr(C)] -#[derive(Copy, Clone)] -pub struct _MIB_IPFORWARD_ROW2 { - pub InterfaceLuid: NET_LUID, - pub InterfaceIndex: NET_IFINDEX, - pub DestinationPrefix: IP_ADDRESS_PREFIX, - pub NextHop: SOCKADDR_INET, - pub SitePrefixLength: UCHAR, - pub ValidLifetime: ULONG, - pub PreferredLifetime: ULONG, - pub Metric: ULONG, - pub Protocol: NL_ROUTE_PROTOCOL, - pub Loopback: BOOLEAN, - pub AutoconfigureAddress: BOOLEAN, - pub Publish: BOOLEAN, - pub Immortal: BOOLEAN, - pub Age: ULONG, - pub Origin: NL_ROUTE_ORIGIN, -} -#[test] -fn bindgen_test_layout__MIB_IPFORWARD_ROW2() { - assert_eq!( - ::std::mem::size_of::<_MIB_IPFORWARD_ROW2>(), - 104usize, - concat!("Size of: ", stringify!(_MIB_IPFORWARD_ROW2)) - ); - assert_eq!( - ::std::mem::align_of::<_MIB_IPFORWARD_ROW2>(), - 8usize, - concat!("Alignment of ", stringify!(_MIB_IPFORWARD_ROW2)) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).InterfaceLuid as *const _ as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(InterfaceLuid) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).InterfaceIndex as *const _ as usize - }, - 8usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(InterfaceIndex) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).DestinationPrefix as *const _ as usize - }, - 12usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(DestinationPrefix) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).NextHop as *const _ as usize }, - 44usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(NextHop) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).SitePrefixLength as *const _ as usize - }, - 72usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(SitePrefixLength) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).ValidLifetime as *const _ as usize - }, - 76usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(ValidLifetime) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).PreferredLifetime as *const _ as usize - }, - 80usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(PreferredLifetime) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).Metric as *const _ as usize }, - 84usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(Metric) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).Protocol as *const _ as usize }, - 88usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(Protocol) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).Loopback as *const _ as usize }, - 92usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(Loopback) - ) - ); - assert_eq!( - unsafe { - &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).AutoconfigureAddress as *const _ - as usize - }, - 93usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(AutoconfigureAddress) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).Publish as *const _ as usize }, - 94usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(Publish) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).Immortal as *const _ as usize }, - 95usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(Immortal) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).Age as *const _ as usize }, - 96usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(Age) - ) - ); - assert_eq!( - unsafe { &(*(::std::ptr::null::<_MIB_IPFORWARD_ROW2>())).Origin as *const _ as usize }, - 100usize, - concat!( - "Offset of field: ", - stringify!(_MIB_IPFORWARD_ROW2), - "::", - stringify!(Origin) - ) - ); -} -impl ::std::fmt::Debug for _MIB_IPFORWARD_ROW2 { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!( - f, - "_MIB_IPFORWARD_ROW2 {{ InterfaceLuid: {:?}, InterfaceIndex: {:?}, DestinationPrefix: \ - {:?}, NextHop: {:?}, SitePrefixLength: {:?}, ValidLifetime: {:?}, PreferredLifetime: \ - {:?}, Metric: {:?}, Protocol: {:?}, Loopback: {:?}, AutoconfigureAddress: {:?}, \ - Publish: {:?}, Immortal: {:?}, Age: {:?}, Origin: {:?} }}", - self.InterfaceLuid, - self.InterfaceIndex, - self.DestinationPrefix, - self.NextHop, - self.SitePrefixLength, - self.ValidLifetime, - self.PreferredLifetime, - self.Metric, - self.Protocol, - self.Loopback, - self.AutoconfigureAddress, - self.Publish, - self.Immortal, - self.Age, - self.Origin - ) - } -} -pub type MIB_IPFORWARD_ROW2 = _MIB_IPFORWARD_ROW2; -pub type PMIB_IPFORWARD_ROW2 = *mut _MIB_IPFORWARD_ROW2; -pub type PIPFORWARD_CHANGE_CALLBACK = ::std::option::Option< - unsafe extern "stdcall" fn( - CallerContext: PVOID, - Row: PMIB_IPFORWARD_ROW2, - NotificationType: MIB_NOTIFICATION_TYPE, - ), ->; -extern "stdcall" { - pub fn NotifyRouteChange2( - AddressFamily: ADDRESS_FAMILY, - Callback: PIPFORWARD_CHANGE_CALLBACK, - CallerContext: PVOID, - InitialNotification: BOOLEAN, - NotificationHandle: *mut HANDLE, - ) -> NTSTATUS; -} -extern "stdcall" { - pub fn CancelMibChangeNotify2(NotificationHandle: HANDLE) -> NTSTATUS; -}