tun_rs/async_device/unix/
mod.rs

1#[cfg(target_os = "linux")]
2use crate::platform::offload::{handle_gro, VirtioNetHdr, VIRTIO_NET_HDR_LEN};
3use crate::platform::DeviceImpl;
4#[cfg(target_os = "linux")]
5use crate::platform::GROTable;
6use crate::SyncDevice;
7use std::io;
8use std::io::{IoSlice, IoSliceMut};
9use std::ops::Deref;
10use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
11
12#[cfg(feature = "async_tokio")]
13mod tokio;
14#[cfg(feature = "async_tokio")]
15pub use self::tokio::AsyncDevice;
16
17#[cfg(all(feature = "async_std", not(feature = "async_tokio")))]
18mod async_std;
19#[cfg(all(feature = "async_std", not(feature = "async_tokio")))]
20pub use self::async_std::AsyncDevice;
21
22impl FromRawFd for AsyncDevice {
23    unsafe fn from_raw_fd(fd: RawFd) -> Self {
24        AsyncDevice::from_fd(fd).unwrap()
25    }
26}
27impl IntoRawFd for AsyncDevice {
28    fn into_raw_fd(self) -> RawFd {
29        self.into_fd().unwrap()
30    }
31}
32impl AsRawFd for AsyncDevice {
33    fn as_raw_fd(&self) -> RawFd {
34        self.get_ref().as_raw_fd()
35    }
36}
37
38impl Deref for AsyncDevice {
39    type Target = DeviceImpl;
40
41    fn deref(&self) -> &Self::Target {
42        self.get_ref()
43    }
44}
45
46impl AsyncDevice {
47    pub fn new(device: SyncDevice) -> io::Result<AsyncDevice> {
48        AsyncDevice::new_dev(device.0)
49    }
50
51    /// # Safety
52    /// This method is safe if the provided fd is valid
53    /// Construct a AsyncDevice from an existing file descriptor
54    pub unsafe fn from_fd(fd: RawFd) -> io::Result<AsyncDevice> {
55        AsyncDevice::new_dev(DeviceImpl::from_fd(fd))
56    }
57    pub fn into_fd(self) -> io::Result<RawFd> {
58        Ok(self.into_device()?.into_raw_fd())
59    }
60    /// Waits for the device to become readable.
61    ///
62    /// This function is usually paired with `try_recv()`.
63    ///
64    /// The function may complete without the device being readable. This is a
65    /// false-positive and attempting a `try_recv()` will return with
66    /// `io::ErrorKind::WouldBlock`.
67    ///
68    /// # Cancel safety
69    ///
70    /// This method is cancel safe. Once a readiness event occurs, the method
71    /// will continue to return immediately until the readiness event is
72    /// consumed by an attempt to read that fails with `WouldBlock` or
73    /// `Poll::Pending`.
74    pub async fn readable(&self) -> io::Result<()> {
75        self.0.readable().await.map(|_| ())
76    }
77    /// Waits for the device to become writable.
78    ///
79    /// This function is usually paired with `try_send()`.
80    ///
81    /// The function may complete without the device being writable. This is a
82    /// false-positive and attempting a `try_send()` will return with
83    /// `io::ErrorKind::WouldBlock`.
84    ///
85    /// # Cancel safety
86    ///
87    /// This method is cancel safe. Once a readiness event occurs, the method
88    /// will continue to return immediately until the readiness event is
89    /// consumed by an attempt to write that fails with `WouldBlock` or
90    /// `Poll::Pending`.
91    pub async fn writable(&self) -> io::Result<()> {
92        self.0.writable().await.map(|_| ())
93    }
94    /// Receives a single packet from the device.
95    /// On success, returns the number of bytes read.
96    ///
97    /// The function must be called with valid byte array `buf` of sufficient
98    /// size to hold the message bytes. If a message is too long to fit in the
99    /// supplied buffer, excess bytes may be discarded.
100    pub async fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
101        self.read_with(|device| device.recv(buf)).await
102    }
103    /// Tries to receive a single packet from the device.
104    /// On success, returns the number of bytes read.
105    ///
106    /// This method must be called with valid byte array `buf` of sufficient size
107    /// to hold the message bytes. If a message is too long to fit in the
108    /// supplied buffer, excess bytes may be discarded.
109    ///
110    /// When there is no pending data, `Err(io::ErrorKind::WouldBlock)` is
111    /// returned. This function is usually paired with `readable()`.
112    pub fn try_recv(&self, buf: &mut [u8]) -> io::Result<usize> {
113        self.try_read_io(|device| device.recv(buf))
114    }
115
116    /// Send a packet to the device
117    ///
118    /// # Return
119    /// On success, the number of bytes sent is returned, otherwise, the encountered error is returned.
120    pub async fn send(&self, buf: &[u8]) -> io::Result<usize> {
121        self.write_with(|device| device.send(buf)).await
122    }
123    /// Tries to send packet to the device.
124    ///
125    /// When the device buffer is full, `Err(io::ErrorKind::WouldBlock)` is
126    /// returned. This function is usually paired with `writable()`.
127    ///
128    /// # Returns
129    ///
130    /// If successful, `Ok(n)` is returned, where `n` is the number of bytes
131    /// sent. If the device is not ready to send data,
132    /// `Err(ErrorKind::WouldBlock)` is returned.
133    pub fn try_send(&self, buf: &[u8]) -> io::Result<usize> {
134        self.try_write_io(|device| device.send(buf))
135    }
136    /// Receives a packet into multiple buffers (scatter read).
137    /// **Processes single packet per call**.
138    pub async fn recv_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
139        self.read_with(|device| device.recv_vectored(bufs)).await
140    }
141    /// Non-blocking version of `recv_vectored`.
142    pub fn try_recv_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
143        self.try_read_io(|device| device.recv_vectored(bufs))
144    }
145    /// Sends multiple buffers as a single packet (gather write).
146    pub async fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
147        self.write_with(|device| device.send_vectored(bufs)).await
148    }
149    /// Non-blocking version of `send_vectored`.
150    pub fn try_send_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
151        self.try_write_io(|device| device.send_vectored(bufs))
152    }
153}
154
155#[cfg(target_os = "linux")]
156impl AsyncDevice {
157    pub fn try_clone(&self) -> io::Result<Self> {
158        AsyncDevice::new_dev(self.get_ref().try_clone()?)
159    }
160    /// Recv a packet from the device.
161    /// If offload is enabled. This method can be used to obtain processed data.
162    ///
163    /// original_buffer is used to store raw data, including the VirtioNetHdr and the unsplit IP packet. The recommended size is 10 + 65535.
164    /// bufs and sizes are used to store the segmented IP packets. bufs.len == sizes.len > 65535/MTU
165    /// offset: Starting position
166    #[cfg(target_os = "linux")]
167    pub async fn recv_multiple<B: AsRef<[u8]> + AsMut<[u8]>>(
168        &self,
169        original_buffer: &mut [u8],
170        bufs: &mut [B],
171        sizes: &mut [usize],
172        offset: usize,
173    ) -> io::Result<usize> {
174        if bufs.is_empty() || bufs.len() != sizes.len() {
175            return Err(io::Error::new(io::ErrorKind::Other, "bufs error"));
176        }
177        let tun = self.get_ref();
178        if tun.vnet_hdr {
179            let len = self.recv(original_buffer).await?;
180            if len <= VIRTIO_NET_HDR_LEN {
181                Err(io::Error::new(
182                    io::ErrorKind::Other,
183                    format!(
184                        "length of packet ({len}) <= VIRTIO_NET_HDR_LEN ({VIRTIO_NET_HDR_LEN})",
185                    ),
186                ))?
187            }
188            let hdr = VirtioNetHdr::decode(&original_buffer[..VIRTIO_NET_HDR_LEN])?;
189            tun.handle_virtio_read(
190                hdr,
191                &mut original_buffer[VIRTIO_NET_HDR_LEN..len],
192                bufs,
193                sizes,
194                offset,
195            )
196        } else {
197            let len = self.recv(bufs[0].as_mut()).await?;
198            sizes[0] = len;
199            Ok(1)
200        }
201    }
202    /// send multiple fragmented data packets.
203    /// GROTable can be reused, as it is used to assist in data merging.
204    /// Offset is the starting position of the data. Need to meet offset>10.
205    #[cfg(target_os = "linux")]
206    pub async fn send_multiple<B: crate::platform::ExpandBuffer>(
207        &self,
208        gro_table: &mut GROTable,
209        bufs: &mut [B],
210        mut offset: usize,
211    ) -> io::Result<usize> {
212        gro_table.reset();
213        let tun = self.get_ref();
214        if tun.vnet_hdr {
215            handle_gro(
216                bufs,
217                offset,
218                &mut gro_table.tcp_gro_table,
219                &mut gro_table.udp_gro_table,
220                tun.udp_gso,
221                &mut gro_table.to_write,
222            )?;
223            offset -= VIRTIO_NET_HDR_LEN;
224        } else {
225            for i in 0..bufs.len() {
226                gro_table.to_write.push(i);
227            }
228        }
229
230        let mut total = 0;
231        let mut err = Ok(());
232        for buf_idx in &gro_table.to_write {
233            match self.send(&bufs[*buf_idx].as_ref()[offset..]).await {
234                Ok(n) => {
235                    total += n;
236                }
237                Err(e) => {
238                    if let Some(code) = e.raw_os_error() {
239                        if libc::EBADFD == code {
240                            return Err(e);
241                        }
242                    }
243                    err = Err(e)
244                }
245            }
246        }
247        err?;
248        Ok(total)
249    }
250}