use std::{
os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd},
slice,
};
use libc::socklen_t;
use o3::{base::num::bounded, buffer};
use crate::{
Errno,
io::{
fd,
socket::{Create, Domain, Kind, Setup, accept, msg},
},
kernel::{self, errno},
memory,
};
pub trait Receive {
fn recv(&self, output: buffer::raw::Output<'_>) -> Result<Option<()>, Errno>;
unsafe fn receive(&self, output: buffer::raw::Output<'_>) -> Result<(), Errno>;
}
pub trait Open: AsFd + Sized {
fn open(domain: Domain, kind: Kind) -> Result<Self, Create>;
fn adopt(file: OwnedFd) -> Result<Self, Setup>;
unsafe fn accept(
&self,
addr: *mut libc::sockaddr_storage,
len: *mut socklen_t,
) -> Result<Self, accept::Error>;
}
pub trait Source: errno::Source {
unsafe fn accept<E: From<Errno>>(
file: BorrowedFd<'_>,
addr: *mut libc::sockaddr,
len: *mut socklen_t,
) -> Result<OwnedFd, E> {
let raw = unsafe { libc::accept(file.as_raw_fd(), addr, len) };
unsafe { <OwnedFd as fd::raw::Adopt>::try_adopt::<Self, E>(raw) }
}
unsafe fn send<X: memory::raw::Extent, E: From<Errno>>(
file: BorrowedFd<'_>,
ptr: *const u8,
len: X::Length,
) -> Result<X::Length, E> {
let len: bounded::U32<0, { i32::MAX as u32 }> = len.into();
let capacity = len.get() as usize;
let raw = unsafe { libc::send(file.as_raw_fd(), ptr.cast(), capacity, libc::MSG_NOSIGNAL) };
Ok(
unsafe { kernel::raw::Status::from_count(raw).try_count::<Self, E>() }?
.bounded()
.into(),
)
}
unsafe fn sendmsg<E: From<Errno>>(
file: BorrowedFd<'_>,
header: &msg::Header,
flags: libc::c_int,
) -> Result<bounded::U32<0, { i32::MAX as u32 }>, E> {
let raw = unsafe { libc::sendmsg(file.as_raw_fd(), header.as_raw(), flags) };
Ok(unsafe { kernel::raw::Status::from_count(raw).try_count::<Self, E>() }?.bounded())
}
}
impl<T: errno::Source> Source for T {}
pub trait Iovec {
unsafe fn as_slice<'a>(&self) -> &'a [u8];
}
impl Iovec for msg::Iovec {
unsafe fn as_slice<'a>(&self) -> &'a [u8] {
if self.is_empty() {
return &[];
}
unsafe { slice::from_raw_parts(self.0.iov_base.cast(), self.0.iov_len) }
}
}