use std::{
os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd},
slice,
};
use libc::socklen_t;
use o3::{base::num::bounded, buffer, buffer::pool};
use crate::{
Errno,
io::{
fd,
socket::{Create, Domain, Kind, Setup, accept, msg},
},
kernel::{self, errno},
memory,
};
pub trait Receive {
fn recv<'a>(
&self,
output: buffer::raw::Output<'a>,
) -> Result<Option<pool::Complete<'a>>, Errno>;
unsafe fn receive<'a>(
&self,
output: buffer::raw::Output<'a>,
) -> Result<pool::Complete<'a>, 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(raw, || kernel::raw::Code::last::<Self>().into())
}
}
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::<E>(|| kernel::raw::Code::last::<Self>().into())
}?
.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::<E>(|| kernel::raw::Code::last::<Self>().into())
}?
.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) }
}
}