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        // 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        #[cfg(windows)]
49        let std_socket = unsafe {
50            use std::os::windows::io::{FromRawSocket, IntoRawSocket};
51            StdUdpSocket::from_raw_socket(socket.into_raw_socket())
52        };
53        #[cfg(unix)]
54        let std_socket = unsafe {
55            use std::os::fd::{FromRawFd, IntoRawFd};
56            StdUdpSocket::from_raw_fd(socket.into_raw_fd())
57        };
58
59        let inner = UdpSocket::from_std(std_socket)?;
60
61        Ok(Self { inner })
62    }
63
64    /// Create a socket of arbitrary type (DGRAM or RAW).
65    pub fn new(domain: Domain, sock_type: SockType) -> io::Result<Self> {
66        let socket = Socket::new(domain, sock_type, Some(Protocol::UDP))?;
67        socket.set_nonblocking(true)?;
68
69        #[cfg(windows)]
70        let std_socket = unsafe {
71            use std::os::windows::io::{FromRawSocket, IntoRawSocket};
72            StdUdpSocket::from_raw_socket(socket.into_raw_socket())
73        };
74        #[cfg(unix)]
75        let std_socket = unsafe {
76            use std::os::fd::{FromRawFd, IntoRawFd};
77            StdUdpSocket::from_raw_fd(socket.into_raw_fd())
78        };
79
80        let inner = UdpSocket::from_std(std_socket)?;
81
82        Ok(Self { inner })
83    }
84
85    /// Convenience constructor for IPv4 DGRAM.
86    pub fn v4_dgram() -> io::Result<Self> {
87        Self::new(Domain::IPV4, SockType::DGRAM)
88    }
89
90    /// Convenience constructor for IPv6 DGRAM.
91    pub fn v6_dgram() -> io::Result<Self> {
92        Self::new(Domain::IPV6, SockType::DGRAM)
93    }
94
95    /// IPv4 RAW UDP. Requires administrator privileges.
96    pub fn raw_v4() -> io::Result<Self> {
97        Self::new(Domain::IPV4, SockType::RAW)
98    }
99
100    /// IPv6 RAW UDP. Requires administrator privileges.
101    pub fn raw_v6() -> io::Result<Self> {
102        Self::new(Domain::IPV6, SockType::RAW)
103    }
104
105    /// Send data asynchronously.
106    pub async fn send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
107        self.inner.send_to(buf, target).await
108    }
109
110    /// Receive data asynchronously.
111    pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
112        self.inner.recv_from(buf).await
113    }
114
115    /// Retrieve the local socket address.
116    pub fn local_addr(&self) -> io::Result<SocketAddr> {
117        self.inner.local_addr()
118    }
119
120    pub fn into_tokio_socket(self) -> io::Result<UdpSocket> {
121        Ok(self.inner)
122    }
123
124    #[cfg(unix)]
125    pub fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
126        use std::os::fd::AsRawFd;
127        self.inner.as_raw_fd()
128    }
129
130    #[cfg(windows)]
131    pub fn as_raw_socket(&self) -> std::os::windows::io::RawSocket {
132        use std::os::windows::io::AsRawSocket;
133        self.inner.as_raw_socket()
134    }
135}