nex_socket/udp/
async_impl.rs

1use crate::udp::UdpConfig;
2use socket2::{Domain, Protocol, Socket, Type as SockType};
3use std::io;
4use std::net::{SocketAddr, UdpSocket as StdUdpSocket};
5use tokio::net::UdpSocket;
6
7/// Asynchronous UDP socket built on top of Tokio.
8#[derive(Debug)]
9pub struct AsyncUdpSocket {
10    inner: UdpSocket,
11}
12
13impl AsyncUdpSocket {
14    /// Create an asynchronous UDP socket from the given configuration.
15    pub fn from_config(config: &UdpConfig) -> io::Result<Self> {
16        let socket = Socket::new(
17            config.socket_family.to_domain(),
18            config.socket_type.to_sock_type(),
19            Some(Protocol::UDP),
20        )?;
21
22        socket.set_nonblocking(true)?;
23
24        // Set socket options based on configuration
25        if let Some(flag) = config.reuseaddr {
26            socket.set_reuse_address(flag)?;
27        }
28        if let Some(flag) = config.broadcast {
29            socket.set_broadcast(flag)?;
30        }
31        if let Some(ttl) = config.ttl {
32            socket.set_ttl(ttl)?;
33        }
34        if let Some(hoplimit) = config.hoplimit {
35            socket.set_unicast_hops_v6(hoplimit)?;
36        }
37        if let Some(timeout) = config.read_timeout {
38            socket.set_read_timeout(Some(timeout))?;
39        }
40        if let Some(timeout) = config.write_timeout {
41            socket.set_write_timeout(Some(timeout))?;
42        }
43
44        // Linux: optional interface name
45        #[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))]
46        if let Some(iface) = &config.bind_device {
47            socket.bind_device(Some(iface.as_bytes()))?;
48        }
49
50        // bind to the specified address if provided
51        if let Some(addr) = config.bind_addr {
52            socket.bind(&addr.into())?;
53        }
54
55        #[cfg(windows)]
56        let std_socket = unsafe {
57            use std::os::windows::io::{FromRawSocket, IntoRawSocket};
58            StdUdpSocket::from_raw_socket(socket.into_raw_socket())
59        };
60        #[cfg(unix)]
61        let std_socket = unsafe {
62            use std::os::fd::{FromRawFd, IntoRawFd};
63            StdUdpSocket::from_raw_fd(socket.into_raw_fd())
64        };
65
66        let inner = UdpSocket::from_std(std_socket)?;
67
68        Ok(Self { inner })
69    }
70
71    /// Create a socket of arbitrary type (DGRAM or RAW).
72    pub fn new(domain: Domain, sock_type: SockType) -> io::Result<Self> {
73        let socket = Socket::new(domain, sock_type, Some(Protocol::UDP))?;
74        socket.set_nonblocking(true)?;
75
76        #[cfg(windows)]
77        let std_socket = unsafe {
78            use std::os::windows::io::{FromRawSocket, IntoRawSocket};
79            StdUdpSocket::from_raw_socket(socket.into_raw_socket())
80        };
81        #[cfg(unix)]
82        let std_socket = unsafe {
83            use std::os::fd::{FromRawFd, IntoRawFd};
84            StdUdpSocket::from_raw_fd(socket.into_raw_fd())
85        };
86
87        let inner = UdpSocket::from_std(std_socket)?;
88
89        Ok(Self { inner })
90    }
91
92    /// Convenience constructor for IPv4 DGRAM.
93    pub fn v4_dgram() -> io::Result<Self> {
94        Self::new(Domain::IPV4, SockType::DGRAM)
95    }
96
97    /// Convenience constructor for IPv6 DGRAM.
98    pub fn v6_dgram() -> io::Result<Self> {
99        Self::new(Domain::IPV6, SockType::DGRAM)
100    }
101
102    /// IPv4 RAW UDP. Requires administrator privileges.
103    pub fn raw_v4() -> io::Result<Self> {
104        Self::new(Domain::IPV4, SockType::RAW)
105    }
106
107    /// IPv6 RAW UDP. Requires administrator privileges.
108    pub fn raw_v6() -> io::Result<Self> {
109        Self::new(Domain::IPV6, SockType::RAW)
110    }
111
112    /// Send data asynchronously.
113    pub async fn send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
114        self.inner.send_to(buf, target).await
115    }
116
117    /// Receive data asynchronously.
118    pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
119        self.inner.recv_from(buf).await
120    }
121
122    /// Retrieve the local socket address.
123    pub fn local_addr(&self) -> io::Result<SocketAddr> {
124        self.inner.local_addr()
125    }
126
127    pub fn into_tokio_socket(self) -> io::Result<UdpSocket> {
128        Ok(self.inner)
129    }
130
131    #[cfg(unix)]
132    pub fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
133        use std::os::fd::AsRawFd;
134        self.inner.as_raw_fd()
135    }
136
137    #[cfg(windows)]
138    pub fn as_raw_socket(&self) -> std::os::windows::io::RawSocket {
139        use std::os::windows::io::AsRawSocket;
140        self.inner.as_raw_socket()
141    }
142}