pub struct SyncDevice(/* private fields */);Expand description
A transparent wrapper around DeviceImpl, providing synchronous I/O operations.
§Examples
Basic read/write operation:
use std::net::Ipv4Addr;
use tun_rs::DeviceBuilder;
fn main() -> std::io::Result<()> {
// Create a TUN device using the builder
let mut tun = DeviceBuilder::new()
.name("my-tun")
.ipv4(Ipv4Addr::new(10, 0, 0, 1), 24, None)
.build_sync()?;
// Send a packet
// Example IP packet (Replace with real IP message)
let packet = b"[IP Packet: 10.0.0.1 -> 10.0.0.2] Hello, TUN!";
tun.send(packet)?;
println!("Sent {} bytes IP packet", packet.len());
// Receive a packet
let mut buf = [0u8; 1500];
let n = tun.recv(&mut buf)?;
println!("Received {} bytes: {:?}", n, &buf[..n]);
Ok(())
}Implementations§
Source§impl SyncDevice
impl SyncDevice
Sourcepub unsafe fn from_fd(fd: RawFd) -> Result<Self>
Available on Unix only.
pub unsafe fn from_fd(fd: RawFd) -> Result<Self>
Creates a SyncDevice from a raw file descriptor.
§Safety
- The file descriptor (
fd) must be an owned file descriptor. - It must be valid and open.
- The file descriptor must refer to a TUN/TAP device.
- After calling this function, the
SyncDevicetakes ownership of the fd and will close it when dropped.
This function is only available on Unix platforms.
§Example
On iOS using PacketTunnelProvider:
use std::os::fd::RawFd;
use tun_rs::SyncDevice;
// On iOS, obtain fd from PacketTunnelProvider.packetFlow
// let fd: RawFd = packet_flow.value(forKeyPath: "socket.fileDescriptor") as! Int32
let fd: RawFd = 10; // Example value - obtain from platform VPN APIs
// SAFETY: fd must be a valid, open file descriptor to a TUN device
let dev = unsafe { SyncDevice::from_fd(fd)? };
// Device now owns the file descriptor
let mut buf = [0u8; 1500];
let n = dev.recv(&mut buf)?;
println!("Received {} bytes", n);On Android using VpnService:
use tun_rs::SyncDevice;
// On Android, obtain fd from VpnService.Builder.establish()
// ParcelFileDescriptor vpnInterface = builder.establish();
// int fd = vpnInterface.getFd();
let fd = 10; // Example value - obtain from VpnService
// SAFETY: fd must be valid and open
let dev = unsafe { SyncDevice::from_fd(fd)? };
let mut buf = [0u8; 1500];
loop {
let n = dev.recv(&mut buf)?;
// Process packet...
}Sourcepub fn recv(&self, buf: &mut [u8]) -> Result<usize>
pub fn recv(&self, buf: &mut [u8]) -> Result<usize>
Receives data from the device into the provided buffer.
Returns the number of bytes read, or an I/O error.
§Example
use std::net::Ipv4Addr;
use tun_rs::DeviceBuilder;
let mut tun = DeviceBuilder::new()
.name("my-tun")
.ipv4(Ipv4Addr::new(10, 0, 0, 1), 24, None)
.build_sync()
.unwrap();
let mut buf = [0u8; 1500];
tun.recv(&mut buf).unwrap();§Note
Blocking the current thread if no packet is available
Sourcepub fn send(&self, buf: &[u8]) -> Result<usize>
pub fn send(&self, buf: &[u8]) -> Result<usize>
Sends data from the provided buffer to the device.
Returns the number of bytes written, or an I/O error.
§Example
use std::net::Ipv4Addr;
use tun_rs::DeviceBuilder;
let mut tun = DeviceBuilder::new()
.name("my-tun")
.ipv4(Ipv4Addr::new(10, 0, 0, 1), 24, None)
.build_sync()
.unwrap();
tun.send(b"hello").unwrap();pub fn shutdown(&self) -> Result<()>
experimental only.Sourcepub fn recv_intr(&self, buf: &mut [u8], event: &InterruptEvent) -> Result<usize>
Available on crate feature interruptible only.
pub fn recv_intr(&self, buf: &mut [u8], event: &InterruptEvent) -> Result<usize>
interruptible only.Reads data into the provided buffer, with support for interruption.
This function attempts to read from the underlying file descriptor into buf,
and can be interrupted using the given InterruptEvent. If the event is triggered
while the read operation is blocked, the function will return early with
an error of kind std::io::ErrorKind::Interrupted.
§Arguments
buf- The buffer to store the read data.event- AnInterruptEventused to interrupt the blocking read.
§Returns
On success, returns the number of bytes read. On failure, returns an std::io::Error.
§Platform-specific Behavior
On Unix platforms, it is recommended to use this together with set_nonblocking(true).
Without setting non-blocking mode, concurrent reads may not respond properly to interrupt signals.
§Feature
This method is only available when the interruptible feature is enabled.
Sourcepub fn recv_intr_timeout(
&self,
buf: &mut [u8],
event: &InterruptEvent,
timeout: Option<Duration>,
) -> Result<usize>
Available on crate feature interruptible only.
pub fn recv_intr_timeout( &self, buf: &mut [u8], event: &InterruptEvent, timeout: Option<Duration>, ) -> Result<usize>
interruptible only.Like recv_intr, but with an optional timeout.
This function reads data from the device into the provided buffer, but can be interrupted by the given event or by the timeout expiring.
§Arguments
buf- The buffer to store the read dataevent- The interrupt event that can cancel the operationtimeout- Optional duration to wait before returning with a timeout error
§Returns
Ok(n)- Successfully readnbytesErr(e)withErrorKind::Interrupted- Operation was interrupted by the eventErr(e)withErrorKind::TimedOut- Timeout expired before data was available
§Example
use std::time::Duration;
use tun_rs::{DeviceBuilder, InterruptEvent};
let dev = DeviceBuilder::new()
.ipv4("10.0.0.1", 24, None)
.build_sync()?;
let event = InterruptEvent::new()?;
let mut buf = vec![0u8; 1500];
// Read with a 5-second timeout
match dev.recv_intr_timeout(&mut buf, &event, Some(Duration::from_secs(5))) {
Ok(n) => println!("Received {} bytes", n),
Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {
println!("Timed out waiting for data");
}
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => {
println!("Interrupted by event");
}
Err(e) => return Err(e),
}§Feature
This method is only available when the interruptible feature is enabled.
Sourcepub fn recv_vectored_intr(
&self,
bufs: &mut [IoSliceMut<'_>],
event: &InterruptEvent,
) -> Result<usize>
Available on Unix and crate feature interruptible only.
pub fn recv_vectored_intr( &self, bufs: &mut [IoSliceMut<'_>], event: &InterruptEvent, ) -> Result<usize>
interruptible only.Sourcepub fn recv_vectored_intr_timeout(
&self,
bufs: &mut [IoSliceMut<'_>],
event: &InterruptEvent,
timeout: Option<Duration>,
) -> Result<usize>
Available on Unix and crate feature interruptible only.
pub fn recv_vectored_intr_timeout( &self, bufs: &mut [IoSliceMut<'_>], event: &InterruptEvent, timeout: Option<Duration>, ) -> Result<usize>
interruptible only.Like recv_vectored_intr, but with an optional timeout.
This function reads data from the device into multiple buffers using vectored I/O, but can be interrupted by the given event or by the timeout expiring.
§Arguments
bufs- Multiple buffers to store the read dataevent- The interrupt event that can cancel the operationtimeout- Optional duration to wait before returning with a timeout error
§Returns
Ok(n)- Successfully readnbytes total across all buffersErr(e)withErrorKind::Interrupted- Operation was interrupted by the eventErr(e)withErrorKind::TimedOut- Timeout expired before data was available
§Example
use std::io::IoSliceMut;
use std::time::Duration;
use tun_rs::{DeviceBuilder, InterruptEvent};
let dev = DeviceBuilder::new()
.ipv4("10.0.0.1", 24, None)
.build_sync()?;
let event = InterruptEvent::new()?;
let mut header = [0u8; 20];
let mut payload = [0u8; 1480];
let mut bufs = [IoSliceMut::new(&mut header), IoSliceMut::new(&mut payload)];
// Read with timeout into multiple buffers
match dev.recv_vectored_intr_timeout(&mut bufs, &event, Some(Duration::from_secs(5))) {
Ok(n) => println!("Received {} bytes", n),
Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {
println!("Timed out");
}
Err(e) => return Err(e),
}§Feature
This method is only available when the interruptible feature is enabled.
pub fn wait_readable_intr(&self, event: &InterruptEvent) -> Result<()>
interruptible only.Sourcepub fn wait_readable_intr_timeout(
&self,
event: &InterruptEvent,
timeout: Option<Duration>,
) -> Result<()>
Available on crate feature interruptible only.
pub fn wait_readable_intr_timeout( &self, event: &InterruptEvent, timeout: Option<Duration>, ) -> Result<()>
interruptible only.Like wait_readable_intr, but with an optional timeout.
This function waits until the device becomes readable, but can be interrupted by the given event or by the timeout expiring.
§Arguments
event- The interrupt event that can cancel the waittimeout- Optional duration to wait before returning with a timeout error
§Returns
Ok(())- Device is now readableErr(e)withErrorKind::Interrupted- Wait was interrupted by the eventErr(e)withErrorKind::TimedOut- Timeout expired
§Example
use std::time::Duration;
use tun_rs::{DeviceBuilder, InterruptEvent};
let dev = DeviceBuilder::new()
.ipv4("10.0.0.1", 24, None)
.build_sync()?;
let event = InterruptEvent::new()?;
// Wait for readability with timeout
match dev.wait_readable_intr_timeout(&event, Some(Duration::from_secs(10))) {
Ok(()) => {
println!("Device is readable");
// Now try to read...
}
Err(e) if e.kind() == std::io::ErrorKind::TimedOut => {
println!("Timed out waiting for data");
}
Err(e) => return Err(e),
}§Feature
This method is only available when the interruptible feature is enabled.
pub fn send_intr(&self, buf: &[u8], event: &InterruptEvent) -> Result<usize>
interruptible only.Sourcepub fn send_vectored_intr(
&self,
bufs: &[IoSlice<'_>],
event: &InterruptEvent,
) -> Result<usize>
Available on Unix and crate feature interruptible only.
pub fn send_vectored_intr( &self, bufs: &[IoSlice<'_>], event: &InterruptEvent, ) -> Result<usize>
interruptible only.Sends data to the device from multiple buffers using vectored I/O, with interruption support.
Like send_intr, but uses writev to send from multiple
non-contiguous buffers in a single operation.
§Arguments
bufs- Multiple buffers containing the data to sendevent- The interrupt event that can cancel the operation
§Returns
Ok(n)- Successfully sentnbytes total from all buffersErr(e)withErrorKind::Interrupted- Operation was interrupted by the event
§Example
use std::io::IoSlice;
use tun_rs::{DeviceBuilder, InterruptEvent};
let dev = DeviceBuilder::new()
.ipv4("10.0.0.1", 24, None)
.build_sync()?;
let event = InterruptEvent::new()?;
let header = [0x45, 0x00, 0x00, 0x14]; // IPv4 header
let payload = b"Hello, TUN!";
let bufs = [IoSlice::new(&header), IoSlice::new(payload)];
match dev.send_vectored_intr(&bufs, &event) {
Ok(n) => println!("Sent {} bytes", n),
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => {
println!("Send was interrupted");
}
Err(e) => return Err(e),
}§Feature
This method is only available when the interruptible feature is enabled.
Sourcepub fn wait_writable_intr(&self, event: &InterruptEvent) -> Result<()>
Available on Unix and crate feature interruptible only.
pub fn wait_writable_intr(&self, event: &InterruptEvent) -> Result<()>
interruptible only.Waits for the device to become writable, with interruption support.
This function waits until the device is ready to accept data for sending, but can be interrupted by the given event.
§Arguments
event- The interrupt event that can cancel the wait
§Returns
Ok(())- Device is now writableErr(e)withErrorKind::Interrupted- Wait was interrupted by the event
§Example
use tun_rs::{DeviceBuilder, InterruptEvent};
let dev = DeviceBuilder::new()
.ipv4("10.0.0.1", 24, None)
.build_sync()?;
let event = InterruptEvent::new()?;
// Wait for device to be writable
match dev.wait_writable_intr(&event) {
Ok(()) => {
println!("Device is writable");
// Now send data...
}
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => {
println!("Wait was interrupted");
}
Err(e) => return Err(e),
}§Feature
This method is only available when the interruptible feature is enabled.
Sourcepub fn recv_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>
Available on Unix only.
pub fn recv_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>
Receives data from the device into multiple buffers using vectored I/O.
Note: This method operates on a single packet only. It will only read data from one packet, even if multiple buffers are provided.
Returns the total number of bytes read from the packet, or an error.
§Example
use std::io::IoSliceMut;
use tun_rs::DeviceBuilder;
let dev = DeviceBuilder::new()
.ipv4("10.0.0.1", 24, None)
.build_sync()?;
// Prepare multiple buffers for receiving data
let mut header = [0u8; 20];
let mut payload = [0u8; 1480];
let mut bufs = [IoSliceMut::new(&mut header), IoSliceMut::new(&mut payload)];
// Read one packet into the buffers
let n = dev.recv_vectored(&mut bufs)?;
println!("Received {} bytes total", n);Sourcepub fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> Result<usize>
Available on Unix only.
pub fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> Result<usize>
Sends data to the device from multiple buffers using vectored I/O.
Note: This method operates on a single packet only. It will only send the data contained in the provided buffers as one packet.
Returns the total number of bytes written for the packet, or an error.
§Example
use std::io::IoSlice;
use tun_rs::DeviceBuilder;
let dev = DeviceBuilder::new()
.ipv4("10.0.0.1", 24, None)
.build_sync()?;
// Send a packet with header and payload in separate buffers
let header = [0x45, 0x00, 0x00, 0x14]; // IPv4 header
let payload = b"Hello, TUN!";
let bufs = [IoSlice::new(&header), IoSlice::new(payload)];
let n = dev.send_vectored(&bufs)?;
println!("Sent {} bytes", n);Sourcepub fn is_nonblocking(&self) -> Result<bool>
Available on Unix only.
pub fn is_nonblocking(&self) -> Result<bool>
Checks whether the device is currently operating in nonblocking mode.
Returns true if nonblocking mode is enabled, false otherwise, or an error.
§Example
use tun_rs::DeviceBuilder;
let dev = DeviceBuilder::new()
.ipv4("10.0.0.1", 24, None)
.build_sync()?;
// Check current nonblocking mode
if dev.is_nonblocking()? {
println!("Device is in nonblocking mode");
} else {
println!("Device is in blocking mode");
}Sourcepub fn set_nonblocking(&self, nonblocking: bool) -> Result<()>
Available on Unix only.
pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()>
Sets the nonblocking mode for the device.
nonblocking: Passtrueto enable nonblocking mode,falseto disable.
Returns an empty result on success or an I/O error.
§Example
use tun_rs::DeviceBuilder;
let dev = DeviceBuilder::new()
.ipv4("10.0.0.1", 24, None)
.build_sync()?;
// Enable nonblocking mode for non-blocking I/O
dev.set_nonblocking(true)?;
// Now recv() will return WouldBlock if no data is available
let mut buf = [0u8; 1500];
match dev.recv(&mut buf) {
Ok(n) => println!("Received {} bytes", n),
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
println!("No data available");
}
Err(e) => return Err(e),
}Trait Implementations§
Source§impl AsFd for SyncDevice
Available on Unix only.
impl AsFd for SyncDevice
Source§fn as_fd(&self) -> BorrowedFd<'_>
fn as_fd(&self) -> BorrowedFd<'_>
Source§impl AsRawFd for SyncDevice
Available on Unix only.
impl AsRawFd for SyncDevice
Source§impl Deref for SyncDevice
impl Deref for SyncDevice
Source§impl FromRawFd for SyncDevice
Available on Unix only.
impl FromRawFd for SyncDevice
Source§unsafe fn from_raw_fd(fd: RawFd) -> Self
unsafe fn from_raw_fd(fd: RawFd) -> Self
Self from the given raw file
descriptor. Read more