1use crate::addr::NetAddr;
27use std::convert::TryFrom;
28use std::io;
29use std::net;
30use std::os::unix::io::AsRawFd as _;
31use tokio::io::unix::AsyncFd;
32
33use nix::libc;
34
35pub struct UdpSocket {
36 fd: AsyncFd<mio::net::UdpSocket>,
37}
38
39pub type MsgFlags = crate::socket::MsgFlags;
40pub type ControlMessage = crate::socket::ControlMessage;
41pub type RecvMsg = crate::socket::RecvMsg;
42
43pub fn std_to_libc_in_addr(addr: net::Ipv4Addr) -> libc::in_addr {
44 libc::in_addr {
45 s_addr: addr
46 .octets()
47 .iter()
48 .fold(0, |acc, x| ((acc << 8) | (*x as u32))),
49 }
50}
51
52pub const fn std_to_libc_in6_addr(addr: net::Ipv6Addr) -> libc::in6_addr {
53 libc::in6_addr {
54 s6_addr: addr.octets(),
55 }
56}
57
58impl TryFrom<mio::net::UdpSocket> for UdpSocket {
59 type Error = io::Error;
60 fn try_from(s: mio::net::UdpSocket) -> Result<Self, Self::Error> {
61 Ok(UdpSocket {
62 fd: AsyncFd::new(s)?,
63 })
64 }
65}
66
67impl UdpSocket {
68 pub async fn bind(addrs: &[NetAddr]) -> Result<Self, io::Error> {
69 use crate::addr::NetAddrExt as _;
70 let mut last_err = None;
71
72 for addr in addrs {
73 match mio::net::UdpSocket::bind(addr.to_std_socket_addr().unwrap()) {
74 Ok(socket) => return Self::try_from(socket),
75 Err(e) => last_err = Some(e),
76 }
77 }
78
79 Err(last_err.unwrap_or_else(|| {
80 io::Error::new(
81 io::ErrorKind::InvalidInput,
82 "could not resolve to any address",
83 )
84 }))
85 }
86
87 pub async fn recv_msg(&self, bufsize: usize, flags: MsgFlags) -> io::Result<RecvMsg> {
88 crate::socket::recv_msg(&self.fd, bufsize, flags).await
89 }
90
91 pub async fn send_msg(
92 &self,
93 buffer: &[u8],
94 cmsg: &ControlMessage,
95 flags: MsgFlags,
96 addr: Option<&NetAddr>,
97 ) -> io::Result<()> {
98 crate::socket::send_msg(&self.fd, buffer, cmsg, flags, addr).await
99 }
100
101 pub fn local_addr(&self) -> Result<NetAddr, io::Error> {
102 self.fd.get_ref().local_addr().map(|x| x.into())
103 }
104
105 pub fn set_opt_ipv4_packet_info(&self, b: bool) -> Result<(), io::Error> {
106 nix::sys::socket::setsockopt(
107 self.fd.get_ref().as_raw_fd(),
108 nix::sys::socket::sockopt::Ipv4PacketInfo,
109 &b,
110 )
111 .map_err(|e| e.into())
112 }
113
114 pub fn set_opt_ipv6_packet_info(&self, b: bool) -> Result<(), io::Error> {
115 nix::sys::socket::setsockopt(
116 self.fd.get_ref().as_raw_fd(),
117 nix::sys::socket::sockopt::Ipv6RecvPacketInfo,
118 &b,
119 )
120 .map_err(|e| e.into())
121 }
122
123 pub fn set_opt_reuse_port(&self, b: bool) -> Result<(), io::Error> {
124 nix::sys::socket::setsockopt(
125 self.fd.get_ref().as_raw_fd(),
126 nix::sys::socket::sockopt::ReusePort,
127 &b,
128 )
129 .map_err(|e| e.into())
130 }
131}