diff options
| author | David Lönnhager <david.l@mullvad.net> | 2023-10-17 11:24:08 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2023-10-20 18:17:06 +0200 |
| commit | b3cc38c2bea1869e495206ec1febc6a92bb300bc (patch) | |
| tree | 6c9663ef925b5699db8c2befcb5fa910b0e28deb | |
| parent | 5f5e7b3c0e4b14cd8cbd4e53919e3555e24319ed (diff) | |
| download | mullvadvpn-b3cc38c2bea1869e495206ec1febc6a92bb300bc.tar.xz mullvadvpn-b3cc38c2bea1869e495206ec1febc6a92bb300bc.zip | |
Move Event and Overlapped to talpid-windows crate
| -rw-r--r-- | Cargo.lock | 8 | ||||
| -rw-r--r-- | talpid-core/Cargo.toml | 1 | ||||
| -rw-r--r-- | talpid-core/src/split_tunnel/windows/driver.rs | 7 | ||||
| -rw-r--r-- | talpid-core/src/split_tunnel/windows/mod.rs | 31 | ||||
| -rw-r--r-- | talpid-core/src/split_tunnel/windows/windows.rs | 99 | ||||
| -rw-r--r-- | talpid-windows/Cargo.toml | 21 | ||||
| -rw-r--r-- | talpid-windows/src/io.rs | 49 | ||||
| -rw-r--r-- | talpid-windows/src/lib.rs | 12 | ||||
| -rw-r--r-- | talpid-windows/src/sync.rs | 75 |
9 files changed, 191 insertions, 112 deletions
diff --git a/Cargo.lock b/Cargo.lock index c929ce5754..63031c21c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3456,6 +3456,7 @@ dependencies = [ "talpid-tunnel", "talpid-tunnel-config-client", "talpid-types", + "talpid-windows", "talpid-windows-net", "talpid-wireguard", "tokio", @@ -3622,6 +3623,13 @@ dependencies = [ ] [[package]] +name = "talpid-windows" +version = "0.0.0" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] name = "talpid-windows-net" version = "0.0.0" dependencies = [ diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml index e39b07f244..40dae6b27b 100644 --- a/talpid-core/Cargo.toml +++ b/talpid-core/Cargo.toml @@ -61,6 +61,7 @@ winreg = { version = "0.51", features = ["transactions"] } memoffset = "0.6" windows-service = "0.6.0" talpid-windows-net = { path = "../talpid-windows-net" } +talpid-windows = { path = "../talpid-windows" } [target.'cfg(windows)'.dependencies.windows-sys] workspace = true diff --git a/talpid-core/src/split_tunnel/windows/driver.rs b/talpid-core/src/split_tunnel/windows/driver.rs index c868834518..eea79f188f 100644 --- a/talpid-core/src/split_tunnel/windows/driver.rs +++ b/talpid-core/src/split_tunnel/windows/driver.rs @@ -1,6 +1,6 @@ use super::windows::{ - get_device_path, get_process_creation_time, get_process_device_path, open_process, Event, - Overlapped, ProcessAccess, ProcessSnapshot, + get_device_path, get_process_creation_time, get_process_device_path, open_process, + ProcessAccess, ProcessSnapshot, }; use bitflags::bitflags; use memoffset::offset_of; @@ -22,6 +22,7 @@ use std::{ time::Duration, }; use talpid_types::ErrorExt; +use talpid_windows::{io::Overlapped, sync::Event}; use windows_sys::Win32::{ Foundation::{ ERROR_ACCESS_DENIED, ERROR_FILE_NOT_FOUND, ERROR_INVALID_PARAMETER, ERROR_IO_PENDING, @@ -877,7 +878,7 @@ pub fn get_overlapped_result( let event = overlapped.get_event().unwrap(); // SAFETY: This is a valid event object. - unsafe { wait_for_single_object(event.as_handle(), None) }?; + unsafe { wait_for_single_object(event.as_raw(), None) }?; // SAFETY: The handle and overlapped object are valid. let mut returned_bytes = 0u32; diff --git a/talpid-core/src/split_tunnel/windows/mod.rs b/talpid-core/src/split_tunnel/windows/mod.rs index 40d7c340ad..dcabda7c8e 100644 --- a/talpid-core/src/split_tunnel/windows/mod.rs +++ b/talpid-core/src/split_tunnel/windows/mod.rs @@ -105,7 +105,7 @@ pub struct SplitTunnel { runtime: tokio::runtime::Handle, request_tx: RequestTx, event_thread: Option<std::thread::JoinHandle<()>>, - quit_event: Arc<windows::Event>, + quit_event: Arc<talpid_windows::sync::Event>, excluded_processes: Arc<RwLock<HashMap<usize, ExcludedProcess>>>, _route_change_callback: Option<CallbackHandle>, daemon_tx: Weak<mpsc::UnboundedSender<TunnelCommand>>, @@ -191,14 +191,21 @@ impl SplitTunnel { fn spawn_event_listener( handle: Arc<driver::DeviceHandle>, excluded_processes: Arc<RwLock<HashMap<usize, ExcludedProcess>>>, - ) -> Result<(std::thread::JoinHandle<()>, Arc<windows::Event>), Error> { - let mut event_overlapped = windows::Overlapped::new(Some( - windows::Event::new(true, false).map_err(Error::EventThreadError)?, + ) -> Result< + ( + std::thread::JoinHandle<()>, + Arc<talpid_windows::sync::Event>, + ), + Error, + > { + let mut event_overlapped = talpid_windows::io::Overlapped::new(Some( + talpid_windows::sync::Event::new(true, false).map_err(Error::EventThreadError)?, )) .map_err(Error::EventThreadError)?; - let quit_event = - Arc::new(windows::Event::new(true, false).map_err(Error::EventThreadError)?); + let quit_event = Arc::new( + talpid_windows::sync::Event::new(true, false).map_err(Error::EventThreadError)?, + ); let quit_event_copy = quit_event.clone(); let event_thread = std::thread::spawn(move || { @@ -237,11 +244,11 @@ impl SplitTunnel { fn fetch_next_event( device: &Arc<driver::DeviceHandle>, - quit_event: &windows::Event, - overlapped: &mut windows::Overlapped, + quit_event: &talpid_windows::sync::Event, + overlapped: &mut talpid_windows::io::Overlapped, data_buffer: &mut Vec<u8>, ) -> io::Result<EventResult> { - if unsafe { driver::wait_for_single_object(quit_event.as_handle(), Some(Duration::ZERO)) } + if unsafe { driver::wait_for_single_object(quit_event.as_raw(), Some(Duration::ZERO)) } .is_ok() { return Ok(EventResult::Quit); @@ -268,8 +275,8 @@ impl SplitTunnel { })?; let event_objects = [ - overlapped.get_event().unwrap().as_handle(), - quit_event.as_handle(), + overlapped.get_event().unwrap().as_raw(), + quit_event.as_raw(), ]; let signaled_object = @@ -283,7 +290,7 @@ impl SplitTunnel { }, )?; - if signaled_object == quit_event.as_handle() { + if signaled_object == quit_event.as_raw() { // Quit event was signaled return Ok(EventResult::Quit); } diff --git a/talpid-core/src/split_tunnel/windows/windows.rs b/talpid-core/src/split_tunnel/windows/windows.rs index 77fafdc199..423426c385 100644 --- a/talpid-core/src/split_tunnel/windows/windows.rs +++ b/talpid-core/src/split_tunnel/windows/windows.rs @@ -13,7 +13,7 @@ use std::{ }; use windows_sys::Win32::{ Foundation::{ - CloseHandle, BOOL, ERROR_INSUFFICIENT_BUFFER, ERROR_NO_MORE_FILES, FILETIME, HANDLE, + CloseHandle, ERROR_INSUFFICIENT_BUFFER, ERROR_NO_MORE_FILES, FILETIME, HANDLE, INVALID_HANDLE_VALUE, }, Storage::FileSystem::{GetFinalPathNameByHandleW, QueryDosDeviceW}, @@ -22,11 +22,8 @@ use windows_sys::Win32::{ CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W, }, ProcessStatus::GetProcessImageFileNameW, - Threading::{ - CreateEventW, GetProcessTimes, OpenProcess, SetEvent, PROCESS_QUERY_LIMITED_INFORMATION, - }, + Threading::{GetProcessTimes, OpenProcess, PROCESS_QUERY_LIMITED_INFORMATION}, WindowsProgramming::VOLUME_NAME_NT, - IO::OVERLAPPED, }, }; @@ -299,95 +296,3 @@ fn get_process_device_path_inner( Ok(OsStringExt::from_wide(&buffer)) } - -/// Abstraction over `OVERLAPPED`, which is used for async I/O. -pub struct Overlapped { - overlapped: OVERLAPPED, - event: Option<Event>, -} - -unsafe impl Send for Overlapped {} -unsafe impl Sync for Overlapped {} - -impl Overlapped { - /// Creates an `OVERLAPPED` object with `hEvent` set. - pub fn new(event: Option<Event>) -> io::Result<Self> { - let mut overlapped = Overlapped { - overlapped: unsafe { mem::zeroed() }, - event: None, - }; - overlapped.set_event(event); - Ok(overlapped) - } - - /// Borrows the underlying `OVERLAPPED` object. - pub fn as_mut_ptr(&mut self) -> *mut OVERLAPPED { - &mut self.overlapped - } - - /// Returns a reference to the associated event. - pub fn get_event(&self) -> Option<&Event> { - self.event.as_ref() - } - - /// Sets the event object for the underlying `OVERLAPPED` object (i.e., `hEvent`) - fn set_event(&mut self, event: Option<Event>) { - match event { - Some(event) => { - self.overlapped.hEvent = event.0; - self.event = Some(event); - } - None => { - self.overlapped.hEvent = 0; - self.event = None; - } - } - } -} - -/// Abstraction over a Windows event object. -pub struct Event(HANDLE); - -unsafe impl Send for Event {} -unsafe impl Sync for Event {} - -impl Event { - pub fn new(manual_reset: bool, initial_state: bool) -> io::Result<Self> { - let event = unsafe { - CreateEventW( - ptr::null_mut(), - bool_to_winbool(manual_reset), - bool_to_winbool(initial_state), - ptr::null(), - ) - }; - if event == 0 { - return Err(io::Error::last_os_error()); - } - Ok(Self(event)) - } - - pub fn set(&self) -> io::Result<()> { - if unsafe { SetEvent(self.0) } == 0 { - return Err(io::Error::last_os_error()); - } - Ok(()) - } - - pub fn as_handle(&self) -> HANDLE { - self.0 - } -} - -impl Drop for Event { - fn drop(&mut self) { - unsafe { CloseHandle(self.0) }; - } -} - -const fn bool_to_winbool(val: bool) -> BOOL { - match val { - true => 1, - false => 0, - } -} diff --git a/talpid-windows/Cargo.toml b/talpid-windows/Cargo.toml new file mode 100644 index 0000000000..20a4d1ae3e --- /dev/null +++ b/talpid-windows/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "talpid-windows" +description = "Nice abstractions for Windows" +version.workspace = true +authors.workspace = true +repository.workspace = true +license.workspace = true +edition.workspace = true +publish.workspace = true + +[target.'cfg(windows)'.dependencies.windows-sys] +workspace = true +features = [ + "Win32_Foundation", + "Win32_Globalization", + "Win32_System_Com", + "Win32_System_IO", + "Win32_Networking_WinSock", + "Win32_NetworkManagement_IpHelper", + "Win32_NetworkManagement_Ndis", +] diff --git a/talpid-windows/src/io.rs b/talpid-windows/src/io.rs new file mode 100644 index 0000000000..1bcffb30d3 --- /dev/null +++ b/talpid-windows/src/io.rs @@ -0,0 +1,49 @@ +use std::{io, mem}; +use windows_sys::Win32::System::IO::OVERLAPPED; + +use crate::sync::Event; + +/// Abstraction over `OVERLAPPED`. +pub struct Overlapped { + overlapped: OVERLAPPED, + event: Option<Event>, +} + +unsafe impl Send for Overlapped {} +unsafe impl Sync for Overlapped {} + +impl Overlapped { + /// Creates an `OVERLAPPED` object with `hEvent` set. + pub fn new(event: Option<Event>) -> io::Result<Self> { + let mut overlapped = Overlapped { + overlapped: unsafe { mem::zeroed() }, + event: None, + }; + overlapped.set_event(event); + Ok(overlapped) + } + + /// Borrows the underlying `OVERLAPPED` object. + pub fn as_mut_ptr(&mut self) -> *mut OVERLAPPED { + &mut self.overlapped + } + + /// Returns a reference to the associated event. + pub fn get_event(&self) -> Option<&Event> { + self.event.as_ref() + } + + /// Sets the event object for the underlying `OVERLAPPED` object (i.e., `hEvent`) + fn set_event(&mut self, event: Option<Event>) { + match event { + Some(event) => { + self.overlapped.hEvent = event.as_raw(); + self.event = Some(event); + } + None => { + self.overlapped.hEvent = 0; + self.event = None; + } + } + } +} diff --git a/talpid-windows/src/lib.rs b/talpid-windows/src/lib.rs new file mode 100644 index 0000000000..edc471aa33 --- /dev/null +++ b/talpid-windows/src/lib.rs @@ -0,0 +1,12 @@ +//! Interface with low-level windows specific bits. + +#![deny(missing_docs)] +#![deny(rust_2018_idioms)] + +/// Windows I/O +#[cfg(windows)] +pub mod io; + +/// Synchronization (event objects, etc.) +#[cfg(windows)] +pub mod sync; diff --git a/talpid-windows/src/sync.rs b/talpid-windows/src/sync.rs new file mode 100644 index 0000000000..7b4ed59be3 --- /dev/null +++ b/talpid-windows/src/sync.rs @@ -0,0 +1,75 @@ +use std::{io, ptr}; +use windows_sys::Win32::{ + Foundation::{CloseHandle, DuplicateHandle, BOOL, DUPLICATE_SAME_ACCESS, HANDLE}, + System::Threading::{CreateEventW, GetCurrentProcess, SetEvent}, +}; + +/// Windows event object +pub struct Event(HANDLE); + +unsafe impl Send for Event {} +unsafe impl Sync for Event {} + +impl Event { + /// Create a new event object using `CreateEventW` + pub fn new(manual_reset: bool, initial_state: bool) -> io::Result<Self> { + let event = unsafe { + CreateEventW( + ptr::null_mut(), + bool_to_winbool(manual_reset), + bool_to_winbool(initial_state), + ptr::null(), + ) + }; + if event == 0 { + return Err(io::Error::last_os_error()); + } + Ok(Self(event)) + } + + /// Signal the event object + pub fn set(&self) -> io::Result<()> { + if unsafe { SetEvent(self.0) } == 0 { + return Err(io::Error::last_os_error()); + } + Ok(()) + } + + /// Return raw event object + pub fn as_raw(&self) -> HANDLE { + self.0 + } + + /// Duplicate the event object with `DuplicateHandle()` + pub fn duplicate(&self) -> io::Result<Event> { + let mut new_event = 0; + let status = unsafe { + DuplicateHandle( + GetCurrentProcess(), + self.0, + GetCurrentProcess(), + &mut new_event, + 0, + 0, + DUPLICATE_SAME_ACCESS, + ) + }; + if status == 0 { + return Err(io::Error::last_os_error()); + } + Ok(Event(new_event)) + } +} + +impl Drop for Event { + fn drop(&mut self) { + unsafe { CloseHandle(self.0) }; + } +} + +const fn bool_to_winbool(val: bool) -> BOOL { + match val { + true => 1, + false => 0, + } +} |
