summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2021-05-04 11:01:01 +0200
committerDavid Lönnhager <david.l@mullvad.net>2021-05-20 11:01:10 +0200
commit8e9a4e68af1669594b8a9ded67f4307f157bd399 (patch)
tree1137be278ac5e4e9eada62325ba629aaf50ef7c6
parent4cf35350a9d86c81d78acaed00e582ce045ccb3c (diff)
downloadmullvadvpn-8e9a4e68af1669594b8a9ded67f4307f157bd399.tar.xz
mullvadvpn-8e9a4e68af1669594b8a9ded67f4307f157bd399.zip
Add NotifyIpInterfaceChange function
-rw-r--r--talpid-core/src/tunnel/openvpn/windows.rs70
1 files changed, 68 insertions, 2 deletions
diff --git a/talpid-core/src/tunnel/openvpn/windows.rs b/talpid-core/src/tunnel/openvpn/windows.rs
index c1aa80a631..c51cb8d805 100644
--- a/talpid-core/src/tunnel/openvpn/windows.rs
+++ b/talpid-core/src/tunnel/openvpn/windows.rs
@@ -4,7 +4,7 @@ use std::{
os::windows::{ffi::OsStrExt, io::RawHandle},
path::Path,
ptr,
- sync::Arc,
+ sync::{Arc, Mutex},
};
use talpid_types::ErrorExt;
use widestring::{U16CStr, U16CString};
@@ -13,7 +13,11 @@ use winapi::{
guiddef::GUID,
ifdef::NET_LUID,
minwindef::{BOOL, FARPROC, HINSTANCE, HMODULE},
- netioapi::ConvertInterfaceLuidToGuid,
+ netioapi::{
+ CancelMibChangeNotify2, ConvertInterfaceLuidToGuid, NotifyIpInterfaceChange,
+ MIB_IPINTERFACE_ROW,
+ },
+ ntdef::FALSE,
winerror::NO_ERROR,
},
um::{
@@ -425,6 +429,68 @@ pub fn find_adapter_registry_key(find_guid: &str, permissions: REGSAM) -> io::Re
Err(io::Error::new(io::ErrorKind::NotFound, "device not found"))
}
+pub struct IpNotifierHandle<'a> {
+ mutex: Mutex<()>,
+ callback: Option<Box<dyn FnMut(&MIB_IPINTERFACE_ROW, u32) + Send + 'a>>,
+ handle: RawHandle,
+}
+
+impl<'a> Drop for IpNotifierHandle<'a> {
+ fn drop(&mut self) {
+ // Inner callback may be called while destructing
+ unsafe { CancelMibChangeNotify2(self.handle as *mut _) };
+
+ let _ = self
+ .mutex
+ .lock()
+ .expect("NotifyIpInterfaceChange mutex poisoned");
+ let _ = self.callback.take();
+ }
+}
+
+unsafe extern "system" fn inner_callback(
+ context: *mut winapi::ctypes::c_void,
+ row: *mut MIB_IPINTERFACE_ROW,
+ notify_type: u32,
+) {
+ let context = &mut *(context as *mut IpNotifierHandle<'_>);
+ let _ = context
+ .mutex
+ .lock()
+ .expect("NotifyIpInterfaceChange mutex poisoned");
+
+ if let Some(ref mut callback) = context.callback {
+ callback(&*row, notify_type);
+ }
+}
+
+pub fn notify_ip_interface_change<'a, T: FnMut(&MIB_IPINTERFACE_ROW, u32) + Send + 'a>(
+ callback: T,
+ family: u16,
+) -> io::Result<Box<IpNotifierHandle<'a>>> {
+ let mut context = Box::new(IpNotifierHandle {
+ mutex: Mutex::default(),
+ callback: Some(Box::new(callback)),
+ handle: std::ptr::null_mut(),
+ });
+
+ let status = unsafe {
+ NotifyIpInterfaceChange(
+ family,
+ Some(inner_callback),
+ &mut *context as *mut _ as *mut _,
+ FALSE,
+ (&mut context.handle) as *mut _,
+ )
+ };
+
+ if status != NO_ERROR {
+ return Err(io::Error::last_os_error());
+ }
+
+ Ok(context)
+}
+
#[cfg(test)]
mod tests {
use super::*;