5 use windows
::Win32
::Foundation
::ERROR_INVALID_HANDLE
;
6 use windows
::Win32
::Foundation
::ERROR_INVALID_PARAMETER
;
7 use windows
::Win32
::Foundation
::ERROR_NOT_ENOUGH_MEMORY
;
8 use windows
::Win32
::Foundation
::NO_ERROR
;
9 use windows
::Win32
::NetworkManagement
::IpHelper
::CancelMibChangeNotify2
;
10 use windows
::Win32
::NetworkManagement
::IpHelper
::MIB_NOTIFICATION_TYPE
;
11 use windows
::Win32
::NetworkManagement
::IpHelper
::MIB_UNICASTIPADDRESS_ROW
;
13 Foundation
::{BOOLEAN
, HANDLE
},
14 NetworkManagement
::IpHelper
::NotifyUnicastIpAddressChange
,
15 Networking
::WinSock
::AF_UNSPEC
,
23 /// The last result that we captured, for diffing
26 cb
: Box
<dyn
FnMut(Update
) + Send
+ '
static>,
29 pub(crate) struct WatchHandle
{
31 _state
: Pin
<Box
<Mutex
<WatchState
>>>,
34 impl Drop
for WatchHandle
{
37 let _
= CancelMibChangeNotify2(self.hnd
);
42 pub(crate) fn watch_interfaces
<F
: FnMut(Update
) + Send
+ '
static>(
44 ) -> Result
<WatchHandle
, Error
> {
45 let state
= Box
::pin(Mutex
::new(WatchState
{
46 prev_list
: List
::default(),
47 cb
: Box
::new(callback
),
49 let state_ctx
= &*state
.as_ref() as *const _
as *const c_void
;
51 let mut hnd
= HANDLE
::default();
53 NotifyUnicastIpAddressChange(
63 // Trigger an initial update.
64 // This is allowed to race with true updates because it
65 // will always calculate a diff and discard no-ops.
66 handle_notif(&mut state
.lock().unwrap
());
67 // Then return the handle
68 Ok(WatchHandle
{ hnd
, _state
: state
})
70 ERROR_INVALID_HANDLE
=> Err(Error
::Internal
),
71 ERROR_INVALID_PARAMETER
=> Err(Error
::Internal
),
72 ERROR_NOT_ENOUGH_MEMORY
=> Err(Error
::Internal
),
73 _
=> Err(Error
::Internal
), // TODO: Use FormatMessage and get real error
77 unsafe extern "system" fn notif(
79 _row
: *const MIB_UNICASTIPADDRESS_ROW
,
80 _notification_type
: MIB_NOTIFICATION_TYPE
,
82 let state_ptr
= ctx
as *const Mutex
<WatchState
>;
84 let state_guard
= &mut *state_ptr
86 .expect("callback ctx should never be null")
89 handle_notif(state_guard
);
93 fn handle_notif(state
: &mut WatchState
) {
94 let Ok(new_list
) = crate::list
::list_interfaces() else {
97 if new_list
== state
.prev_list
{
100 let update
= Update
{
101 interfaces
: new_list
.0.clone(),
102 diff
: new_list
.diff_from(&state
.prev_list
),
105 state
.prev_list
= new_list
;