use super::{const_buf, const_void, mut_buf, mut_void, AioFd, Fd, SocketAddr};
use crate::event::{POLLIN, POLLOUT};
use crate::{Error, Result};
use core::mem;
use core::time::Duration;
use hierr::set_errno;
pub const SHUT_RD: i32 = libc::SHUT_RD;
pub const SHUT_WR: i32 = libc::SHUT_WR;
pub const SHUT_RDWR: i32 = libc::SHUT_RDWR;
impl Fd {
pub fn socket(family: i32, ty: i32, proto: i32) -> Result<Self> {
let fd =
unsafe { libc::socket(family, ty | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC, proto) };
if fd >= 0 {
Ok(Self::new(fd))
} else {
Err(Error::last())
}
}
pub fn shutdown(&self, how: i32) -> Result<()> {
if unsafe { libc::shutdown(self.fd, how) } == 0 {
return Ok(());
}
Err(Error::last())
}
pub fn tcp_server(addr: &SocketAddr) -> Result<Self> {
let (addr, addrlen) = addr.get();
let fd = Self::socket(addr.sa_family.into(), libc::SOCK_STREAM, 0)?;
fd.tcp_server_config();
let ret = unsafe { libc::bind(fd.fd, addr, addrlen) };
if ret != 0 {
return Err(Error::last());
}
let ret = unsafe { libc::listen(fd.fd, libc::SOMAXCONN) };
if ret != 0 {
return Err(Error::last());
}
Ok(fd)
}
pub fn tcp_client(family: i32, addr: Option<&SocketAddr>) -> Result<Self> {
let fd = Self::socket(family, libc::SOCK_STREAM, 0)?;
if let Some(addr) = addr {
let (addr, addrlen) = addr.get();
let ret = unsafe { libc::bind(fd.fd, addr, addrlen) };
if ret != 0 {
return Err(Error::last());
}
}
Ok(fd)
}
pub fn try_connect(&self, addr: &SocketAddr) -> Result<()> {
loop {
let (addr, addrlen) = addr.get();
let ret = unsafe { libc::connect(self.fd, addr, addrlen) };
if ret == 0 {
return Ok(());
}
let err = Error::last();
if err.errno == libc::EINTR {
continue;
}
return Err(err);
}
}
pub fn set_linger(&self, time: Option<Duration>) {
let linger = if let Some(tm) = time {
libc::linger {
l_onoff: 1,
l_linger: tm.as_secs() as i32,
}
} else {
libc::linger {
l_onoff: 0,
l_linger: 0,
}
};
unsafe {
libc::setsockopt(
self.fd,
libc::SOL_SOCKET,
libc::SO_LINGER,
const_void(&linger),
mem::size_of_val(&linger) as u32,
);
}
}
pub fn getsockname(&self) -> Result<SocketAddr> {
let mut sockaddr = SocketAddr::uninit();
let (addr, mut addrlen) = sockaddr.get_uninit_mut();
let ret = unsafe { libc::getsockname(self.fd, addr, &mut addrlen) };
if ret == 0 {
return Ok(sockaddr);
}
Err(Error::last())
}
pub fn getpeername(&self) -> Result<SocketAddr> {
let mut sockaddr = SocketAddr::uninit();
let (addr, mut addrlen) = sockaddr.get_uninit_mut();
let ret = unsafe { libc::getpeername(self.fd, addr, &mut addrlen) };
if ret == 0 {
return Ok(sockaddr);
}
Err(Error::last())
}
pub fn try_sendto(&self, buf: &[u8], flags: i32, dst: &SocketAddr) -> Result<usize> {
let flags = flags | libc::MSG_DONTWAIT;
let (addr, addrlen) = dst.get();
let ret = unsafe { libc::sendto(self.fd, const_buf(buf), buf.len(), flags, addr, addrlen) };
if ret >= 0 {
return Ok(ret as usize);
}
Err(Error::last())
}
pub fn try_recvfrom(&self, buf: &mut [u8], flags: i32) -> Result<(usize, SocketAddr)> {
let flags = flags | libc::MSG_DONTWAIT;
let mut sockaddr = SocketAddr::uninit();
let (addr, mut addrlen) = sockaddr.get_uninit_mut();
let ret =
unsafe { libc::recvfrom(self.fd, mut_buf(buf), buf.len(), flags, addr, &mut addrlen) };
if ret >= 0 {
return Ok((ret as usize, sockaddr));
}
Err(Error::last())
}
fn tcp_server_config(&self) {
let val = 1_i32;
unsafe {
libc::setsockopt(
self.fd,
libc::SOL_SOCKET,
libc::SO_REUSEADDR,
const_void(&val),
mem::size_of_val(&val) as u32,
);
}
}
fn tcp_connection_config(&self) {}
}
impl AioFd<'_> {
pub async fn accept(&mut self) -> Result<(Fd, SocketAddr)> {
let mut peer_addr = SocketAddr::uninit();
loop {
{
let (addr, mut addrlen) = peer_addr.get_uninit_mut();
let ret = unsafe {
libc::accept4(
self.fd.fd,
addr,
&mut addrlen,
libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC,
)
};
if ret >= 0 {
let conn = Fd::new(ret);
conn.tcp_connection_config();
return Ok((conn, peer_addr));
}
}
let err = Error::last();
match err.errno {
libc::EINTR => continue,
libc::EAGAIN => {
self.wait(POLLIN).await?;
continue;
}
_ => return Err(err),
}
}
}
pub async fn connect(&mut self, addr: &SocketAddr) -> Result<()> {
let (addr, addrlen) = addr.get();
loop {
let ret = unsafe { libc::connect(self.fd.fd, addr, addrlen) };
if ret == 0 {
return Ok(());
}
let e = Error::last();
if e.errno == libc::EINPROGRESS || e.errno == libc::EALREADY {
self.wait(POLLOUT).await?;
let mut val: i32 = 0;
let mut len = mem::size_of_val(&val) as u32;
let ret = unsafe {
libc::getsockopt(
self.fd.fd,
libc::SOL_SOCKET,
libc::SO_ERROR,
mut_void(&mut val),
&mut len,
)
};
if ret == 0 {
if val == 0 {
return Ok(());
}
set_errno(val);
return Err(Error::new(val));
}
return Err(Error::last());
}
}
}
}