use std::{
io,
mem::MaybeUninit,
net::{Shutdown, SocketAddr},
time::Duration,
};
pub use crate::addr::{lookup_host, ToAddrs};
mod sock;
mod udp;
#[cfg(all(unix, not(nexio_runtime_fallback)))]
#[path = "../unix.rs"]
pub mod unix;
#[cfg(unix)]
use sock::raw;
use sock::{is_in_progress, socket_addr, Io};
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
pub use udp::UdpSocket;
#[cfg(all(unix, not(nexio_runtime_fallback)))]
pub use unix::{UnixDatagram, UnixListener, UnixStream};
use crate::buf::{BufResult, IoBuf, IoBufMut};
pub struct TcpListener {
io: Io,
}
impl TcpListener {
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(l) => return Ok(l),
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::STREAM, Some(Protocol::TCP))?;
#[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))?;
sock.listen(crate::profile::HardwareProfile::get().listen_backlog())?;
Ok(Self { io: Io::new(sock)? })
}
pub fn from_std(listener: std::net::TcpListener) -> io::Result<Self> {
Ok(Self {
io: Io::new(Socket::from(listener))?,
})
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
socket_addr(self.io.sock.local_addr()?)
}
pub async fn accept(&self) -> io::Result<TcpStream> {
Ok(self.accept_addr().await?.0)
}
pub async fn accept_addr(&self) -> io::Result<(TcpStream, SocketAddr)> {
loop {
match self.io.sock.accept() {
Ok((sock, peer)) => {
return Ok((TcpStream { io: Io::new(sock)? }, socket_addr(peer)?));
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => self.io.ready(false).await?,
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
}
pub fn try_accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
let (sock, peer) = self.io.sock.accept()?;
Ok((TcpStream { io: Io::new(sock)? }, socket_addr(peer)?))
}
pub fn set_reuseaddr(&self, reuse: bool) -> io::Result<()> {
self.io.sock.set_reuse_address(reuse)
}
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, reuse: bool) -> io::Result<()> {
self.io.sock.set_reuse_port(reuse)
}
#[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 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)
}
}
pub struct TcpStream {
io: Io,
}
impl TcpStream {
pub async fn connect(addr: impl crate::addr::ToAddrs) -> io::Result<Self> {
let mut last = None;
for sa in crate::addr::lookup_host(addr).await? {
match Self::connect_addr(sa).await {
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 async fn connect_addr(addr: SocketAddr) -> io::Result<Self> {
let sock = Socket::new(Domain::for_address(addr), Type::STREAM, Some(Protocol::TCP))?;
let io = Io::new(sock)?;
match io.sock.connect(&SockAddr::from(addr)) {
Ok(()) => {}
Err(e) if is_in_progress(&e) => loop {
io.ready(true).await?;
if let Some(e) = io.sock.take_error()? {
return Err(e);
}
match io.sock.peer_addr() {
Ok(_) => break,
Err(e) if e.kind() == io::ErrorKind::NotConnected => {}
Err(e) => return Err(e),
}
},
Err(e) => return Err(e),
}
Ok(Self { io })
}
pub fn from_std(stream: std::net::TcpStream) -> io::Result<Self> {
Ok(Self {
io: Io::new(Socket::from(stream))?,
})
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
socket_addr(self.io.sock.peer_addr()?)
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
socket_addr(self.io.sock.local_addr()?)
}
pub async fn read<B>(&self, mut buf: B) -> BufResult<usize, B>
where
B: IoBufMut + Send + 'static,
{
loop {
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) };
return (Ok(n), buf);
}
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 => {}
Err(e) => return (Err(e), buf),
}
}
}
pub async fn read_exact<B>(&self, mut buf: B) -> BufResult<(), B>
where
B: IoBufMut + Send + 'static,
{
let total = buf.bytes_total();
let mut got = 0usize;
while got < total {
let base = buf.stable_ptr_mut();
let ptr = unsafe { base.add(got) } as *mut MaybeUninit<u8>;
let spare = unsafe { std::slice::from_raw_parts_mut(ptr, total - got) };
match self.io.sock.recv(spare) {
Ok(0) => {
let e =
io::Error::new(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer");
return (Err(e), buf);
}
Ok(n) => got += n,
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 => {}
Err(e) => return (Err(e), buf),
}
}
unsafe { buf.set_init(total) };
(Ok(()), buf)
}
pub async fn write<B>(&self, buf: B) -> BufResult<usize, B>
where
B: IoBuf + Send + 'static,
{
loop {
let data = unsafe { std::slice::from_raw_parts(buf.stable_ptr(), buf.bytes_init()) };
match self.io.send_nosig(data) {
Ok(n) => return (Ok(n), 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 => {}
Err(e) => return (Err(e), buf),
}
}
}
pub async fn write_all<B>(&self, buf: B) -> BufResult<(), B>
where
B: IoBuf + Send + 'static,
{
let total = buf.bytes_init();
let mut sent = 0usize;
while sent < total {
let data =
unsafe { std::slice::from_raw_parts(buf.stable_ptr().add(sent), total - sent) };
match self.io.send_nosig(data) {
Ok(0) => {
let e =
io::Error::new(io::ErrorKind::WriteZero, "failed to write whole buffer");
return (Err(e), buf);
}
Ok(n) => sent += n,
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 => {}
Err(e) => return (Err(e), buf),
}
}
(Ok(()), buf)
}
pub async fn read_vectored<B>(&self, mut bufs: Vec<B>) -> BufResult<usize, Vec<B>>
where
B: IoBufMut + Send + 'static,
{
if bufs.is_empty() {
return (Ok(0), bufs);
}
loop {
let mut slices: Vec<std::io::IoSliceMut<'_>> = bufs
.iter_mut()
.map(|b| {
let slice = unsafe {
std::slice::from_raw_parts_mut(b.stable_ptr_mut(), b.bytes_total())
};
std::io::IoSliceMut::new(slice)
})
.collect();
let res = {
use std::io::Read;
(&self.io.sock).read_vectored(&mut slices)
};
drop(slices);
match res {
Ok(n) => {
let mut rem = n;
for b in &mut bufs {
let take = rem.min(b.bytes_total());
unsafe { b.set_init(take) };
rem -= take;
if rem == 0 {
break;
}
}
return (Ok(n), bufs);
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
if let Err(e) = self.io.ready(false).await {
return (Err(e), bufs);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return (Err(e), bufs),
}
}
}
pub async fn write_vectored<B>(&self, bufs: Vec<B>) -> BufResult<usize, Vec<B>>
where
B: IoBuf + Send + 'static,
{
if bufs.is_empty() {
return (Ok(0), bufs);
}
loop {
let slices: Vec<std::io::IoSlice<'_>> = bufs
.iter()
.map(|b| {
let slice =
unsafe { std::slice::from_raw_parts(b.stable_ptr(), b.bytes_init()) };
std::io::IoSlice::new(slice)
})
.collect();
let res = {
use std::io::Write;
(&self.io.sock).write_vectored(&slices)
};
drop(slices);
match res {
Ok(n) => return (Ok(n), bufs),
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
if let Err(e) = self.io.ready(true).await {
return (Err(e), bufs);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return (Err(e), bufs),
}
}
}
pub async fn write_all_vectored<B>(&self, bufs: Vec<B>) -> BufResult<(), Vec<B>>
where
B: IoBuf + Send + 'static,
{
let mut idx = 0usize;
let mut off = 0usize;
while idx < bufs.len() {
let init_len = bufs[idx].bytes_init();
if off >= init_len {
idx += 1;
off = 0;
continue;
}
let res = {
let slices: Vec<std::io::IoSlice<'_>> = bufs[idx..]
.iter()
.enumerate()
.map(|(i, b)| {
let skip = if i == 0 { off } else { 0 };
let len = b.bytes_init().saturating_sub(skip);
let slice = if len == 0 {
&[]
} else {
unsafe { std::slice::from_raw_parts(b.stable_ptr().add(skip), len) }
};
std::io::IoSlice::new(slice)
})
.collect();
use std::io::Write;
(&self.io.sock).write_vectored(&slices)
};
match res {
Ok(0) => {
return (
Err(io::Error::new(
io::ErrorKind::WriteZero,
"failed to write whole vectored buffer",
)),
bufs,
);
}
Ok(mut n) => {
while n > 0 && idx < bufs.len() {
let rem = bufs[idx].bytes_init().saturating_sub(off);
if n >= rem {
n -= rem;
idx += 1;
off = 0;
} else {
off += n;
n = 0;
}
}
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
if let Err(e) = self.io.ready(true).await {
return (Err(e), bufs);
}
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return (Err(e), bufs),
}
}
(Ok(()), bufs)
}
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
self.io.sock.shutdown(how)
}
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
self.io.sock.set_nodelay(nodelay)
}
pub fn nodelay(&self) -> io::Result<bool> {
self.io.sock.nodelay()
}
pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> {
self.io.sock.set_keepalive(keepalive)
}
pub fn keepalive(&self) -> io::Result<bool> {
self.io.sock.keepalive()
}
pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> {
self.io.sock.set_linger(dur)
}
pub fn linger(&self) -> io::Result<Option<Duration>> {
self.io.sock.linger()
}
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 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 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)
}
}
define_stream_split!(TcpStream);