use std::{io, net::Shutdown};
use socket2::{Protocol, SockAddr, Type};
#[cfg(feature = "runtime")]
use crate::{
buf::{IoBuf, IoBufMut, VectoredBufWrapper},
BufResult,
};
use crate::{
impl_raw_fd,
net::{Socket, ToSockAddrs},
};
pub struct TcpListener {
inner: Socket,
}
impl TcpListener {
pub fn bind(addr: impl ToSockAddrs) -> io::Result<Self> {
super::each_addr(addr, |addr| {
let socket = Socket::bind(&addr, Type::STREAM, Some(Protocol::TCP))?;
socket.listen(128)?;
Ok(Self { inner: socket })
})
}
pub fn try_clone(&self) -> io::Result<Self> {
Ok(Self {
inner: self.inner.try_clone()?,
})
}
#[cfg(feature = "runtime")]
pub async fn accept(&self) -> io::Result<(TcpStream, SockAddr)> {
let (socket, addr) = self.inner.accept().await?;
let stream = TcpStream { inner: socket };
Ok((stream, addr))
}
pub fn local_addr(&self) -> io::Result<SockAddr> {
self.inner.local_addr()
}
}
impl_raw_fd!(TcpListener, inner);
pub struct TcpStream {
inner: Socket,
}
impl TcpStream {
#[cfg(feature = "runtime")]
pub async fn connect(addr: impl ToSockAddrs) -> io::Result<Self> {
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
super::each_addr_async(addr, |addr| async move {
let socket = if cfg!(target_os = "windows") {
let bind_addr = if addr.is_ipv4() {
SockAddr::from(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0))
} else if addr.is_ipv6() {
SockAddr::from(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0))
} else {
return Err(io::Error::new(
io::ErrorKind::AddrNotAvailable,
"Unsupported address domain.",
));
};
Socket::bind(&bind_addr, Type::STREAM, Some(Protocol::TCP))?
} else {
Socket::new(addr.domain(), Type::STREAM, Some(Protocol::TCP))?
};
socket.connect_async(&addr).await?;
Ok(Self { inner: socket })
})
.await
}
pub fn try_clone(&self) -> io::Result<Self> {
Ok(Self {
inner: self.inner.try_clone()?,
})
}
pub fn peer_addr(&self) -> io::Result<SockAddr> {
self.inner.peer_addr()
}
pub fn local_addr(&self) -> io::Result<SockAddr> {
self.inner.local_addr()
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
self.inner.shutdown(how)
}
#[cfg(feature = "runtime")]
pub async fn recv<T: IoBufMut<'static>>(&self, buffer: T) -> BufResult<usize, T> {
self.inner.recv(buffer).await
}
#[cfg(feature = "runtime")]
pub async fn recv_exact<T: IoBufMut<'static>>(&self, buffer: T) -> BufResult<usize, T> {
self.inner.recv_exact(buffer).await
}
#[cfg(feature = "runtime")]
pub async fn recv_vectored<T: IoBufMut<'static>>(
&self,
buffer: VectoredBufWrapper<'static, T>,
) -> BufResult<usize, VectoredBufWrapper<'static, T>> {
self.inner.recv_vectored(buffer).await
}
#[cfg(feature = "runtime")]
pub async fn send<T: IoBuf<'static>>(&self, buffer: T) -> BufResult<usize, T> {
self.inner.send(buffer).await
}
#[cfg(feature = "runtime")]
pub async fn send_all<T: IoBuf<'static>>(&self, buffer: T) -> BufResult<usize, T> {
self.inner.send_all(buffer).await
}
#[cfg(feature = "runtime")]
pub async fn send_vectored<T: IoBuf<'static>>(
&self,
buffer: VectoredBufWrapper<'static, T>,
) -> BufResult<usize, VectoredBufWrapper<'static, T>> {
self.inner.send_vectored(buffer).await
}
}
impl_raw_fd!(TcpStream, inner);