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 handle_notif(&mut state
.lock().unwrap
(), crate::list
::list_interfaces()?
);
65 // Then return the handle
66 Ok(WatchHandle
{ hnd
, _state
: state
})
68 ERROR_INVALID_HANDLE
=> Err(Error
::Internal
),
69 ERROR_INVALID_PARAMETER
=> Err(Error
::Internal
),
70 ERROR_NOT_ENOUGH_MEMORY
=> Err(Error
::Internal
),
71 _
=> Err(Error
::Internal
), // TODO: Use FormatMessage and get real error
75 unsafe extern "system" fn notif(
77 _row
: *const MIB_UNICASTIPADDRESS_ROW
,
78 _notification_type
: MIB_NOTIFICATION_TYPE
,
80 let state_ptr
= ctx
as *const Mutex
<WatchState
>;
82 let state_guard
= &mut *state_ptr
84 .expect("callback ctx should never be null")
87 let Ok(new_list
) = crate::list
::list_interfaces() else {
90 handle_notif(state_guard
, new_list
);
94 fn handle_notif(state
: &mut WatchState
, new_list
: List
) {
95 if new_list
== state
.prev_list
{
99 interfaces
: new_list
.0.clone(),
100 diff
: new_list
.diff_from(&state
.prev_list
),
103 state
.prev_list
= new_list
;