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 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 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 #[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 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 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 pub fn v4_dgram() -> io::Result<Self> {
94 Self::new(Domain::IPV4, SockType::DGRAM)
95 }
96
97 pub fn v6_dgram() -> io::Result<Self> {
99 Self::new(Domain::IPV6, SockType::DGRAM)
100 }
101
102 pub fn raw_v4() -> io::Result<Self> {
104 Self::new(Domain::IPV4, SockType::RAW)
105 }
106
107 pub fn raw_v6() -> io::Result<Self> {
109 Self::new(Domain::IPV6, SockType::RAW)
110 }
111
112 pub async fn send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
114 self.inner.send_to(buf, target).await
115 }
116
117 pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
119 self.inner.recv_from(buf).await
120 }
121
122 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}