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