use std::{io, mem::MaybeUninit, net::SocketAddr};
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
#[cfg(unix)]
use super::sock::raw;
use super::sock::{socket_addr, Io};
use crate::buf::{BufResult, IoBuf, IoBufMut};
pub struct UdpSocket {
io: Io,
}
impl UdpSocket {
pub async fn bind(addr: impl crate::addr::ToAddrs) -> io::Result<Self> {
let mut last = None;
for sa in crate::addr::lookup_host(addr).await? {
match Self::bind_addr(sa) {
Ok(s) => return Ok(s),
Err(e) => last = Some(e),
}
}
Err(last.unwrap_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"could not resolve to any address",
)
}))
}
pub fn bind_addr(addr: SocketAddr) -> io::Result<Self> {
let sock = Socket::new(Domain::for_address(addr), Type::DGRAM, Some(Protocol::UDP))?;
#[cfg(unix)]
sock.set_reuse_address(true)?;
#[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))]
sock.set_reuse_port(true)?;
sock.bind(&SockAddr::from(addr))?;
Ok(Self { io: Io::new(sock)? })
}
pub fn from_std(socket: std::net::UdpSocket) -> io::Result<Self> {
Ok(Self {
io: Io::new(Socket::from(socket))?,
})
}
pub async fn connect(&self, addr: impl crate::addr::ToAddrs) -> io::Result<()> {
let mut last = None;
for sa in crate::addr::lookup_host(addr).await? {
match self.connect_addr(sa) {
Ok(()) => return Ok(()),
Err(e) => last = Some(e),
}
}
Err(last.unwrap_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"could not resolve to any address",
)
}))
}
pub fn connect_addr(&self, addr: SocketAddr) -> io::Result<()> {
self.io.sock.connect(&SockAddr::from(addr))
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
socket_addr(self.io.sock.local_addr()?)
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
socket_addr(self.io.sock.peer_addr()?)
}
pub async fn send<B>(&self, buf: B) -> BufResult<usize, B>
where
B: IoBuf + Send + 'static,
{
loop {
match self.try_send(&buf) {
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
if let Err(e) = self.io.ready(true).await {
return (Err(e), buf);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
other => return (other, buf),
}
}
}
pub async fn recv<B>(&self, mut buf: B) -> BufResult<usize, B>
where
B: IoBufMut + Send + 'static,
{
loop {
let (res, b) = self.try_recv(buf);
buf = b;
match res {
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
if let Err(e) = self.io.ready(false).await {
return (Err(e), buf);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
other => return (other, buf),
}
}
}
pub async fn send_to<B>(&self, buf: B, target: SocketAddr) -> BufResult<usize, B>
where
B: IoBuf + Send + 'static,
{
loop {
match self.try_send_to(&buf, target) {
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
if let Err(e) = self.io.ready(true).await {
return (Err(e), buf);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
other => return (other, buf),
}
}
}
pub async fn recv_from<B>(&self, mut buf: B) -> (io::Result<(usize, SocketAddr)>, B)
where
B: IoBufMut + Send + 'static,
{
loop {
let (res, b) = self.try_recv_from(buf);
buf = b;
match res {
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
if let Err(e) = self.io.ready(false).await {
return (Err(e), buf);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
other => return (other, buf),
}
}
}
pub fn try_send_to<B: IoBuf>(&self, buf: &B, target: SocketAddr) -> io::Result<usize> {
let data = unsafe { std::slice::from_raw_parts(buf.stable_ptr(), buf.bytes_init()) };
self.io.sock.send_to(data, &SockAddr::from(target))
}
pub fn try_send<B: IoBuf>(&self, buf: &B) -> io::Result<usize> {
let data = unsafe { std::slice::from_raw_parts(buf.stable_ptr(), buf.bytes_init()) };
self.io.sock.send(data)
}
pub fn try_recv_from<B: IoBufMut>(&self, mut buf: B) -> (io::Result<(usize, SocketAddr)>, B) {
let total = buf.bytes_total();
let ptr = buf.stable_ptr_mut() as *mut MaybeUninit<u8>;
let spare = unsafe { std::slice::from_raw_parts_mut(ptr, total) };
match self.io.sock.recv_from(spare) {
Ok((n, from)) => {
unsafe { buf.set_init(n) };
(socket_addr(from).map(|a| (n, a)), buf)
}
Err(e) => (Err(e), buf),
}
}
pub fn try_recv<B: IoBufMut>(&self, mut buf: B) -> BufResult<usize, B> {
let total = buf.bytes_total();
let ptr = buf.stable_ptr_mut() as *mut MaybeUninit<u8>;
let spare = unsafe { std::slice::from_raw_parts_mut(ptr, total) };
match self.io.sock.recv(spare) {
Ok(n) => {
unsafe { buf.set_init(n) };
(Ok(n), buf)
}
Err(e) => (Err(e), buf),
}
}
pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
self.io.sock.set_broadcast(on)
}
pub fn broadcast(&self) -> io::Result<bool> {
self.io.sock.broadcast()
}
#[cfg(unix)]
pub fn set_reuseaddr(&self, on: bool) -> io::Result<()> {
self.io.sock.set_reuse_address(on)
}
#[cfg(unix)]
pub fn reuseaddr(&self) -> io::Result<bool> {
self.io.sock.reuse_address()
}
#[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))]
pub fn set_reuseport(&self, on: bool) -> io::Result<()> {
self.io.sock.set_reuse_port(on)
}
#[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))]
pub fn reuseport(&self) -> io::Result<bool> {
self.io.sock.reuse_port()
}
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
self.io.sock.set_ttl(ttl)
}
pub fn ttl(&self) -> io::Result<u32> {
self.io.sock.ttl()
}
pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
self.io.sock.set_recv_buffer_size(size)
}
pub fn recv_buffer_size(&self) -> io::Result<usize> {
self.io.sock.recv_buffer_size()
}
pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
self.io.sock.set_send_buffer_size(size)
}
pub fn send_buffer_size(&self) -> io::Result<usize> {
self.io.sock.send_buffer_size()
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.io.sock.take_error()
}
#[cfg(unix)]
pub fn as_raw_fd(&self) -> std::os::fd::RawFd {
raw(&self.io.sock)
}
}