nex_socket/udp/
sync_impl.rs1use crate::udp::UdpConfig;
2use socket2::{Domain, Protocol, Socket, Type as SockType};
3use std::io;
4use std::net::{SocketAddr, UdpSocket as StdUdpSocket};
5
6#[derive(Debug)]
8pub struct UdpSocket {
9 socket: Socket,
10}
11
12impl UdpSocket {
13 pub fn from_config(config: &UdpConfig) -> io::Result<Self> {
15 let socket = Socket::new(
16 config.socket_family.to_domain(),
17 config.socket_type.to_sock_type(),
18 Some(Protocol::UDP),
19 )?;
20
21 socket.set_nonblocking(false)?;
22
23 if let Some(flag) = config.reuseaddr {
25 socket.set_reuse_address(flag)?;
26 }
27 if let Some(flag) = config.broadcast {
28 socket.set_broadcast(flag)?;
29 }
30 if let Some(ttl) = config.ttl {
31 socket.set_ttl(ttl)?;
32 }
33 if let Some(hoplimit) = config.hoplimit {
34 socket.set_unicast_hops_v6(hoplimit)?;
35 }
36 if let Some(timeout) = config.read_timeout {
37 socket.set_read_timeout(Some(timeout))?;
38 }
39 if let Some(timeout) = config.write_timeout {
40 socket.set_write_timeout(Some(timeout))?;
41 }
42
43 #[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))]
45 if let Some(iface) = &config.bind_device {
46 socket.bind_device(Some(iface.as_bytes()))?;
47 }
48
49 if let Some(addr) = config.bind_addr {
51 socket.bind(&addr.into())?;
52 }
53
54 Ok(Self { socket })
55 }
56
57 pub fn new(domain: Domain, sock_type: SockType) -> io::Result<Self> {
59 let socket = Socket::new(domain, sock_type, Some(Protocol::UDP))?;
60 socket.set_nonblocking(false)?;
61 Ok(Self { socket })
62 }
63
64 pub fn v4_dgram() -> io::Result<Self> {
66 Self::new(Domain::IPV4, SockType::DGRAM)
67 }
68
69 pub fn v6_dgram() -> io::Result<Self> {
71 Self::new(Domain::IPV6, SockType::DGRAM)
72 }
73
74 pub fn raw_v4() -> io::Result<Self> {
76 Self::new(Domain::IPV4, SockType::RAW)
77 }
78
79 pub fn raw_v6() -> io::Result<Self> {
81 Self::new(Domain::IPV6, SockType::RAW)
82 }
83
84 pub fn send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
86 self.socket.send_to(buf, &target.into())
87 }
88
89 pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
91 let buf_maybe = unsafe {
93 std::slice::from_raw_parts_mut(
94 buf.as_mut_ptr() as *mut std::mem::MaybeUninit<u8>,
95 buf.len(),
96 )
97 };
98
99 let (n, addr) = self.socket.recv_from(buf_maybe)?;
100 let addr = addr
101 .as_socket()
102 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "invalid address format"))?;
103
104 Ok((n, addr))
105 }
106
107 pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
108 self.socket.set_ttl(ttl)
109 }
110
111 pub fn set_hoplimit(&self, hops: u32) -> io::Result<()> {
112 self.socket.set_unicast_hops_v6(hops)
113 }
114
115 pub fn set_keepalive(&self, on: bool) -> io::Result<()> {
116 self.socket.set_keepalive(on)
117 }
118
119 pub fn local_addr(&self) -> io::Result<SocketAddr> {
121 self.socket
122 .local_addr()?
123 .as_socket()
124 .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Failed to get socket address"))
125 }
126
127 pub fn to_std(self) -> io::Result<StdUdpSocket> {
129 Ok(self.socket.into())
130 }
131
132 #[cfg(unix)]
133 pub fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
134 use std::os::fd::AsRawFd;
135 self.socket.as_raw_fd()
136 }
137
138 #[cfg(windows)]
139 pub fn as_raw_socket(&self) -> std::os::windows::io::RawSocket {
140 use std::os::windows::io::AsRawSocket;
141 self.socket.as_raw_socket()
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 #[test]
150 fn create_v4_socket() {
151 let sock = UdpSocket::v4_dgram().expect("create socket");
152 let addr = sock.local_addr().expect("addr");
153 assert!(addr.is_ipv4());
154 }
155}