nex_socket/udp/
async_impl.rs1use 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#[derive(Debug)]
9pub struct AsyncUdpSocket {
10 inner: UdpSocket,
11}
12
13impl AsyncUdpSocket {
14 pub fn from_config(config: &UdpConfig) -> io::Result<Self> {
16 config.validate()?;
17
18 let socket = Socket::new(
19 config.socket_family.to_domain(),
20 config.socket_type.to_sock_type(),
21 Some(Protocol::UDP),
22 )?;
23
24 socket.set_nonblocking(true)?;
25
26 if let Some(flag) = config.reuseaddr {
28 socket.set_reuse_address(flag)?;
29 }
30 #[cfg(any(
31 target_os = "android",
32 target_os = "dragonfly",
33 target_os = "freebsd",
34 target_os = "fuchsia",
35 target_os = "ios",
36 target_os = "linux",
37 target_os = "macos",
38 target_os = "netbsd",
39 target_os = "openbsd",
40 target_os = "tvos",
41 target_os = "visionos",
42 target_os = "watchos"
43 ))]
44 if let Some(flag) = config.reuseport {
45 socket.set_reuse_port(flag)?;
46 }
47 if let Some(flag) = config.broadcast {
48 socket.set_broadcast(flag)?;
49 }
50 if let Some(ttl) = config.ttl {
51 socket.set_ttl(ttl)?;
52 }
53 if let Some(hoplimit) = config.hoplimit {
54 socket.set_unicast_hops_v6(hoplimit)?;
55 }
56 if let Some(timeout) = config.read_timeout {
57 socket.set_read_timeout(Some(timeout))?;
58 }
59 if let Some(timeout) = config.write_timeout {
60 socket.set_write_timeout(Some(timeout))?;
61 }
62 if let Some(size) = config.recv_buffer_size {
63 socket.set_recv_buffer_size(size)?;
64 }
65 if let Some(size) = config.send_buffer_size {
66 socket.set_send_buffer_size(size)?;
67 }
68 if let Some(tos) = config.tos {
69 socket.set_tos(tos)?;
70 }
71 #[cfg(any(
72 target_os = "android",
73 target_os = "dragonfly",
74 target_os = "freebsd",
75 target_os = "fuchsia",
76 target_os = "ios",
77 target_os = "linux",
78 target_os = "macos",
79 target_os = "netbsd",
80 target_os = "openbsd",
81 target_os = "tvos",
82 target_os = "visionos",
83 target_os = "watchos"
84 ))]
85 if let Some(tclass) = config.tclass_v6 {
86 socket.set_tclass_v6(tclass)?;
87 }
88 if let Some(only_v6) = config.only_v6 {
89 socket.set_only_v6(only_v6)?;
90 }
91 if let Some(on) = config.recv_pktinfo {
92 crate::udp::set_recv_pktinfo(&socket, config.socket_family, on)?;
93 }
94
95 #[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))]
97 if let Some(iface) = &config.bind_device {
98 socket.bind_device(Some(iface.as_bytes()))?;
99 }
100
101 if let Some(addr) = config.bind_addr {
103 socket.bind(&addr.into())?;
104 }
105
106 #[cfg(windows)]
107 let std_socket = unsafe {
108 use std::os::windows::io::{FromRawSocket, IntoRawSocket};
109 StdUdpSocket::from_raw_socket(socket.into_raw_socket())
110 };
111 #[cfg(unix)]
112 let std_socket = unsafe {
113 use std::os::fd::{FromRawFd, IntoRawFd};
114 StdUdpSocket::from_raw_fd(socket.into_raw_fd())
115 };
116
117 let inner = UdpSocket::from_std(std_socket)?;
118
119 Ok(Self { inner })
120 }
121
122 pub fn new(domain: Domain, sock_type: SockType) -> io::Result<Self> {
124 let socket = Socket::new(domain, sock_type, Some(Protocol::UDP))?;
125 socket.set_nonblocking(true)?;
126
127 #[cfg(windows)]
128 let std_socket = unsafe {
129 use std::os::windows::io::{FromRawSocket, IntoRawSocket};
130 StdUdpSocket::from_raw_socket(socket.into_raw_socket())
131 };
132 #[cfg(unix)]
133 let std_socket = unsafe {
134 use std::os::fd::{FromRawFd, IntoRawFd};
135 StdUdpSocket::from_raw_fd(socket.into_raw_fd())
136 };
137
138 let inner = UdpSocket::from_std(std_socket)?;
139
140 Ok(Self { inner })
141 }
142
143 pub fn v4_dgram() -> io::Result<Self> {
145 Self::new(Domain::IPV4, SockType::DGRAM)
146 }
147
148 pub fn v6_dgram() -> io::Result<Self> {
150 Self::new(Domain::IPV6, SockType::DGRAM)
151 }
152
153 pub fn raw_v4() -> io::Result<Self> {
155 Self::new(Domain::IPV4, SockType::RAW)
156 }
157
158 pub fn raw_v6() -> io::Result<Self> {
160 Self::new(Domain::IPV6, SockType::RAW)
161 }
162
163 pub async fn send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
165 self.inner.send_to(buf, target).await
166 }
167
168 pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
170 self.inner.recv_from(buf).await
171 }
172
173 pub fn local_addr(&self) -> io::Result<SocketAddr> {
175 self.inner.local_addr()
176 }
177
178 pub fn into_tokio_socket(self) -> io::Result<UdpSocket> {
179 Ok(self.inner)
180 }
181
182 pub fn from_std_socket(socket: StdUdpSocket) -> io::Result<Self> {
184 Ok(Self {
185 inner: UdpSocket::from_std(socket)?,
186 })
187 }
188
189 pub fn into_std_socket(self) -> io::Result<StdUdpSocket> {
191 self.inner.into_std()
192 }
193
194 pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
196 self.inner.set_ttl(ttl)
197 }
198
199 pub fn ttl(&self) -> io::Result<u32> {
201 self.inner.ttl()
202 }
203
204 pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
206 self.inner.set_broadcast(on)
207 }
208
209 pub fn broadcast(&self) -> io::Result<bool> {
211 self.inner.broadcast()
212 }
213
214 #[cfg(unix)]
215 pub fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
216 use std::os::fd::AsRawFd;
217 self.inner.as_raw_fd()
218 }
219
220 #[cfg(windows)]
221 pub fn as_raw_socket(&self) -> std::os::windows::io::RawSocket {
222 use std::os::windows::io::AsRawSocket;
223 self.inner.as_raw_socket()
224 }
225}