use super::{
fd::{udp, Flags},
Protocol, Socket, TransportFeatures,
};
use crate::msg::{addr::Addr, cmsg};
use core::task::{Context, Poll};
use s2n_quic_core::{ensure, inet::ExplicitCongestionNotification, ready};
use std::{
io::{self, IoSlice, IoSliceMut},
net::SocketAddr,
};
use tokio::io::unix::{AsyncFd, TryIoError};
impl<T> Socket for AsyncFd<T>
where
T: udp::Socket,
{
#[inline]
fn local_addr(&self) -> io::Result<SocketAddr> {
self.get_ref().local_addr()
}
#[inline]
fn protocol(&self) -> Protocol {
Protocol::Udp
}
#[inline]
fn features(&self) -> TransportFeatures {
TransportFeatures::UDP
}
#[inline]
fn poll_peek_len(&self, cx: &mut Context) -> Poll<io::Result<usize>> {
loop {
let mut socket = ready!(self.poll_read_ready(cx))?;
let res = socket.try_io(udp::peek);
match res {
Ok(Ok(len)) => return Ok(len).into(),
Ok(Err(ref e)) if e.kind() == io::ErrorKind::Interrupted => {
continue;
}
Ok(Err(err)) => return Err(err).into(),
Err(err) => {
let _: TryIoError = err;
continue;
}
}
}
}
#[inline]
fn poll_recv(
&self,
cx: &mut Context,
addr: &mut Addr,
cmsg: &mut cmsg::Receiver,
buffer: &mut [IoSliceMut],
) -> Poll<io::Result<usize>> {
ensure!(!buffer.is_empty(), Ok(0).into());
debug_assert!(
buffer.iter().any(|s| !s.is_empty()),
"trying to recv into an empty buffer"
);
loop {
let mut socket = ready!(self.poll_read_ready(cx))?;
let flags = Flags::default();
let res = socket.try_io(|fd| udp::recv(fd, addr, cmsg, buffer, flags));
match res {
Ok(Ok(0)) => {
continue;
}
Ok(Ok(len)) => return Ok(len).into(),
Ok(Err(ref e)) if e.kind() == io::ErrorKind::Interrupted => {
continue;
}
Ok(Err(err)) => return Err(err).into(),
Err(err) => {
let _: TryIoError = err;
continue;
}
}
}
}
#[inline]
fn try_send(
&self,
addr: &Addr,
ecn: ExplicitCongestionNotification,
buffer: &[IoSlice],
) -> io::Result<usize> {
ensure!(!buffer.is_empty(), Ok(0));
debug_assert!(
buffer.iter().any(|s| !s.is_empty()),
"trying to send from an empty buffer"
);
debug_assert!(
addr.get().port() != 0,
"cannot send packet to unspecified port"
);
loop {
match udp::send(self.get_ref(), addr, ecn, buffer, Default::default()) {
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {
continue;
}
res => return res,
}
}
}
#[inline]
fn poll_send(
&self,
cx: &mut Context,
addr: &Addr,
ecn: ExplicitCongestionNotification,
buffer: &[IoSlice],
) -> Poll<io::Result<usize>> {
ensure!(!buffer.is_empty(), Ok(0).into());
debug_assert!(
buffer.iter().any(|s| !s.is_empty()),
"trying to send from an empty buffer"
);
debug_assert!(
addr.get().port() != 0,
"cannot send packet to unspecified port"
);
loop {
let mut socket = ready!(self.poll_write_ready(cx))?;
let res = socket.try_io(|fd| udp::send(fd, addr, ecn, buffer, Default::default()));
match res {
Ok(Ok(len)) => return Ok(len).into(),
Ok(Err(ref e)) if e.kind() == io::ErrorKind::Interrupted => {
continue;
}
Ok(Err(err)) => return Err(err).into(),
Err(err) => {
let _: TryIoError = err;
continue;
}
}
}
}
#[inline]
fn send_finish(&self) -> io::Result<()> {
Ok(())
}
}