Skip to main content

tun_rs/platform/
mod.rs

1#[cfg(unix)]
2pub(crate) mod unix;
3
4#[cfg(all(
5    unix,
6    not(any(
7        target_os = "windows",
8        target_os = "macos",
9        all(target_os = "linux", not(target_env = "ohos")),
10        target_os = "freebsd",
11        target_os = "openbsd",
12        target_os = "netbsd",
13    ))
14))]
15pub use self::unix::DeviceImpl;
16#[cfg(unix)]
17#[cfg(feature = "interruptible")]
18pub use unix::InterruptEvent;
19#[cfg(windows)]
20#[cfg(feature = "interruptible")]
21pub use windows::InterruptEvent;
22#[cfg(all(target_os = "linux", not(target_env = "ohos")))]
23pub(crate) mod linux;
24#[cfg(all(target_os = "linux", not(target_env = "ohos")))]
25pub use self::linux::*;
26
27#[cfg(target_os = "freebsd")]
28pub(crate) mod freebsd;
29#[cfg(target_os = "freebsd")]
30pub use self::freebsd::DeviceImpl;
31
32#[cfg(target_os = "macos")]
33pub(crate) mod macos;
34#[cfg(target_os = "macos")]
35pub use self::macos::DeviceImpl;
36#[cfg(target_os = "openbsd")]
37pub(crate) mod openbsd;
38#[cfg(target_os = "openbsd")]
39pub use self::openbsd::DeviceImpl;
40
41#[cfg(target_os = "netbsd")]
42pub(crate) mod netbsd;
43#[cfg(target_os = "netbsd")]
44pub use self::netbsd::DeviceImpl;
45
46#[cfg(target_os = "windows")]
47pub(crate) mod windows;
48#[cfg(target_os = "windows")]
49pub use self::windows::DeviceImpl;
50
51use getifaddrs::Interface;
52#[cfg(unix)]
53use std::io::{IoSlice, IoSliceMut};
54use std::ops::Deref;
55#[cfg(unix)]
56use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
57
58#[allow(dead_code)]
59pub(crate) const ETHER_ADDR_LEN: u8 = 6;
60
61#[allow(dead_code)]
62pub(crate) fn get_if_addrs_by_name(if_name: String) -> std::io::Result<Vec<Interface>> {
63    let addrs = getifaddrs::getifaddrs()?;
64    let ifs = addrs.filter(|v| v.name == if_name).collect();
65    Ok(ifs)
66}
67
68/// A transparent wrapper around DeviceImpl, providing synchronous I/O operations.
69///
70/// # Examples
71///
72/// Basic read/write operation:
73///
74/// ```no_run
75/// use std::net::Ipv4Addr;
76/// use tun_rs::DeviceBuilder;
77///
78/// fn main() -> std::io::Result<()> {
79///     // Create a TUN device using the builder
80///     let mut tun = DeviceBuilder::new()
81///         .name("my-tun")
82///         .ipv4(Ipv4Addr::new(10, 0, 0, 1), 24, None)
83///         .build_sync()?;
84///
85///     // Send a packet
86///     // Example IP packet (Replace with real IP message)
87///     let packet = b"[IP Packet: 10.0.0.1 -> 10.0.0.2] Hello, TUN!";
88///     tun.send(packet)?;
89///     println!("Sent {} bytes IP packet", packet.len());
90///
91///     // Receive a packet
92///     let mut buf = [0u8; 1500];
93///     let n = tun.recv(&mut buf)?;
94///     println!("Received {} bytes: {:?}", n, &buf[..n]);
95///
96///     Ok(())
97/// }
98/// ```
99#[repr(transparent)]
100pub struct SyncDevice(pub(crate) DeviceImpl);
101
102impl SyncDevice {
103    /// Creates a `SyncDevice` from a raw file descriptor.
104    ///
105    /// # Safety
106    /// - The file descriptor (`fd`) must be an owned file descriptor.
107    /// - It must be valid and open.
108    /// - The file descriptor must refer to a TUN/TAP device.
109    /// - After calling this function, the `SyncDevice` takes ownership of the fd and will close it when dropped.
110    ///
111    /// This function is only available on Unix platforms.
112    ///
113    /// # Example
114    ///
115    /// On iOS using PacketTunnelProvider:
116    ///
117    /// ```no_run
118    /// # #[cfg(unix)]
119    /// # {
120    /// use std::os::fd::RawFd;
121    /// use tun_rs::SyncDevice;
122    ///
123    /// // On iOS, obtain fd from PacketTunnelProvider.packetFlow
124    /// // let fd: RawFd = packet_flow.value(forKeyPath: "socket.fileDescriptor") as! Int32
125    /// let fd: RawFd = 10; // Example value - obtain from platform VPN APIs
126    ///
127    /// // SAFETY: fd must be a valid, open file descriptor to a TUN device
128    /// let dev = unsafe { SyncDevice::from_fd(fd)? };
129    ///
130    /// // Device now owns the file descriptor
131    /// let mut buf = [0u8; 1500];
132    /// let n = dev.recv(&mut buf)?;
133    /// println!("Received {} bytes", n);
134    /// # }
135    /// # Ok::<(), std::io::Error>(())
136    /// ```
137    ///
138    /// On Android using VpnService:
139    ///
140    /// ```no_run
141    /// # #[cfg(unix)]
142    /// # {
143    /// use tun_rs::SyncDevice;
144    ///
145    /// // On Android, obtain fd from VpnService.Builder.establish()
146    /// // ParcelFileDescriptor vpnInterface = builder.establish();
147    /// // int fd = vpnInterface.getFd();
148    /// let fd = 10; // Example value - obtain from VpnService
149    ///
150    /// // SAFETY: fd must be valid and open
151    /// let dev = unsafe { SyncDevice::from_fd(fd)? };
152    ///
153    /// let mut buf = [0u8; 1500];
154    /// loop {
155    ///     let n = dev.recv(&mut buf)?;
156    ///     // Process packet...
157    /// }
158    /// # }
159    /// # Ok::<(), std::io::Error>(())
160    /// ```
161    #[cfg(unix)]
162    pub unsafe fn from_fd(fd: RawFd) -> std::io::Result<Self> {
163        Ok(SyncDevice(DeviceImpl::from_fd(fd)?))
164    }
165    /// # Safety
166    /// The fd passed in must be a valid, open file descriptor.
167    /// Unlike [`from_fd`], this function does **not** take ownership of `fd`,
168    /// and therefore will not close it when dropped.  
169    /// The caller is responsible for ensuring the lifetime and eventual closure of `fd`.
170    #[cfg(unix)]
171    pub(crate) unsafe fn borrow_raw(fd: RawFd) -> std::io::Result<Self> {
172        Ok(SyncDevice(DeviceImpl::borrow_raw(fd)?))
173    }
174    /// Receives data from the device into the provided buffer.
175    ///
176    /// Returns the number of bytes read, or an I/O error.
177    ///
178    /// # Example
179    /// ```no_run
180    /// use std::net::Ipv4Addr;
181    /// use tun_rs::DeviceBuilder;
182    /// let mut tun = DeviceBuilder::new()
183    ///     .name("my-tun")
184    ///     .ipv4(Ipv4Addr::new(10, 0, 0, 1), 24, None)
185    ///     .build_sync()
186    ///     .unwrap();
187    /// let mut buf = [0u8; 1500];
188    /// tun.recv(&mut buf).unwrap();
189    /// ```
190    /// # Note
191    /// Blocking the current thread if no packet is available
192    #[inline]
193    pub fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> {
194        self.0.recv(buf)
195    }
196    /// Sends data from the provided buffer to the device.
197    ///
198    /// Returns the number of bytes written, or an I/O error.
199    ///
200    /// # Example
201    /// ```no_run
202    /// use std::net::Ipv4Addr;
203    /// use tun_rs::DeviceBuilder;
204    /// let mut tun = DeviceBuilder::new()
205    ///     .name("my-tun")
206    ///     .ipv4(Ipv4Addr::new(10, 0, 0, 1), 24, None)
207    ///     .build_sync()
208    ///     .unwrap();
209    /// tun.send(b"hello").unwrap();
210    /// ```
211    #[inline]
212    pub fn send(&self, buf: &[u8]) -> std::io::Result<usize> {
213        self.0.send(buf)
214    }
215    /// Attempts to receive data from the device in a non-blocking fashion.
216    ///
217    /// Returns the number of bytes read or an error if the operation would block.
218    #[cfg(target_os = "windows")]
219    #[inline]
220    pub fn try_recv(&self, buf: &mut [u8]) -> std::io::Result<usize> {
221        self.0.try_recv(buf)
222    }
223    /// Attempts to send data to the device in a non-blocking fashion.
224    ///
225    /// Returns the number of bytes written or an error if the operation would block.
226    #[cfg(target_os = "windows")]
227    #[inline]
228    pub fn try_send(&self, buf: &[u8]) -> std::io::Result<usize> {
229        self.0.try_send(buf)
230    }
231    /// Shuts down the device on Windows.
232    ///
233    /// This may close the device or signal that no further operations will occur.
234    #[cfg(target_os = "windows")]
235    pub fn shutdown(&self) -> std::io::Result<()> {
236        self.0.shutdown()
237    }
238    #[cfg(all(unix, feature = "experimental"))]
239    pub fn shutdown(&self) -> std::io::Result<()> {
240        Err(std::io::Error::from(std::io::ErrorKind::Unsupported))
241    }
242    /// Reads data into the provided buffer, with support for interruption.
243    ///
244    /// This function attempts to read from the underlying file descriptor into `buf`,
245    /// and can be interrupted using the given [`InterruptEvent`]. If the `event` is triggered
246    /// while the read operation is blocked, the function will return early with
247    /// an error of kind [`std::io::ErrorKind::Interrupted`].
248    ///
249    /// # Arguments
250    ///
251    /// * `buf` - The buffer to store the read data.
252    /// * `event` - An [`InterruptEvent`] used to interrupt the blocking read.
253    ///
254    /// # Returns
255    ///
256    /// On success, returns the number of bytes read. On failure, returns an [`std::io::Error`].
257    ///
258    /// # Platform-specific Behavior
259    ///
260    /// On **Unix platforms**, it is recommended to use this together with `set_nonblocking(true)`.
261    /// Without setting non-blocking mode, concurrent reads may not respond properly to interrupt signals.
262    ///
263    /// # Feature
264    ///
265    /// This method is only available when the `interruptible` feature is enabled.
266    #[cfg(feature = "interruptible")]
267    pub fn recv_intr(&self, buf: &mut [u8], event: &InterruptEvent) -> std::io::Result<usize> {
268        self.0.read_interruptible(buf, event, None)
269    }
270
271    /// Like [`recv_intr`](Self::recv_intr), but with an optional timeout.
272    ///
273    /// This function reads data from the device into the provided buffer, but can be
274    /// interrupted by the given event or by the timeout expiring.
275    ///
276    /// # Arguments
277    ///
278    /// * `buf` - The buffer to store the read data
279    /// * `event` - The interrupt event that can cancel the operation
280    /// * `timeout` - Optional duration to wait before returning with a timeout error
281    ///
282    /// # Returns
283    ///
284    /// - `Ok(n)` - Successfully read `n` bytes
285    /// - `Err(e)` with `ErrorKind::Interrupted` - Operation was interrupted by the event
286    /// - `Err(e)` with `ErrorKind::TimedOut` - Timeout expired before data was available
287    ///
288    /// # Example
289    ///
290    /// ```no_run
291    /// # #[cfg(all(unix, feature = "interruptible"))]
292    /// # {
293    /// use std::time::Duration;
294    /// use tun_rs::{DeviceBuilder, InterruptEvent};
295    ///
296    /// let dev = DeviceBuilder::new()
297    ///     .ipv4("10.0.0.1", 24, None)
298    ///     .build_sync()?;
299    ///
300    /// let event = InterruptEvent::new()?;
301    /// let mut buf = vec![0u8; 1500];
302    ///
303    /// // Read with a 5-second timeout
304    /// match dev.recv_intr_timeout(&mut buf, &event, Some(Duration::from_secs(5))) {
305    ///     Ok(n) => println!("Received {} bytes", n),
306    ///     Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {
307    ///         println!("Timed out waiting for data");
308    ///     }
309    ///     Err(e) if e.kind() == std::io::ErrorKind::Interrupted => {
310    ///         println!("Interrupted by event");
311    ///     }
312    ///     Err(e) => return Err(e),
313    /// }
314    /// # }
315    /// # Ok::<(), std::io::Error>(())
316    /// ```
317    ///
318    /// # Feature
319    ///
320    /// This method is only available when the `interruptible` feature is enabled.
321    #[cfg(feature = "interruptible")]
322    pub fn recv_intr_timeout(
323        &self,
324        buf: &mut [u8],
325        event: &InterruptEvent,
326        timeout: Option<std::time::Duration>,
327    ) -> std::io::Result<usize> {
328        self.0.read_interruptible(buf, event, timeout)
329    }
330    /// Like [`recv_intr`](Self::recv_intr), but reads into multiple buffers.
331    ///
332    /// This function behaves the same as [`recv_intr`](Self::recv_intr),
333    /// but uses `readv` to fill the provided set of non-contiguous buffers.
334    ///
335    /// # Feature
336    ///
337    /// This method is only available when the `interruptible` feature is enabled.
338    #[cfg(all(unix, feature = "interruptible"))]
339    pub fn recv_vectored_intr(
340        &self,
341        bufs: &mut [IoSliceMut<'_>],
342        event: &InterruptEvent,
343    ) -> std::io::Result<usize> {
344        self.0.readv_interruptible(bufs, event, None)
345    }
346
347    /// Like [`recv_vectored_intr`](Self::recv_vectored_intr), but with an optional timeout.
348    ///
349    /// This function reads data from the device into multiple buffers using vectored I/O,
350    /// but can be interrupted by the given event or by the timeout expiring.
351    ///
352    /// # Arguments
353    ///
354    /// * `bufs` - Multiple buffers to store the read data
355    /// * `event` - The interrupt event that can cancel the operation
356    /// * `timeout` - Optional duration to wait before returning with a timeout error
357    ///
358    /// # Returns
359    ///
360    /// - `Ok(n)` - Successfully read `n` bytes total across all buffers
361    /// - `Err(e)` with `ErrorKind::Interrupted` - Operation was interrupted by the event
362    /// - `Err(e)` with `ErrorKind::TimedOut` - Timeout expired before data was available
363    ///
364    /// # Example
365    ///
366    /// ```no_run
367    /// # #[cfg(all(unix, feature = "interruptible"))]
368    /// # {
369    /// use std::io::IoSliceMut;
370    /// use std::time::Duration;
371    /// use tun_rs::{DeviceBuilder, InterruptEvent};
372    ///
373    /// let dev = DeviceBuilder::new()
374    ///     .ipv4("10.0.0.1", 24, None)
375    ///     .build_sync()?;
376    ///
377    /// let event = InterruptEvent::new()?;
378    /// let mut header = [0u8; 20];
379    /// let mut payload = [0u8; 1480];
380    /// let mut bufs = [IoSliceMut::new(&mut header), IoSliceMut::new(&mut payload)];
381    ///
382    /// // Read with timeout into multiple buffers
383    /// match dev.recv_vectored_intr_timeout(&mut bufs, &event, Some(Duration::from_secs(5))) {
384    ///     Ok(n) => println!("Received {} bytes", n),
385    ///     Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {
386    ///         println!("Timed out");
387    ///     }
388    ///     Err(e) => return Err(e),
389    /// }
390    /// # }
391    /// # Ok::<(), std::io::Error>(())
392    /// ```
393    ///
394    /// # Feature
395    ///
396    /// This method is only available when the `interruptible` feature is enabled.
397    #[cfg(all(unix, feature = "interruptible"))]
398    pub fn recv_vectored_intr_timeout(
399        &self,
400        bufs: &mut [IoSliceMut<'_>],
401        event: &InterruptEvent,
402        timeout: Option<std::time::Duration>,
403    ) -> std::io::Result<usize> {
404        self.0.readv_interruptible(bufs, event, timeout)
405    }
406    #[cfg(feature = "interruptible")]
407    pub fn wait_readable_intr(&self, event: &InterruptEvent) -> std::io::Result<()> {
408        self.0.wait_readable_interruptible(event, None)
409    }
410
411    /// Like [`wait_readable_intr`](Self::wait_readable_intr), but with an optional timeout.
412    ///
413    /// This function waits until the device becomes readable, but can be interrupted
414    /// by the given event or by the timeout expiring.
415    ///
416    /// # Arguments
417    ///
418    /// * `event` - The interrupt event that can cancel the wait
419    /// * `timeout` - Optional duration to wait before returning with a timeout error
420    ///
421    /// # Returns
422    ///
423    /// - `Ok(())` - Device is now readable
424    /// - `Err(e)` with `ErrorKind::Interrupted` - Wait was interrupted by the event
425    /// - `Err(e)` with `ErrorKind::TimedOut` - Timeout expired
426    ///
427    /// # Example
428    ///
429    /// ```no_run
430    /// # #[cfg(all(unix, feature = "interruptible"))]
431    /// # {
432    /// use std::time::Duration;
433    /// use tun_rs::{DeviceBuilder, InterruptEvent};
434    ///
435    /// let dev = DeviceBuilder::new()
436    ///     .ipv4("10.0.0.1", 24, None)
437    ///     .build_sync()?;
438    ///
439    /// let event = InterruptEvent::new()?;
440    ///
441    /// // Wait for readability with timeout
442    /// match dev.wait_readable_intr_timeout(&event, Some(Duration::from_secs(10))) {
443    ///     Ok(()) => {
444    ///         println!("Device is readable");
445    ///         // Now try to read...
446    ///     }
447    ///     Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {
448    ///         println!("Timed out waiting for data");
449    ///     }
450    ///     Err(e) => return Err(e),
451    /// }
452    /// # }
453    /// # Ok::<(), std::io::Error>(())
454    /// ```
455    ///
456    /// # Feature
457    ///
458    /// This method is only available when the `interruptible` feature is enabled.
459    #[cfg(feature = "interruptible")]
460    pub fn wait_readable_intr_timeout(
461        &self,
462        event: &InterruptEvent,
463        timeout: Option<std::time::Duration>,
464    ) -> std::io::Result<()> {
465        self.0.wait_readable_interruptible(event, timeout)
466    }
467    #[cfg(feature = "interruptible")]
468    pub fn send_intr(&self, buf: &[u8], event: &InterruptEvent) -> std::io::Result<usize> {
469        self.0.write_interruptible(buf, event)
470    }
471
472    /// Sends data to the device from multiple buffers using vectored I/O, with interruption support.
473    ///
474    /// Like [`send_intr`](Self::send_intr), but uses `writev` to send from multiple
475    /// non-contiguous buffers in a single operation.
476    ///
477    /// # Arguments
478    ///
479    /// * `bufs` - Multiple buffers containing the data to send
480    /// * `event` - The interrupt event that can cancel the operation
481    ///
482    /// # Returns
483    ///
484    /// - `Ok(n)` - Successfully sent `n` bytes total from all buffers
485    /// - `Err(e)` with `ErrorKind::Interrupted` - Operation was interrupted by the event
486    ///
487    /// # Example
488    ///
489    /// ```no_run
490    /// # #[cfg(all(unix, feature = "interruptible"))]
491    /// # {
492    /// use std::io::IoSlice;
493    /// use tun_rs::{DeviceBuilder, InterruptEvent};
494    ///
495    /// let dev = DeviceBuilder::new()
496    ///     .ipv4("10.0.0.1", 24, None)
497    ///     .build_sync()?;
498    ///
499    /// let event = InterruptEvent::new()?;
500    /// let header = [0x45, 0x00, 0x00, 0x14]; // IPv4 header
501    /// let payload = b"Hello, TUN!";
502    /// let bufs = [IoSlice::new(&header), IoSlice::new(payload)];
503    ///
504    /// match dev.send_vectored_intr(&bufs, &event) {
505    ///     Ok(n) => println!("Sent {} bytes", n),
506    ///     Err(e) if e.kind() == std::io::ErrorKind::Interrupted => {
507    ///         println!("Send was interrupted");
508    ///     }
509    ///     Err(e) => return Err(e),
510    /// }
511    /// # }
512    /// # Ok::<(), std::io::Error>(())
513    /// ```
514    ///
515    /// # Feature
516    ///
517    /// This method is only available when the `interruptible` feature is enabled.
518    #[cfg(all(unix, feature = "interruptible"))]
519    pub fn send_vectored_intr(
520        &self,
521        bufs: &[IoSlice<'_>],
522        event: &InterruptEvent,
523    ) -> std::io::Result<usize> {
524        self.0.writev_interruptible(bufs, event)
525    }
526
527    /// Waits for the device to become writable, with interruption support.
528    ///
529    /// This function waits until the device is ready to accept data for sending,
530    /// but can be interrupted by the given event.
531    ///
532    /// # Arguments
533    ///
534    /// * `event` - The interrupt event that can cancel the wait
535    ///
536    /// # Returns
537    ///
538    /// - `Ok(())` - Device is now writable
539    /// - `Err(e)` with `ErrorKind::Interrupted` - Wait was interrupted by the event
540    ///
541    /// # Example
542    ///
543    /// ```no_run
544    /// # #[cfg(all(unix, feature = "interruptible"))]
545    /// # {
546    /// use tun_rs::{DeviceBuilder, InterruptEvent};
547    ///
548    /// let dev = DeviceBuilder::new()
549    ///     .ipv4("10.0.0.1", 24, None)
550    ///     .build_sync()?;
551    ///
552    /// let event = InterruptEvent::new()?;
553    ///
554    /// // Wait for device to be writable
555    /// match dev.wait_writable_intr(&event) {
556    ///     Ok(()) => {
557    ///         println!("Device is writable");
558    ///         // Now send data...
559    ///     }
560    ///     Err(e) if e.kind() == std::io::ErrorKind::Interrupted => {
561    ///         println!("Wait was interrupted");
562    ///     }
563    ///     Err(e) => return Err(e),
564    /// }
565    /// # }
566    /// # Ok::<(), std::io::Error>(())
567    /// ```
568    ///
569    /// # Feature
570    ///
571    /// This method is only available when the `interruptible` feature is enabled.
572    #[cfg(all(unix, feature = "interruptible"))]
573    #[inline]
574    pub fn wait_writable_intr(&self, event: &InterruptEvent) -> std::io::Result<()> {
575        self.0.wait_writable_interruptible(event)
576    }
577    /// Receives data from the device into multiple buffers using vectored I/O.
578    ///
579    /// **Note:** This method operates on a single packet only. It will only read data from one packet,
580    /// even if multiple buffers are provided.
581    ///
582    /// Returns the total number of bytes read from the packet, or an error.
583    ///
584    /// # Example
585    ///
586    /// ```no_run
587    /// # #[cfg(unix)]
588    /// # {
589    /// use std::io::IoSliceMut;
590    /// use tun_rs::DeviceBuilder;
591    ///
592    /// let dev = DeviceBuilder::new()
593    ///     .ipv4("10.0.0.1", 24, None)
594    ///     .build_sync()?;
595    ///
596    /// // Prepare multiple buffers for receiving data
597    /// let mut header = [0u8; 20];
598    /// let mut payload = [0u8; 1480];
599    /// let mut bufs = [IoSliceMut::new(&mut header), IoSliceMut::new(&mut payload)];
600    ///
601    /// // Read one packet into the buffers
602    /// let n = dev.recv_vectored(&mut bufs)?;
603    /// println!("Received {} bytes total", n);
604    /// # }
605    /// # Ok::<(), std::io::Error>(())
606    /// ```
607    #[cfg(unix)]
608    pub fn recv_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> std::io::Result<usize> {
609        self.0.recv_vectored(bufs)
610    }
611    /// Sends data to the device from multiple buffers using vectored I/O.
612    ///
613    /// **Note:** This method operates on a single packet only. It will only send the data contained in
614    /// the provided buffers as one packet.
615    ///
616    /// Returns the total number of bytes written for the packet, or an error.
617    ///
618    /// # Example
619    ///
620    /// ```no_run
621    /// # #[cfg(unix)]
622    /// # {
623    /// use std::io::IoSlice;
624    /// use tun_rs::DeviceBuilder;
625    ///
626    /// let dev = DeviceBuilder::new()
627    ///     .ipv4("10.0.0.1", 24, None)
628    ///     .build_sync()?;
629    ///
630    /// // Send a packet with header and payload in separate buffers
631    /// let header = [0x45, 0x00, 0x00, 0x14]; // IPv4 header
632    /// let payload = b"Hello, TUN!";
633    /// let bufs = [IoSlice::new(&header), IoSlice::new(payload)];
634    ///
635    /// let n = dev.send_vectored(&bufs)?;
636    /// println!("Sent {} bytes", n);
637    /// # }
638    /// # Ok::<(), std::io::Error>(())
639    /// ```
640    #[cfg(unix)]
641    pub fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> std::io::Result<usize> {
642        self.0.send_vectored(bufs)
643    }
644    /// Checks whether the device is currently operating in nonblocking mode.
645    ///
646    /// Returns `true` if nonblocking mode is enabled, `false` otherwise, or an error.
647    ///
648    /// # Example
649    ///
650    /// ```no_run
651    /// # #[cfg(unix)]
652    /// # {
653    /// use tun_rs::DeviceBuilder;
654    ///
655    /// let dev = DeviceBuilder::new()
656    ///     .ipv4("10.0.0.1", 24, None)
657    ///     .build_sync()?;
658    ///
659    /// // Check current nonblocking mode
660    /// if dev.is_nonblocking()? {
661    ///     println!("Device is in nonblocking mode");
662    /// } else {
663    ///     println!("Device is in blocking mode");
664    /// }
665    /// # }
666    /// # Ok::<(), std::io::Error>(())
667    /// ```
668    #[cfg(unix)]
669    pub fn is_nonblocking(&self) -> std::io::Result<bool> {
670        self.0.is_nonblocking()
671    }
672
673    /// Sets the nonblocking mode for the device.
674    ///
675    /// - `nonblocking`: Pass `true` to enable nonblocking mode, `false` to disable.
676    ///
677    /// Returns an empty result on success or an I/O error.
678    ///
679    /// # Example
680    ///
681    /// ```no_run
682    /// # #[cfg(unix)]
683    /// # {
684    /// use tun_rs::DeviceBuilder;
685    ///
686    /// let dev = DeviceBuilder::new()
687    ///     .ipv4("10.0.0.1", 24, None)
688    ///     .build_sync()?;
689    ///
690    /// // Enable nonblocking mode for non-blocking I/O
691    /// dev.set_nonblocking(true)?;
692    ///
693    /// // Now recv() will return WouldBlock if no data is available
694    /// let mut buf = [0u8; 1500];
695    /// match dev.recv(&mut buf) {
696    ///     Ok(n) => println!("Received {} bytes", n),
697    ///     Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
698    ///         println!("No data available");
699    ///     }
700    ///     Err(e) => return Err(e),
701    /// }
702    /// # }
703    /// # Ok::<(), std::io::Error>(())
704    /// ```
705    #[cfg(unix)]
706    pub fn set_nonblocking(&self, nonblocking: bool) -> std::io::Result<()> {
707        self.0.set_nonblocking(nonblocking)
708    }
709
710    /// Creates a new queue for multi-queue TUN/TAP devices on Linux.
711    ///
712    /// # Prerequisites
713    /// - The `IFF_MULTI_QUEUE` flag must be enabled (via `.multi_queue(true)` in DeviceBuilder).
714    /// - The system must support network interface multi-queue functionality.
715    ///
716    /// # Description
717    /// When multi-queue is enabled, create a new queue by duplicating an existing one.
718    /// This allows parallel packet processing across multiple threads/CPU cores.
719    ///
720    /// # Example
721    ///
722    /// ```no_run
723    /// # #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
724    /// # {
725    /// use std::thread;
726    /// use tun_rs::DeviceBuilder;
727    ///
728    /// let dev = DeviceBuilder::new()
729    ///     .ipv4("10.0.0.1", 24, None)
730    ///     .with(|builder| {
731    ///         builder.multi_queue(true) // Enable multi-queue support
732    ///     })
733    ///     .build_sync()?;
734    ///
735    /// // Clone the device to create a new queue
736    /// let dev_clone = dev.try_clone()?;
737    ///
738    /// // Use the cloned device in another thread for parallel processing
739    /// thread::spawn(move || {
740    ///     let mut buf = [0u8; 1500];
741    ///     loop {
742    ///         if let Ok(n) = dev_clone.recv(&mut buf) {
743    ///             println!("Thread 2 received {} bytes", n);
744    ///         }
745    ///     }
746    /// });
747    ///
748    /// // Process packets in the main thread
749    /// let mut buf = [0u8; 1500];
750    /// loop {
751    ///     let n = dev.recv(&mut buf)?;
752    ///     println!("Thread 1 received {} bytes", n);
753    /// }
754    /// # }
755    /// # Ok::<(), std::io::Error>(())
756    /// ```
757    #[cfg(all(target_os = "linux", not(target_env = "ohos")))]
758    pub fn try_clone(&self) -> std::io::Result<SyncDevice> {
759        let device_impl = self.0.try_clone()?;
760        Ok(SyncDevice(device_impl))
761    }
762}
763#[cfg(all(target_os = "linux", not(target_env = "ohos")))]
764impl SyncDevice {
765    #[cfg(feature = "interruptible")]
766    pub fn send_multiple_intr<B: ExpandBuffer>(
767        &self,
768        gro_table: &mut GROTable,
769        bufs: &mut [B],
770        offset: usize,
771        event: &InterruptEvent,
772    ) -> std::io::Result<usize> {
773        self.send_multiple0(gro_table, bufs, offset, |tun, buf| {
774            tun.write_interruptible(buf, event)
775        })
776    }
777    #[cfg(feature = "interruptible")]
778    pub fn recv_multiple_intr<B: AsRef<[u8]> + AsMut<[u8]>>(
779        &self,
780        original_buffer: &mut [u8],
781        bufs: &mut [B],
782        sizes: &mut [usize],
783        offset: usize,
784        event: &InterruptEvent,
785    ) -> std::io::Result<usize> {
786        self.recv_multiple0(original_buffer, bufs, sizes, offset, |tun, buf| {
787            tun.read_interruptible(buf, event, None)
788        })
789    }
790}
791
792impl Deref for SyncDevice {
793    type Target = DeviceImpl;
794    fn deref(&self) -> &Self::Target {
795        &self.0
796    }
797}
798
799#[cfg(unix)]
800impl FromRawFd for SyncDevice {
801    unsafe fn from_raw_fd(fd: RawFd) -> Self {
802        SyncDevice::from_fd(fd).unwrap()
803    }
804}
805#[cfg(unix)]
806impl AsRawFd for SyncDevice {
807    fn as_raw_fd(&self) -> RawFd {
808        self.0.as_raw_fd()
809    }
810}
811#[cfg(unix)]
812impl AsFd for SyncDevice {
813    fn as_fd(&self) -> BorrowedFd<'_> {
814        unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
815    }
816}
817#[cfg(unix)]
818impl IntoRawFd for SyncDevice {
819    fn into_raw_fd(self) -> RawFd {
820        self.0.into_raw_fd()
821    }
822}
823
824#[cfg(unix)]
825pub struct BorrowedSyncDevice<'dev> {
826    dev: SyncDevice,
827    _phantom: std::marker::PhantomData<&'dev SyncDevice>,
828}
829#[cfg(unix)]
830impl Deref for BorrowedSyncDevice<'_> {
831    type Target = SyncDevice;
832    fn deref(&self) -> &Self::Target {
833        &self.dev
834    }
835}
836#[cfg(unix)]
837impl BorrowedSyncDevice<'_> {
838    /// # Safety
839    /// The fd passed in must be a valid, open file descriptor.
840    /// Unlike [`SyncDevice::from_fd`], this function does **not** take ownership of `fd`,
841    /// and therefore will not close it when dropped.  
842    /// The caller is responsible for ensuring the lifetime and eventual closure of `fd`.
843    pub unsafe fn borrow_raw(fd: RawFd) -> std::io::Result<Self> {
844        #[allow(unused_unsafe)]
845        unsafe {
846            Ok(Self {
847                dev: SyncDevice::borrow_raw(fd)?,
848                _phantom: std::marker::PhantomData,
849            })
850        }
851    }
852}