#[cfg(unix)]
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, AsSocket, BorrowedSocket, RawSocket};
use std::{
fmt,
io::{self, Read, Write},
net::{Shutdown, SocketAddr},
pin::Pin,
sync::atomic::{AtomicBool, Ordering},
task::{Context, Poll, ready},
};
use futures_core::Stream;
use futures_io::{AsyncRead, AsyncWrite};
use socket2::{Domain, SockAddr};
use super::{connect, set_nosigpipe};
use crate::{AsyncIo, Local, Mode, Runtime};
pub struct TcpListener<M = Local>
where
M: Mode,
{
io: AsyncIo<std::net::TcpListener, M>,
}
impl<M> TcpListener<M>
where
M: Mode,
{
pub fn bind<A>(runtime: &Runtime<M>, addr: A) -> io::Result<Self>
where
A: Into<SocketAddr>,
{
Self::from_std(runtime, std::net::TcpListener::bind(addr.into())?)
}
pub fn from_std(runtime: &Runtime<M>, listener: std::net::TcpListener) -> io::Result<Self> {
listener.set_nonblocking(true)?;
Ok(Self {
io: AsyncIo::from_nonblocking(runtime, listener)?,
})
}
pub async fn accept(&self) -> io::Result<(TcpStream<M>, SocketAddr)> {
let (stream, address) = self.io.read_with(|listener| listener.accept()).await?;
self.accepted(stream, address)
}
pub fn incoming(&self) -> Incoming<'_, M> {
Incoming { listener: self }
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io.get_ref().local_addr()
}
pub fn ttl(&self) -> io::Result<u32> {
self.io.get_ref().ttl()
}
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
self.io.get_ref().set_ttl(ttl)
}
}
impl<M> fmt::Debug for TcpListener<M>
where
M: Mode,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.io.get_ref(), f)
}
}
#[cfg(unix)]
impl<M> AsFd for TcpListener<M>
where
M: Mode,
{
fn as_fd(&self) -> BorrowedFd<'_> {
self.io.get_ref().as_fd()
}
}
#[cfg(unix)]
impl<M> AsRawFd for TcpListener<M>
where
M: Mode,
{
fn as_raw_fd(&self) -> RawFd {
self.io.get_ref().as_raw_fd()
}
}
#[cfg(windows)]
impl<M> AsSocket for TcpListener<M>
where
M: Mode,
{
fn as_socket(&self) -> BorrowedSocket<'_> {
self.io.get_ref().as_socket()
}
}
#[cfg(windows)]
impl<M> AsRawSocket for TcpListener<M>
where
M: Mode,
{
fn as_raw_socket(&self) -> RawSocket {
self.io.get_ref().as_raw_socket()
}
}
pub struct TcpStream<M = Local>
where
M: Mode,
{
io: AsyncIo<std::net::TcpStream, M>,
write_shut: AtomicBool,
}
impl<M> TcpStream<M>
where
M: Mode,
{
pub async fn connect<A>(runtime: &Runtime<M>, addr: A) -> io::Result<Self>
where
A: Into<SocketAddr>,
{
let address = addr.into();
let io = connect::connect(
runtime,
Domain::for_address(address),
&SockAddr::from(address),
)
.await?;
Ok(Self {
io,
write_shut: AtomicBool::new(false),
})
}
pub fn from_std(runtime: &Runtime<M>, stream: std::net::TcpStream) -> io::Result<Self> {
stream.set_nonblocking(true)?;
set_nosigpipe(&stream)?;
Ok(Self {
io: AsyncIo::from_nonblocking(runtime, stream)?,
write_shut: AtomicBool::new(false),
})
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.io.get_ref().local_addr()
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.io.get_ref().peer_addr()
}
pub fn into_std(self) -> std::net::TcpStream {
self.io.into_inner()
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
if matches!(how, Shutdown::Write | Shutdown::Both) {
self.write_shut.store(true, Ordering::Relaxed);
}
self.io.get_ref().shutdown(how)
}
pub async fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
self.io.read_with(|stream| stream.peek(buf)).await
}
pub fn nodelay(&self) -> io::Result<bool> {
self.io.get_ref().nodelay()
}
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
self.io.get_ref().set_nodelay(nodelay)
}
pub fn ttl(&self) -> io::Result<u32> {
self.io.get_ref().ttl()
}
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
self.io.get_ref().set_ttl(ttl)
}
}
impl<M> AsyncRead for TcpStream<M>
where
M: Mode,
{
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut &*self).poll_read(cx, buf)
}
}
impl<M> AsyncWrite for TcpStream<M>
where
M: Mode,
{
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut &*self).poll_write(cx, buf)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut &*self).poll_flush(cx)
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut &*self).poll_close(cx)
}
}
impl<M> AsyncRead for &TcpStream<M>
where
M: Mode,
{
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
self.io.poll_read_with(cx, |mut stream| stream.read(buf))
}
}
impl<M> AsyncWrite for &TcpStream<M>
where
M: Mode,
{
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
self.io.poll_write_with(cx, |mut stream| stream.write(buf))
}
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
if self.write_shut.swap(true, Ordering::Relaxed) {
return Poll::Ready(Ok(()));
}
match self.io.get_ref().shutdown(Shutdown::Write) {
Err(e) if e.kind() == io::ErrorKind::NotConnected => Poll::Ready(Ok(())),
result => Poll::Ready(result),
}
}
}
impl<M> fmt::Debug for TcpStream<M>
where
M: Mode,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.io.get_ref(), f)
}
}
#[cfg(unix)]
impl<M> AsFd for TcpStream<M>
where
M: Mode,
{
fn as_fd(&self) -> BorrowedFd<'_> {
self.io.get_ref().as_fd()
}
}
#[cfg(unix)]
impl<M> AsRawFd for TcpStream<M>
where
M: Mode,
{
fn as_raw_fd(&self) -> RawFd {
self.io.get_ref().as_raw_fd()
}
}
#[cfg(windows)]
impl<M> AsSocket for TcpStream<M>
where
M: Mode,
{
fn as_socket(&self) -> BorrowedSocket<'_> {
self.io.get_ref().as_socket()
}
}
#[cfg(windows)]
impl<M> AsRawSocket for TcpStream<M>
where
M: Mode,
{
fn as_raw_socket(&self) -> RawSocket {
self.io.get_ref().as_raw_socket()
}
}
pub struct Incoming<'a, M = Local>
where
M: Mode,
{
listener: &'a TcpListener<M>,
}
impl<M> Stream for Incoming<'_, M>
where
M: Mode,
{
type Item = io::Result<TcpStream<M>>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.listener
.poll_accept(cx)
.map(|accepted| Some(accepted.map(|(stream, _address)| stream)))
}
}
impl<M> fmt::Debug for Incoming<'_, M>
where
M: Mode,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Incoming")
.field("listener", &self.listener)
.finish()
}
}
impl<M> TcpListener<M>
where
M: Mode,
{
fn poll_accept(&self, cx: &mut Context<'_>) -> Poll<io::Result<(TcpStream<M>, SocketAddr)>> {
let (stream, address) = ready!(self.io.poll_read_with(cx, |listener| listener.accept()))?;
Poll::Ready(self.accepted(stream, address))
}
fn accepted(
&self,
stream: std::net::TcpStream,
address: SocketAddr,
) -> io::Result<(TcpStream<M>, SocketAddr)> {
TcpStream::from_std(&self.io.runtime(), stream).map(|stream| (stream, address))
}
}