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    socket: Socket,
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        // Determine address family from the bind address
17        let domain = match config.bind_addr {
18            Some(SocketAddr::V4(_)) => Domain::IPV4,
19            Some(SocketAddr::V6(_)) => Domain::IPV6,
20            None => Domain::IPV4, // default
21        };
22
23        let socket = Socket::new(domain, SockType::DGRAM, Some(Protocol::UDP))?;
24
25        if let Some(flag) = config.reuseaddr {
26            socket.set_reuse_address(flag)?;
27        }
28
29        if let Some(flag) = config.broadcast {
30            socket.set_broadcast(flag)?;
31        }
32
33        if let Some(ttl) = config.ttl {
34            socket.set_ttl(ttl)?;
35        }
36
37        #[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))]
38        if let Some(iface) = &config.bind_device {
39            socket.bind_device(Some(iface.as_bytes()))?;
40        }
41
42        if let Some(addr) = config.bind_addr {
43            socket.bind(&addr.into())?;
44        }
45
46        socket.set_nonblocking(true)?;
47
48        Ok(Self { socket })
49    }
50
51    /// Create a socket of arbitrary type (DGRAM or RAW).
52    pub fn new(domain: Domain, sock_type: SockType) -> io::Result<Self> {
53        let socket = Socket::new(domain, sock_type, Some(Protocol::UDP))?;
54        socket.set_nonblocking(true)?;
55        Ok(Self { socket })
56    }
57
58    /// Convenience constructor for IPv4 DGRAM.
59    pub fn v4_dgram() -> io::Result<Self> {
60        Self::new(Domain::IPV4, SockType::DGRAM)
61    }
62
63    /// Convenience constructor for IPv6 DGRAM.
64    pub fn v6_dgram() -> io::Result<Self> {
65        Self::new(Domain::IPV6, SockType::DGRAM)
66    }
67
68    /// IPv4 RAW UDP. Requires administrator privileges.
69    pub fn raw_v4() -> io::Result<Self> {
70        Self::new(Domain::IPV4, SockType::RAW)
71    }
72
73    /// IPv6 RAW UDP. Requires administrator privileges.
74    pub fn raw_v6() -> io::Result<Self> {
75        Self::new(Domain::IPV6, SockType::RAW)
76    }
77
78    /// Send data asynchronously.
79    pub async fn send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
80        let std_udp: StdUdpSocket = self.socket.try_clone()?.into();
81        let udp_socket = UdpSocket::from_std(std_udp)?;
82        udp_socket.send_to(buf, target).await
83    }
84
85    /// Receive data asynchronously.
86    pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
87        let std_udp: StdUdpSocket = self.socket.try_clone()?.into();
88        let udp_socket = UdpSocket::from_std(std_udp)?;
89        udp_socket.recv_from(buf).await
90    }
91
92    /// Retrieve the local socket address.
93    pub fn local_addr(&self) -> io::Result<SocketAddr> {
94        self.socket.local_addr()?.as_socket().ok_or_else(|| {
95            io::Error::new(io::ErrorKind::Other, "Failed to get socket address")
96        })
97    }
98
99    pub fn into_tokio_socket(self) -> io::Result<UdpSocket> {
100        let std_socket: StdUdpSocket = self.socket.into();
101        UdpSocket::from_std(std_socket)
102    }
103
104    #[cfg(unix)]
105    pub fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
106        use std::os::fd::AsRawFd;
107        self.socket.as_raw_fd()
108    }
109
110    #[cfg(windows)]
111    pub fn as_raw_socket(&self) -> std::os::windows::io::RawSocket {
112        use std::os::windows::io::AsRawSocket;
113        self.socket.as_raw_socket()
114    }
115}