wintun_bindings/
session.rs1use crate::{
2 Adapter, Error, Wintun,
3 handle::{SafeEvent, UnsafeHandle},
4 packet, util, wintun_raw,
5};
6use std::{ptr, slice, sync::Arc, sync::OnceLock};
7use windows_sys::Win32::{
8 Foundation::{ERROR_NO_MORE_ITEMS, FALSE, GetLastError, HANDLE, WAIT_EVENT, WAIT_FAILED, WAIT_OBJECT_0},
9 System::Threading::{INFINITE, WaitForMultipleObjects},
10};
11
12pub struct Session {
14 pub(crate) inner: UnsafeHandle<wintun_raw::WINTUN_SESSION_HANDLE>,
16
17 pub(crate) read_event: OnceLock<UnsafeHandle<HANDLE>>,
20
21 pub(crate) shutdown_event: Arc<SafeEvent>,
24
25 pub(crate) adapter: Arc<Adapter>,
27}
28
29impl Session {
30 pub fn get_adapter(&self) -> Arc<Adapter> {
31 self.adapter.clone()
32 }
33
34 pub(crate) fn get_wintun(&self) -> Wintun {
35 self.adapter.wintun.clone()
36 }
37
38 pub fn allocate_send_packet(self: &Arc<Self>, size: u16) -> Result<packet::Packet, Error> {
46 let wintun = self.get_wintun();
47 let ptr = unsafe { wintun.WintunAllocateSendPacket(self.inner.0, size as u32) };
48 if ptr.is_null() {
49 return Err(util::get_last_error()?.into());
50 }
51 Ok(packet::Packet {
52 bytes: unsafe { slice::from_raw_parts_mut(ptr, size as usize) },
55 session: self.clone(),
56 kind: packet::Kind::SendPacketPending,
57 })
58 }
59
60 pub fn send_packet(&self, mut packet: packet::Packet) {
62 assert!(matches!(packet.kind, packet::Kind::SendPacketPending));
63
64 let wintun = self.get_wintun();
65 unsafe { wintun.WintunSendPacket(self.inner.0, packet.bytes.as_ptr()) };
66 packet.kind = packet::Kind::SendPacketSent;
68 }
69
70 pub fn try_receive(self: &Arc<Self>) -> Result<Option<packet::Packet>, Error> {
74 let mut size = 0u32;
75
76 let wintun = self.get_wintun();
77 let ptr = unsafe { wintun.WintunReceivePacket(self.inner.0, &mut size as *mut u32) };
78
79 debug_assert!(size <= u16::MAX as u32);
80 if ptr.is_null() {
81 return match unsafe { GetLastError() } {
83 ERROR_NO_MORE_ITEMS => Ok(None),
84 e => Err(std::io::Error::from_raw_os_error(e as i32).into()),
85 };
86 }
87 Ok(Some(packet::Packet {
88 kind: packet::Kind::ReceivePacket,
89 bytes: unsafe { slice::from_raw_parts_mut(ptr, size as usize) },
92 session: self.clone(),
93 }))
94 }
95
96 pub fn get_read_wait_event(&self) -> Result<UnsafeHandle<HANDLE>, Error> {
100 let wintun = self.get_wintun();
101 Ok(*self
102 .read_event
103 .get_or_init(|| UnsafeHandle(unsafe { wintun.WintunGetReadWaitEvent(self.inner.0) })))
104 }
105
106 pub fn get_shutdown_event(&self) -> UnsafeHandle<HANDLE> {
107 self.shutdown_event.get_handle()
108 }
109
110 pub fn receive_blocking(self: &Arc<Self>) -> Result<packet::Packet, Error> {
114 loop {
115 for _ in 0..5 {
118 match self.try_receive() {
119 Err(err) => return Err(err),
120 Ok(Some(packet)) => return Ok(packet),
121 Ok(None) => {
122 continue;
124 }
125 }
126 }
127 self.wait_read()?;
128 }
129 }
130
131 pub fn wait_read(&self) -> Result<(), Error> {
132 let handles = [self.get_read_wait_event()?.0, self.shutdown_event.0.0];
134 let result = unsafe {
135 WaitForMultipleObjects(handles.len() as u32, &handles as _, FALSE, INFINITE)
138 };
139 const WAIT_OBJECT_1: WAIT_EVENT = WAIT_OBJECT_0 + 1;
140 match result {
141 WAIT_FAILED => Err(util::get_last_error()?.into()),
142 WAIT_OBJECT_0 => {
143 Ok(())
145 }
146 WAIT_OBJECT_1 => {
147 Err(Error::ShuttingDown)
149 }
150 _ => {
151 panic!("WaitForMultipleObjects returned unexpected value {:?}", result);
153 }
154 }
155 }
156
157 pub fn shutdown(&self) -> Result<(), Error> {
159 self.shutdown_event.set_event()?;
160 Ok(())
161 }
162}
163
164impl Session {
165 pub fn try_recv(&self, buf: &mut [u8]) -> std::io::Result<usize> {
166 let mut size = 0u32;
167
168 let wintun = &self.adapter.wintun;
169 let ptr = unsafe { wintun.WintunReceivePacket(self.inner.0, &mut size as *mut u32) };
170
171 debug_assert!(size <= u16::MAX as u32);
172 if ptr.is_null() {
173 return match unsafe { GetLastError() } {
175 ERROR_NO_MORE_ITEMS => Err(std::io::Error::from(std::io::ErrorKind::WouldBlock)),
176 e => Err(std::io::Error::from_raw_os_error(e as i32)),
177 };
178 }
179 let size = size as usize;
180 if size > buf.len() {
181 unsafe { wintun.WintunReleaseReceivePacket(self.inner.0, ptr) };
182 use std::io::{Error, ErrorKind::InvalidInput};
183 return Err(Error::new(InvalidInput, "destination buffer too small"));
184 }
185 unsafe { ptr::copy_nonoverlapping(ptr, buf.as_mut_ptr(), size) };
186 unsafe { wintun.WintunReleaseReceivePacket(self.inner.0, ptr) };
187 Ok(size)
188 }
189
190 pub fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> {
194 loop {
195 for _ in 0..5 {
198 return match self.try_recv(buf) {
199 Ok(len) => Ok(len),
200 Err(e) => {
201 if e.kind() == std::io::ErrorKind::WouldBlock {
202 continue;
204 }
205 Err(e)
206 }
207 };
208 }
209 self.wait_read()?;
210 }
211 }
212
213 pub fn send(&self, buf: &[u8]) -> std::io::Result<usize> {
214 let wintun = &self.adapter.wintun;
215 let size = buf.len();
216 let ptr = unsafe { wintun.WintunAllocateSendPacket(self.inner.0, size as u32) };
217 if ptr.is_null() {
218 util::get_last_error()?;
219 }
220 unsafe { ptr::copy_nonoverlapping(buf.as_ptr(), ptr, size) };
221 unsafe { wintun.WintunSendPacket(self.inner.0, ptr) };
222 Ok(buf.len())
223 }
224}
225
226impl Drop for Session {
227 fn drop(&mut self) {
228 if let Err(e) = self.shutdown() {
229 log::trace!("Failed to shutdown session: {}", e);
230 }
231 unsafe { self.get_wintun().WintunEndSession(self.inner.0) };
232 self.inner.0 = ptr::null_mut();
233 }
234}