use core::future::poll_fn;
use std::io;
use std::net::{Shutdown, TcpStream};
#[cfg(unix)]
use std::os::unix::net::UnixStream;
use std::sync::Arc;
use std::time::Duration;
use crate::io::source::Source;
use crate::io::{Handle, IoObject, sys};
const KERNEL_DROPS_QUEUE: bool = !cfg!(any(target_os = "linux", target_os = "android"));
macro_rules! shut {
($($ty:ty),* $(,)?) => {$(
impl Handle<$ty> {
pub async fn shut(&self, how: Shutdown) -> io::Result<()> {
shut(self.source(), how).await
}
}
)*};
}
shut!(TcpStream);
#[cfg(unix)]
shut!(UnixStream);
async fn shut(source: &Arc<Source>, how: Shutdown) -> io::Result<()> {
match how {
Shutdown::Read => shut_read(source).await?,
Shutdown::Write | Shutdown::Both => {
poll_fn(|cx| source.poll_shutdown(cx, how)).await?;
}
}
if how != Shutdown::Write && KERNEL_DROPS_QUEUE {
poll_fn(|cx| source.poll_drop_ahead(cx)).await?;
}
Ok(())
}
async fn shut_read(source: &Arc<Source>) -> io::Result<()> {
let lease = source.lease()?;
#[cfg(ring)]
if let Ok(mut job) = crate::fs::ring::shutdown(&lease, libc::SHUT_RD) {
return poll_fn(|cx| job.poll(cx.waker()))
.await
.inspect_err(crate::rt::counters::io_error);
}
sys::shutdown(lease.raw(), Shutdown::Read).inspect_err(crate::rt::counters::io_error)
}
impl Handle<TcpStream> {
pub fn abort(self) -> io::Result<()> {
super::opt::set_linger_time(self.raw_io(), Some(Duration::ZERO))?;
self.close_now();
Ok(())
}
}