abi: file options, remove NonBlocking socket option

This commit is contained in:
Mark Poliakov 2025-01-10 15:40:58 +02:00
parent ed9bbea189
commit 2e3af98822
22 changed files with 453 additions and 344 deletions

View File

@ -14,9 +14,12 @@ use libk::{
};
use libk_mm::PageBox;
use libk_util::{queue::BoundedMpmcQueue, sync::spin_rwlock::IrqSafeRwLock};
use yggdrasil_abi::net::{
options::{self, RawSocketOptionVariant, SocketOption},
SocketAddr, SocketInterfaceQuery,
use yggdrasil_abi::{
net::{
options::{self, RawSocketOptionVariant},
SocketAddr, SocketInterfaceQuery,
},
option::OptionValue,
};
use crate::{ethernet::L2Packet, interface::NetworkInterface};

View File

@ -14,9 +14,12 @@ use libk::{
vfs::{ConnectionSocket, FileReadiness, Socket},
};
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
use yggdrasil_abi::net::{
options::{self, SocketOption, TcpSocketOptionVariant},
SocketAddr,
use yggdrasil_abi::{
net::{
options::{self, TcpSocketOptionVariant},
SocketAddr,
},
option::OptionValue,
};
mod listener;

View File

@ -16,9 +16,12 @@ use libk_util::{
queue::BoundedMpmcQueue,
sync::spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockReadGuard},
};
use yggdrasil_abi::net::{
options::{self, SocketOption, UdpSocketOptionVariant},
IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr,
use yggdrasil_abi::{
net::{
options::{self, UdpSocketOptionVariant},
IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr,
},
option::OptionValue,
};
use crate::l4;

View File

@ -1,5 +1,3 @@
use core::sync::atomic::{AtomicBool, Ordering};
use libk_util::sync::IrqSafeSpinlock;
use yggdrasil_abi::{error::Error, io::SeekFrom};
@ -8,11 +6,6 @@ use crate::{
vfs::{CommonImpl, NodeRef},
};
// use crate::vfs::{
// device::{BlockDeviceWrapper, CharDeviceWrapper},
// node::NodeRef,
// };
pub struct BlockFile {
pub(super) device: BlockDeviceFile,
pub(super) node: NodeRef,
@ -21,12 +14,12 @@ pub struct BlockFile {
pub(super) write: bool,
}
#[derive(Clone)]
pub struct CharFile {
pub(super) device: CharDeviceFile,
pub(super) node: NodeRef,
pub(super) read: bool,
pub(super) write: bool,
pub(super) blocking: AtomicBool,
}
impl BlockFile {
@ -82,27 +75,27 @@ impl BlockFile {
}
impl CharFile {
pub fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
pub fn read(&self, buf: &mut [u8], non_blocking: bool) -> Result<usize, Error> {
if !self.read {
return Err(Error::InvalidOperation);
}
if self.blocking.load(Ordering::Acquire) {
block!(self.device.0.read(buf).await)?
} else {
if non_blocking {
self.device.0.read_nonblocking(buf)
} else {
block!(self.device.0.read(buf).await)?
}
}
pub fn write(&self, buf: &[u8]) -> Result<usize, Error> {
pub fn write(&self, buf: &[u8], non_blocking: bool) -> Result<usize, Error> {
if !self.write {
return Err(Error::InvalidOperation);
}
if self.blocking.load(Ordering::Acquire) {
block!(self.device.0.write(buf).await)?
} else {
if non_blocking {
self.device.0.write_nonblocking(buf)
} else {
block!(self.device.0.write(buf).await)?
}
}

View File

@ -2,7 +2,6 @@ use core::{
any::Any,
fmt,
mem::MaybeUninit,
sync::atomic::{AtomicBool, Ordering},
task::{Context, Poll},
};
@ -16,14 +15,16 @@ use device::{BlockFile, CharFile};
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider};
use libk_util::{
io::{ReadAt, WriteAt},
sync::IrqSafeSpinlock,
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
};
use yggdrasil_abi::{
error::Error,
io::{
DeviceRequest, DirectoryEntry, FileMode, OpenOptions, PipeOptions, RawFd, SeekFrom,
TerminalOptions, TerminalSize, TimerOptions,
options::{self, FileOptionVariant},
DeviceRequest, DirectoryEntry, FileMode, OpenOptions, RawFd, SeekFrom, TerminalOptions,
TerminalSize, TimerOptions,
},
option::OptionValue,
process::{ProcessWait, WaitFlags},
};
@ -78,16 +79,23 @@ pub enum DirectoryOpenPosition {
/// Wrapper type for a [File] shared reference
pub type FileRef = Arc<File>;
// TODO some kind of a mutex instead?
/// Describes an open file
#[allow(missing_docs)]
pub enum File {
#[derive(Clone)]
struct FileOptions {
non_blocking: bool,
}
pub struct File {
options: IrqSafeRwLock<FileOptions>,
inner: FileInner,
}
enum FileInner {
Directory(DirectoryFile),
Regular(RegularFile),
Block(BlockFile),
Char(CharFile),
Socket(SocketWrapper),
AnonymousPipe(PipeEnd, AtomicBool),
AnonymousPipe(PipeEnd),
Poll(FdPoll),
Timer(TimerFile),
Channel(ChannelDescriptor),
@ -106,8 +114,8 @@ pub trait TerminalHalf {
fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error>;
}
#[derive(Clone)]
pub struct TerminalHalfWrapper<T: TerminalHalf> {
blocking: AtomicBool,
half: Arc<T>,
node: NodeRef,
}
@ -118,36 +126,38 @@ pub struct FileSet {
}
impl File {
fn from_inner(inner: FileInner) -> Arc<Self> {
Arc::new(Self {
options: IrqSafeRwLock::new(FileOptions {
non_blocking: false,
}),
inner,
})
}
/// Constructs a pipe pair, returning its `(read, write)` ends
pub fn new_pipe_pair(capacity: usize, options: PipeOptions) -> (Arc<Self>, Arc<Self>) {
pub fn new_pipe_pair(capacity: usize) -> (Arc<Self>, Arc<Self>) {
let (read, write) = PipeEnd::new_pair(capacity);
(
Arc::new(Self::AnonymousPipe(
read,
AtomicBool::new(options.contains(PipeOptions::READ_NONBLOCKING)),
)),
Arc::new(Self::AnonymousPipe(
write,
AtomicBool::new(options.contains(PipeOptions::WRITE_NONBLOCKING)),
)),
)
let read = FileInner::AnonymousPipe(read);
let write = FileInner::AnonymousPipe(write);
(Self::from_inner(read), Self::from_inner(write))
}
/// Constructs a new poll channel file
pub fn new_poll_channel() -> Arc<Self> {
Arc::new(Self::Poll(FdPoll::new()))
Self::from_inner(FileInner::Poll(FdPoll::new()))
}
/// Opens a new message channel, optionally subscribing to it as well
pub fn new_message_channel(name: &str, with_sub: bool) -> Arc<Self> {
let channel = ChannelDescriptor::open(name, with_sub);
Arc::new(Self::Channel(channel))
Self::from_inner(FileInner::Channel(channel))
}
/// Creates a buffer of shared memory and associates a [File] with it
pub fn new_shared_memory(size: usize) -> Result<Arc<Self>, Error> {
let shm = SharedMemory::new(size)?;
Ok(Arc::new(Self::SharedMemory(Arc::new(shm))))
Ok(Self::from_inner(FileInner::SharedMemory(Arc::new(shm))))
}
/// Creates a pair of PTY master/slave
@ -160,41 +170,34 @@ impl File {
let slave = Arc::new(slave);
let (master_node, slave_node) =
Node::pseudo_terminal_nodes(&master, &slave, Metadata::now_root(FileMode::new(0o644)));
Ok((
Arc::new(Self::PtyMaster(TerminalHalfWrapper {
blocking: AtomicBool::new(true),
half: master,
node: master_node,
})),
Arc::new(Self::PtySlave(TerminalHalfWrapper {
blocking: AtomicBool::new(true),
half: slave,
node: slave_node,
})),
))
let master = Self::from_inner(FileInner::PtyMaster(TerminalHalfWrapper {
half: master,
node: master_node,
}));
let slave = Self::from_inner(FileInner::PtySlave(TerminalHalfWrapper {
half: slave,
node: slave_node,
}));
Ok((master, slave))
}
pub fn open_pty_master(pty: Arc<PseudoTerminalMaster>, node: Arc<Node>) -> Arc<Self> {
Arc::new(Self::PtyMaster(TerminalHalfWrapper {
blocking: AtomicBool::new(true),
Self::from_inner(FileInner::PtyMaster(TerminalHalfWrapper {
half: pty,
node,
}))
}
pub fn open_pty_slave(pty: Arc<PseudoTerminalSlave>, node: Arc<Node>) -> Arc<Self> {
Arc::new(Self::PtySlave(TerminalHalfWrapper {
blocking: AtomicBool::new(true),
half: pty,
node,
}))
Self::from_inner(FileInner::PtySlave(TerminalHalfWrapper { half: pty, node }))
}
/// Creates a new [TimerFile]-backed File
pub fn new_timer(options: TimerOptions) -> FileRef {
let repeat = options.contains(TimerOptions::REPEAT);
let blocking = !options.contains(TimerOptions::NON_BLOCKING);
Arc::new(Self::Timer(TimerFile::new(repeat, blocking)))
let timer = TimerFile::new(repeat);
Self::from_inner(FileInner::Timer(timer))
}
/// Creates a new [PidFile]-backed file
@ -204,18 +207,18 @@ impl File {
flags: WaitFlags,
) -> Result<FileRef, Error> {
PidFile::new(parent, wait, flags)
.map(Self::Pid)
.map(Arc::new)
.map(FileInner::Pid)
.map(Self::from_inner)
}
/// Constructs a [File] from a [PacketSocket], [ConnectionSocket] or a [ListenerSocket].
pub fn from_socket<S: Into<SocketWrapper>>(socket: S) -> Arc<Self> {
Arc::new(Self::Socket(socket.into()))
Self::from_inner(FileInner::Socket(socket.into()))
}
pub(crate) fn directory(node: NodeRef, position: DirectoryOpenPosition) -> Arc<Self> {
let position = IrqSafeSpinlock::new(position.into());
Arc::new(Self::Directory(DirectoryFile { node, position }))
Self::from_inner(FileInner::Directory(DirectoryFile { node, position }))
}
pub(crate) fn regular(
@ -227,7 +230,7 @@ impl File {
let read = opts.contains(OpenOptions::READ);
let write = opts.contains(OpenOptions::WRITE);
Arc::new(Self::Regular(RegularFile {
Self::from_inner(FileInner::Regular(RegularFile {
node,
read,
write,
@ -251,7 +254,7 @@ impl File {
return Err(Error::ReadOnly);
}
Ok(Arc::new(Self::Block(BlockFile {
Ok(Self::from_inner(FileInner::Block(BlockFile {
device,
node,
position: IrqSafeSpinlock::new(0),
@ -275,67 +278,81 @@ impl File {
return Err(Error::ReadOnly);
}
Ok(Arc::new(Self::Char(CharFile {
Ok(Self::from_inner(FileInner::Char(CharFile {
device,
node,
read,
write,
blocking: AtomicBool::new(true),
})))
}
pub fn is_non_blocking(&self) -> bool {
self.options.read().non_blocking
}
/// Clones an open file for sending it to another process
pub fn send(self: &Arc<Self>) -> Result<Arc<Self>, Error> {
match self.as_ref() {
Self::Char(_) => Ok(self.clone()),
Self::Block(_) => todo!(),
Self::Regular(file) => Ok(Arc::new(Self::Regular(file.clone()))),
Self::SharedMemory(shm) => Ok(Arc::new(Self::SharedMemory(shm.clone()))),
Self::Pid(pid) => Ok(Arc::new(Self::Pid(pid.clone()))),
let options = self.options.read().clone();
Ok(Arc::new(Self {
inner: self.inner.send()?,
options: IrqSafeRwLock::new(options),
}))
}
Self::PtySlave(half) => Ok(Arc::new(Self::PtySlave(half.clone()))),
Self::PtyMaster(half) => Ok(Arc::new(Self::PtyMaster(half.clone()))),
pub fn set_option(&self, option: u32, buffer: &[u8]) -> Result<(), Error> {
let option = FileOptionVariant::try_from(option)?;
let mut options = self.options.write();
match option {
FileOptionVariant::NonBlocking => {
options.non_blocking = options::NonBlocking::load(buffer)?;
Ok(())
}
}
}
_ => {
log::info!("Invalid file send(): {:?}", self);
Err(Error::InvalidOperation)
pub fn get_option(&self, option: u32, buffer: &mut [u8]) -> Result<usize, Error> {
let option = FileOptionVariant::try_from(option)?;
let options = self.options.read();
match option {
FileOptionVariant::NonBlocking => {
options::NonBlocking::store(&options.non_blocking, buffer)
}
}
}
/// Reads entries from the directory
pub fn read_dir(&self, entries: &mut [MaybeUninit<DirectoryEntry>]) -> Result<usize, Error> {
match self {
Self::Directory(dir) => dir.read_entries(entries),
match &self.inner {
FileInner::Directory(dir) => dir.read_entries(entries),
_ => Err(Error::NotADirectory),
}
}
/// Returns the underlying [Node] the file contains
pub fn node(&self) -> Option<&NodeRef> {
match self {
Self::Directory(file) => Some(&file.node),
Self::Regular(file) => Some(&file.node),
Self::Block(file) => Some(&file.node),
Self::Char(file) => Some(&file.node),
Self::PtyMaster(half) => Some(&half.node),
Self::PtySlave(half) => Some(&half.node),
match &self.inner {
FileInner::Directory(file) => Some(&file.node),
FileInner::Regular(file) => Some(&file.node),
FileInner::Block(file) => Some(&file.node),
FileInner::Char(file) => Some(&file.node),
FileInner::PtyMaster(half) => Some(&half.node),
FileInner::PtySlave(half) => Some(&half.node),
_ => None,
}
}
/// Polls a file for "read-readiness"
pub fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
match self {
Self::Char(f) => f.device.poll_read(cx),
Self::Channel(ch) => ch.poll_read(cx),
Self::Poll(ch) => ch.poll_read(cx),
Self::PtyMaster(half) => half.half.poll_read(cx),
Self::PtySlave(half) => half.half.poll_read(cx),
Self::Socket(socket) => socket.poll_read(cx),
Self::Timer(timer) => timer.poll_read(cx),
Self::Pid(pid) => pid.poll_read(cx),
Self::AnonymousPipe(pipe, _) => pipe.poll_read(cx),
match &self.inner {
FileInner::Char(f) => f.device.poll_read(cx),
FileInner::Channel(ch) => ch.poll_read(cx),
FileInner::Poll(ch) => ch.poll_read(cx),
FileInner::PtyMaster(half) => half.half.poll_read(cx),
FileInner::PtySlave(half) => half.half.poll_read(cx),
FileInner::Socket(socket) => socket.poll_read(cx),
FileInner::Timer(timer) => timer.poll_read(cx),
FileInner::Pid(pid) => pid.poll_read(cx),
FileInner::AnonymousPipe(pipe) => pipe.poll_read(cx),
// Polling not implemented, return ready immediately (XXX ?)
_ => Poll::Ready(Err(Error::NotImplemented)),
}
@ -348,18 +365,18 @@ impl File {
return Ok(());
}
match self {
Self::Char(f) => f.device.device_request(req),
Self::Block(f) => f.device.device_request(req),
Self::PtySlave(half) => half.half.device_request(req),
Self::PtyMaster(half) => half.half.device_request(req),
match &self.inner {
FileInner::Char(f) => f.device.device_request(req),
FileInner::Block(f) => f.device.device_request(req),
FileInner::PtySlave(half) => half.half.device_request(req),
FileInner::PtyMaster(half) => half.half.device_request(req),
_ => Err(Error::InvalidOperation),
}
}
/// Interprets the file as a poll channel
pub fn as_poll_channel(&self) -> Result<&FdPoll, Error> {
if let Self::Poll(poll) = self {
if let FileInner::Poll(poll) = &self.inner {
Ok(poll)
} else {
Err(Error::InvalidOperation)
@ -368,7 +385,7 @@ impl File {
/// Interprets the file as a message channel
pub fn as_message_channel(&self) -> Result<&ChannelDescriptor, Error> {
if let Self::Channel(ch) = self {
if let FileInner::Channel(ch) = &self.inner {
Ok(ch)
} else {
Err(Error::InvalidOperation)
@ -377,16 +394,16 @@ impl File {
/// Interprets the file as a socket
pub fn as_socket(&self) -> Result<&SocketWrapper, Error> {
match self {
Self::Socket(socket) => Ok(socket),
match &self.inner {
FileInner::Socket(socket) => Ok(socket),
_ => Err(Error::InvalidOperation),
}
}
pub fn is_terminal(&self) -> bool {
match self {
Self::Char(dev) => dev.is_terminal(),
Self::PtySlave(_) | Self::PtyMaster(_) => true,
match &self.inner {
FileInner::Char(dev) => dev.is_terminal(),
FileInner::PtySlave(_) | FileInner::PtyMaster(_) => true,
_ => false,
}
}
@ -394,17 +411,17 @@ impl File {
impl PageProvider for File {
fn get_page(&self, offset: u64) -> Result<PhysicalAddress, Error> {
match self {
Self::Block(f) => f.device.get_page(offset),
Self::SharedMemory(f) => f.get_page(offset),
match &self.inner {
FileInner::Block(f) => f.device.get_page(offset),
FileInner::SharedMemory(f) => f.get_page(offset),
_ => Err(Error::InvalidOperation),
}
}
fn release_page(&self, offset: u64, phys: PhysicalAddress) -> Result<(), Error> {
match self {
Self::Block(f) => f.device.release_page(offset, phys),
Self::SharedMemory(f) => f.release_page(offset, phys),
match &self.inner {
FileInner::Block(f) => f.device.release_page(offset, phys),
FileInner::SharedMemory(f) => f.release_page(offset, phys),
_ => Err(Error::InvalidOperation),
}
}
@ -421,57 +438,55 @@ impl PageProvider for File {
impl Read for File {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
match self {
Self::Regular(file) => file.read(buf),
Self::Block(file) => file.read(buf),
Self::Char(file) => file.read(buf),
Self::AnonymousPipe(pipe, nonblocking) => {
pipe.read(buf, nonblocking.load(Ordering::Acquire))
let non_blocking = self.options.read().non_blocking;
match &self.inner {
FileInner::Regular(file) => file.read(buf),
FileInner::Block(file) => file.read(buf),
FileInner::Char(file) => file.read(buf, non_blocking),
FileInner::AnonymousPipe(pipe) => pipe.read(buf, non_blocking),
FileInner::PtySlave(half) => half.read(buf, non_blocking),
FileInner::PtyMaster(half) => half.read(buf, non_blocking),
FileInner::Timer(timer) => timer.read(buf, non_blocking),
FileInner::Pid(pid) => pid.read(buf, non_blocking),
// TODO allow reads from sockets
FileInner::Socket(socket) => {
let (len, _) = socket.receive_from(buf, non_blocking)?;
Ok(len)
}
Self::PtySlave(half) => half.read(buf),
Self::PtyMaster(half) => half.read(buf),
Self::Timer(timer) => timer.read(buf),
Self::Pid(pid) => pid.read(buf),
// TODO maybe allow reading FDs from poll channels as if they were regular streams?
Self::Poll(_) => Err(Error::InvalidOperation),
// TODO maybe allow reading messages from Channels?
Self::Channel(_) => Err(Error::InvalidOperation),
Self::SharedMemory(_) => Err(Error::InvalidOperation),
// TODO maybe allow reading messages from Packet/Stream sockets?
Self::Socket(_) => Err(Error::InvalidOperation),
Self::Directory(_) => Err(Error::IsADirectory),
FileInner::Directory(_)
| FileInner::Poll(_)
| FileInner::SharedMemory(_)
| FileInner::Channel(_) => Err(Error::InvalidOperation),
}
}
}
impl Write for File {
fn write(&self, buf: &[u8]) -> Result<usize, Error> {
match self {
Self::Regular(file) => file.write(buf),
Self::Block(file) => file.write(buf),
Self::Char(file) => file.write(buf),
Self::AnonymousPipe(pipe, _) => pipe.write(buf),
Self::PtySlave(half) => half.write(buf),
Self::PtyMaster(half) => half.write(buf),
Self::Timer(timer) => timer.write(buf),
// TODO allow sending signals via writes to PID FDs?
Self::Pid(_) => Err(Error::InvalidOperation),
// TODO maybe allow adding FDs to poll channels this way
Self::Poll(_) => Err(Error::InvalidOperation),
// TODO maybe allow writing messages to Channels?
Self::Channel(_) => Err(Error::InvalidOperation),
Self::SharedMemory(_) => Err(Error::InvalidOperation),
// TODO maybe allow writing messages to Packet/Stream sockets?
Self::Socket(_) => Err(Error::InvalidOperation),
Self::Directory(_) => Err(Error::IsADirectory),
let non_blocking = self.options.read().non_blocking;
match &self.inner {
FileInner::Regular(file) => file.write(buf),
FileInner::Block(file) => file.write(buf),
FileInner::Char(file) => file.write(buf, non_blocking),
FileInner::AnonymousPipe(pipe) => pipe.write(buf),
FileInner::PtySlave(half) => half.write(buf),
FileInner::PtyMaster(half) => half.write(buf),
FileInner::Timer(timer) => timer.write(buf),
FileInner::Socket(socket) => socket.send_to(buf, None, non_blocking),
FileInner::Pid(_)
| FileInner::Poll(_)
| FileInner::SharedMemory(_)
| FileInner::Directory(_)
| FileInner::Channel(_) => Err(Error::InvalidOperation),
}
}
}
impl ReadAt for File {
fn read_at(&self, pos: u64, buf: &mut [u8]) -> Result<usize, Error> {
match self {
Self::Regular(file) => file.read_at(pos, buf),
// let non_blocking = self.options.read().non_blocking;
match &self.inner {
FileInner::Regular(file) => file.read_at(pos, buf),
_ => todo!(),
}
}
@ -479,8 +494,9 @@ impl ReadAt for File {
impl WriteAt for File {
fn write_at(&self, pos: u64, buf: &[u8]) -> Result<usize, Error> {
match self {
Self::Regular(file) => file.write_at(pos, buf),
// let non_blocking = self.options.read().non_blocking;
match &self.inner {
FileInner::Regular(file) => file.write_at(pos, buf),
_ => todo!(),
}
}
@ -488,10 +504,10 @@ impl WriteAt for File {
impl Seek for File {
fn tell(&self) -> Result<u64, Error> {
match self {
Self::Regular(file) => Ok(*file.position.lock()),
Self::Block(file) => Ok(*file.position.lock()),
Self::Directory(_) => Err(Error::IsADirectory),
match &self.inner {
FileInner::Regular(file) => Ok(*file.position.lock()),
FileInner::Block(file) => Ok(*file.position.lock()),
FileInner::Directory(_) => Err(Error::IsADirectory),
_ => Ok(0),
}
}
@ -501,10 +517,10 @@ impl Seek for File {
return self.tell();
}
match self {
Self::Regular(file) => file.seek(from),
Self::Block(file) => file.seek(from),
Self::Directory(_) => Err(Error::IsADirectory),
match &self.inner {
FileInner::Regular(file) => file.seek(from),
FileInner::Block(file) => file.seek(from),
FileInner::Directory(_) => Err(Error::IsADirectory),
_ => Err(Error::InvalidOperation),
}
}
@ -512,44 +528,58 @@ impl Seek for File {
impl fmt::Debug for File {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Regular(file) => f
match &self.inner {
FileInner::Regular(file) => f
.debug_struct("RegularFile")
.field("position", &*file.position.lock())
.field("read", &file.read)
.field("write", &file.write)
.finish_non_exhaustive(),
Self::Block(file) => f
FileInner::Block(file) => f
.debug_struct("BlockFile")
.field("position", &*file.position.lock())
.field("read", &file.read)
.field("write", &file.write)
.finish_non_exhaustive(),
Self::Char(file) => f
FileInner::Char(file) => f
.debug_struct("CharFile")
.field("read", &file.read)
.field("write", &file.write)
.finish_non_exhaustive(),
Self::Directory(_) => f.debug_struct("DirectoryFile").finish_non_exhaustive(),
Self::AnonymousPipe(_, _) => f.debug_struct("AnonymousPipe").finish_non_exhaustive(),
Self::Poll(_) => f.debug_struct("Poll").finish_non_exhaustive(),
Self::Channel(_) => f.debug_struct("Channel").finish_non_exhaustive(),
Self::SharedMemory(_) => f.debug_struct("SharedMemory").finish_non_exhaustive(),
Self::PtySlave(_) => f.debug_struct("PtySlave").finish_non_exhaustive(),
Self::PtyMaster(_) => f.debug_struct("PtyMaster").finish_non_exhaustive(),
Self::Socket(socket) => fmt::Debug::fmt(socket, f),
Self::Pid(pid) => fmt::Debug::fmt(pid, f),
Self::Timer(_) => f.debug_struct("Timer").finish_non_exhaustive(),
FileInner::Directory(_) => f.debug_struct("DirectoryFile").finish_non_exhaustive(),
FileInner::AnonymousPipe(_) => f.debug_struct("AnonymousPipe").finish_non_exhaustive(),
FileInner::Poll(_) => f.debug_struct("Poll").finish_non_exhaustive(),
FileInner::Channel(_) => f.debug_struct("Channel").finish_non_exhaustive(),
FileInner::SharedMemory(_) => f.debug_struct("SharedMemory").finish_non_exhaustive(),
FileInner::PtySlave(_) => f.debug_struct("PtySlave").finish_non_exhaustive(),
FileInner::PtyMaster(_) => f.debug_struct("PtyMaster").finish_non_exhaustive(),
FileInner::Socket(socket) => fmt::Debug::fmt(socket, f),
FileInner::Pid(pid) => fmt::Debug::fmt(pid, f),
FileInner::Timer(_) => f.debug_struct("Timer").finish_non_exhaustive(),
}
}
}
impl FileInner {
pub fn send(&self) -> Result<Self, Error> {
match self {
Self::Char(char) => Ok(Self::Char(char.clone())),
Self::Regular(file) => Ok(Self::Regular(file.clone())),
Self::SharedMemory(shm) => Ok(Self::SharedMemory(shm.clone())),
Self::Pid(pid) => Ok(Self::Pid(pid.clone())),
Self::PtySlave(half) => Ok(Self::PtySlave(half.clone())),
Self::PtyMaster(half) => Ok(Self::PtyMaster(half.clone())),
_ => todo!(),
}
}
}
impl<T: TerminalHalf> TerminalHalfWrapper<T> {
pub fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
if self.blocking.load(Ordering::Acquire) {
block!(self.half.read(buf).await)?
} else {
pub fn read(&self, buf: &mut [u8], non_blocking: bool) -> Result<usize, Error> {
if non_blocking {
self.half.read_nonblocking(buf)
} else {
block!(self.half.read(buf).await)?
}
}
@ -558,16 +588,6 @@ impl<T: TerminalHalf> TerminalHalfWrapper<T> {
}
}
impl<T: TerminalHalf> Clone for TerminalHalfWrapper<T> {
fn clone(&self) -> Self {
Self {
half: self.half.clone(),
node: self.node.clone(),
blocking: AtomicBool::new(self.blocking.load(Ordering::Acquire)),
}
}
}
impl FileSet {
/// Creates an empty [FileSet]
pub fn new() -> Self {

View File

@ -4,7 +4,6 @@ use core::{
task::{Context, Poll},
};
use libk_util::io::Read;
use yggdrasil_abi::{
error::Error,
process::{ExitCode, ProcessId, ProcessWait, WaitFlags},
@ -92,10 +91,8 @@ impl PidFile {
}
size_of::<u32>() + size_of::<i32>()
}
}
impl Read for PidFile {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
pub fn read(&self, buf: &mut [u8], _non_blocking: bool) -> Result<usize, Error> {
if buf.len() < size_of::<u32>() + size_of::<i32>() {
return Err(Error::BufferTooSmall);
}
@ -106,6 +103,9 @@ impl Read for PidFile {
}
}
// impl Read for PidFile {
// }
impl FileReadiness for PidFile {
fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
match self {

View File

@ -10,9 +10,10 @@ use libk_util::sync::spin_rwlock::IrqSafeRwLock;
use yggdrasil_abi::{
error::Error,
net::{
options::{self, SocketOption, SocketOptionVariant},
options::{self, SocketOptionVariant},
SocketAddr, SocketShutdown,
},
option::OptionValue,
};
use crate::vfs::FileReadiness;
@ -28,7 +29,6 @@ struct InnerOptions {
connect_timeout: Option<Duration>,
recv_timeout: Option<Duration>,
send_timeout: Option<Duration>,
non_blocking: bool,
}
pub struct SocketWrapper {
@ -177,8 +177,13 @@ impl SocketWrapper {
block!(self.connect_inner(remote).await)?
}
pub fn send_to(&self, data: &[u8], remote: Option<SocketAddr>) -> Result<usize, Error> {
if self.options.read().non_blocking {
pub fn send_to(
&self,
data: &[u8],
remote: Option<SocketAddr>,
non_blocking: bool,
) -> Result<usize, Error> {
if non_blocking {
match &self.inner {
SocketInner::Packet(socket) => socket.clone().send_nonblocking(remote, data),
SocketInner::Connection(socket) => socket.clone().send_nonblocking(data),
@ -188,8 +193,12 @@ impl SocketWrapper {
}
}
pub fn receive_from(&self, data: &mut [u8]) -> Result<(usize, SocketAddr), Error> {
if self.options.read().non_blocking {
pub fn receive_from(
&self,
data: &mut [u8],
non_blocking: bool,
) -> Result<(usize, SocketAddr), Error> {
if non_blocking {
match &self.inner {
SocketInner::Packet(socket) => socket.clone().receive_nonblocking(data),
SocketInner::Connection(socket) => socket.receive_nonblocking(data),
@ -213,12 +222,12 @@ impl SocketWrapper {
}
}
pub fn accept(&self) -> Result<(FileRef, SocketAddr), Error> {
pub fn accept(&self, non_blocking: bool) -> Result<(FileRef, SocketAddr), Error> {
let SocketInner::Connection(socket) = &self.inner else {
return Err(Error::InvalidOperation);
};
let (remote, stream) = if self.options.read().non_blocking {
let (remote, stream) = if non_blocking {
socket.accept_nonblocking()?
} else {
block!(socket.accept().await)??
@ -272,10 +281,6 @@ impl SocketWrapper {
options.connect_timeout = options::ConnectTimeout::load(buffer)?;
Ok(())
}
SocketOptionVariant::NonBlocking => {
options.non_blocking = options::NonBlocking::load(buffer)?;
Ok(())
}
SocketOptionVariant::LocalAddress | SocketOptionVariant::PeerAddress => {
Err(Error::InvalidArgument)
}
@ -310,9 +315,6 @@ impl SocketWrapper {
SocketOptionVariant::ConnectTimeout => {
options::ConnectTimeout::store(&options.connect_timeout, buffer)
}
SocketOptionVariant::NonBlocking => {
options::NonBlocking::store(&options.non_blocking, buffer)
}
};
}
@ -360,7 +362,6 @@ impl Default for InnerOptions {
connect_timeout: None,
recv_timeout: None,
send_timeout: None,
non_blocking: false,
}
}
}

View File

@ -7,7 +7,7 @@ use core::{
use alloc::boxed::Box;
use futures_util::FutureExt;
use libk_util::{io::Read, sync::LockMethod};
use libk_util::sync::LockMethod;
use yggdrasil_abi::error::Error;
use crate::{
@ -21,29 +21,23 @@ use crate::{
/// File-like structure to generate periodic or one-shit events at certain intervals
pub struct TimerFile {
inner: Box<Mutex<Option<SleepFuture>>>,
blocking: bool,
_repeat: bool,
}
impl TimerFile {
/// Creates a new inert timer
pub fn new(repeat: bool, blocking: bool) -> Self {
pub fn new(repeat: bool) -> Self {
Self {
_repeat: repeat,
blocking,
inner: Box::new(Mutex::new(None)),
}
}
}
impl Read for TimerFile {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
pub fn read(&self, buf: &mut [u8], non_blocking: bool) -> Result<usize, Error> {
if buf.len() < size_of::<u8>() {
return Err(Error::BufferTooSmall);
}
if self.blocking {
todo!()
} else {
if non_blocking {
let inner = self.inner.lock()?;
if inner.as_ref().and_then(SleepFuture::remaining).is_some() {
return Err(Error::WouldBlock);
@ -51,6 +45,8 @@ impl Read for TimerFile {
buf[0] = 1;
Ok(1)
} else {
todo!()
}
}
}

View File

@ -4,7 +4,7 @@ pub(crate) use abi::{
error::Error,
io::{
AccessMode, DirectoryEntry, FileAttr, FileMode, FileSync, MountOptions, OpenOptions,
PipeOptions, PollControl, RawFd, RemoveFlags, TerminalOptions, TerminalSize, TimerOptions,
PollControl, RawFd, RemoveFlags, TerminalOptions, TerminalSize, TimerOptions,
UnmountOptions,
},
mem::{MappingFlags, MappingSource},

View File

@ -5,8 +5,8 @@ use abi::{
io::{
AccessMode, ChannelPublisherId, DeviceRequest, DirectoryEntry, FileAttr, FileControl,
FileMetadataUpdate, FileMode, FileSync, FilesystemControl, MessageDestination, OpenOptions,
PipeOptions, PollControl, RawFd, ReceivedMessageMetadata, RemoveFlags, Rename, SeekFrom,
SentMessage, TerminalOptions, TerminalSize, TimerOptions,
PollControl, RawFd, ReceivedMessageMetadata, RemoveFlags, Rename, SeekFrom, SentMessage,
TerminalOptions, TerminalSize, TimerOptions,
},
process::{ProcessWait, WaitFlags},
};
@ -131,6 +131,20 @@ pub(crate) fn seek(fd: RawFd, pos: SeekFrom, output: &mut u64) -> Result<(), Err
})
}
pub(crate) fn get_file_option(fd: RawFd, option: u32, buffer: &mut [u8]) -> Result<usize, Error> {
let thread = Thread::current();
let process = thread.process();
run_with_io(&process, |io| io.files.file(fd)?.get_option(option, buffer))
}
pub(crate) fn set_file_option(fd: RawFd, option: u32, buffer: &[u8]) -> Result<(), Error> {
let thread = Thread::current();
let process = thread.process();
run_with_io(&process, |io| io.files.file(fd)?.set_option(option, buffer))
}
pub(crate) fn open_directory(at: Option<RawFd>, path: &str) -> Result<RawFd, Error> {
let thread = Thread::current();
let process = thread.process();
@ -368,15 +382,12 @@ pub(crate) fn create_poll_channel() -> Result<RawFd, Error> {
})
}
pub(crate) fn create_pipe(
ends: &mut [MaybeUninit<RawFd>; 2],
options: PipeOptions,
) -> Result<(), Error> {
pub(crate) fn create_pipe(ends: &mut [MaybeUninit<RawFd>; 2]) -> Result<(), Error> {
let thread = Thread::current();
let process = thread.process();
run_with_io(&process, |mut io| {
let (read, write) = File::new_pipe_pair(256, options);
let (read, write) = File::new_pipe_pair(256);
let read_fd = io.files.place_file(read, true)?;
let write_fd = io.files.place_file(write, true)?;

View File

@ -58,9 +58,10 @@ pub(crate) fn accept(sock_fd: RawFd, remote: &mut MaybeUninit<SocketAddr>) -> Re
run_with_io(&process, |mut io| {
let listener = io.files.file(sock_fd)?;
let non_blocking = listener.is_non_blocking();
let listener = listener.as_socket()?;
let (stream_file, stream_remote) = listener.accept()?;
let (stream_file, stream_remote) = listener.accept(non_blocking)?;
let stream_fd = io.files.place_file(stream_file, true)?;
remote.write(stream_remote.into());
@ -80,7 +81,9 @@ pub(crate) fn send_to(
remote: &Option<SocketAddr>,
) -> Result<usize, Error> {
let file = get_socket(sock_fd)?;
file.as_socket()?.send_to(data, remote.map(Into::into))
let non_blocking = file.is_non_blocking();
file.as_socket()?
.send_to(data, remote.map(Into::into), non_blocking)
}
pub(crate) fn receive_from(
@ -89,7 +92,8 @@ pub(crate) fn receive_from(
remote: &mut MaybeUninit<SocketAddr>,
) -> Result<usize, Error> {
let file = get_socket(sock_fd)?;
let (len, remote_) = file.as_socket()?.receive_from(data)?;
let non_blocking = file.is_non_blocking();
let (len, remote_) = file.as_socket()?.receive_from(data, non_blocking)?;
remote.write(remote_.into());
Ok(len)
}

View File

@ -65,13 +65,6 @@ bitfield OpenOptions(u32) {
CREATE_EXCL: 5,
}
bitfield PipeOptions(u32) {
/// If set, read end of the pipe will return WouldBlock if there's no data in the pipe
READ_NONBLOCKING: 0,
/// If set, write end of the pipe will return WouldBlock if the pipe is full
WRITE_NONBLOCKING: 1,
}
enum FileType(u32) {
/// Regular file
File = 1,
@ -134,7 +127,6 @@ enum PollControl(u32) {
bitfield TimerOptions(u32) {
REPEAT: 0,
NON_BLOCKING: 1,
}
// abi::io::terminal

View File

@ -128,7 +128,7 @@ syscall truncate(fd: RawFd, size: u64) -> Result<()>;
syscall fsync(fd: RawFd, what: FileSync) -> Result<()>;
syscall read_at(fd: RawFd, pos: u64, data: &mut [u8]) -> Result<usize>;
syscall write_at(fd: RawFd, pos: u64, data: &[u8]) -> Result<usize>;
syscall get_file_option(fd: RawFd, option: u32, data: &mut [u8]) -> Result<()>;
syscall get_file_option(fd: RawFd, option: u32, data: &mut [u8]) -> Result<usize>;
syscall set_file_option(fd: RawFd, option: u32, data: &[u8]) -> Result<()>;
syscall open_directory(at: Option<RawFd>, path: &str) -> Result<RawFd>;
@ -151,7 +151,7 @@ syscall create_pid(target: &ProcessWait, flags: WaitFlags) -> Result<RawFd>;
syscall create_pty(opts: &TerminalOptions, size: &TerminalSize, fds: &mut [MaybeUninit<RawFd>; 2]) -> Result<()>;
syscall create_shared_memory(size: usize) -> Result<RawFd>;
syscall create_poll_channel() -> Result<RawFd>;
syscall create_pipe(fds: &mut [MaybeUninit<RawFd>; 2], options: PipeOptions) -> Result<()>;
syscall create_pipe(fds: &mut [MaybeUninit<RawFd>; 2]) -> Result<()>;
syscall poll_channel_wait(
poll_fd: RawFd,

View File

@ -1,5 +1,7 @@
//! I/O-related definitions
pub mod options;
mod channel;
mod device;
mod file;
@ -9,8 +11,7 @@ mod terminal;
pub use crate::generated::{
AccessMode, DirectoryEntry, FileAttr, FileMode, FileSync, FileType, GroupId, MountOptions,
OpenOptions, PipeOptions, PollControl, RawFd, RemoveFlags, TimerOptions, UnmountOptions,
UserId,
OpenOptions, PollControl, RawFd, RemoveFlags, TimerOptions, UnmountOptions, UserId,
};
pub use channel::{ChannelPublisherId, MessageDestination, ReceivedMessageMetadata, SentMessage};
pub use device::{DeviceRequest, Framebuffer};

12
lib/abi/src/io/options.rs Normal file
View File

@ -0,0 +1,12 @@
//! File option definitions
option_group!(
#[doc = "Common file options"]
pub enum FileOptionVariant<'de> {
#[doc = "
If `true`, makes certain access operations return an error if no data is available
for reading or no buffer space is available for writing.
"]
0x1000: NonBlocking # 4 (bool),
}
);

View File

@ -44,6 +44,9 @@ pub mod error {
pub use generated::SyscallFunction;
#[macro_use]
pub mod option;
pub mod arch;
pub mod debug;
pub mod io;

View File

@ -1,72 +1,9 @@
//! Socket option definitions
use core::{net::SocketAddr, time::Duration};
use abi_serde::{wire, Deserialize, Serialize};
use crate::error::Error;
use super::{MacAddress, SocketInterfaceQuery};
#[allow(missing_docs)]
pub trait SocketOption<'de> {
type Value: Deserialize<'de> + Serialize;
type Variant: Copy + Into<u32> + TryFrom<u32, Error = Error>;
const VARIANT: Self::Variant;
fn store(value: &Self::Value, buffer: &mut [u8]) -> Result<usize, Error> {
Ok(wire::to_slice(value, buffer)?)
}
fn load(buffer: &'de [u8]) -> Result<Self::Value, Error> {
Ok(wire::from_slice(buffer)?)
}
}
#[allow(missing_docs)]
pub trait SocketOptionSizeHint {
const SIZE_HINT: usize;
}
macro_rules! socket_option_group {
(
$(#[$enum_meta:meta])*
$vis:vis enum $variant_ty:ident<$lifetime:lifetime> {
$(
$(#[$variant_meta:meta])*
$discriminant:literal: $variant:ident $(# $size_hint:literal)? ($value:ty)
),* $(,)?
}
) => {
$crate::primitive_enum! {
$(#[$enum_meta])*
$vis enum $variant_ty: u32 {
$(
$(#[$variant_meta])*
$variant = $discriminant
),*
}
}
$(
$(#[$variant_meta])*
$vis struct $variant;
impl<$lifetime> $crate::net::options::SocketOption<$lifetime> for $variant {
type Variant = $variant_ty;
type Value = $value;
const VARIANT: Self::Variant = $variant_ty::$variant;
}
$(
impl $crate::net::options::SocketOptionSizeHint for $variant {
const SIZE_HINT: usize = $size_hint;
}
)?
)*
};
}
socket_option_group!(
option_group!(
#[doc = "Common socket options"]
pub enum SocketOptionVariant<'de> {
#[doc = "(Read-only) Local address of the socket"]
@ -79,15 +16,10 @@ socket_option_group!(
0x1003: SendTimeout # 32 (Option<Duration>),
#[doc = "If not [None], connect operations time out after a certain amount"]
0x1004: ConnectTimeout # 32 (Option<Duration>),
#[doc = "
If `true`, receive/accept/send operations return an error if no
data/buffer space is immediately available.
"]
0x1005: NonBlocking # 4 (bool),
}
);
socket_option_group!(
option_group!(
#[doc = "UDP socket protocol-level options"]
pub enum UdpSocketOptionVariant<'de> {
#[doc = "UDP unicast packet Time-to-Live"]
@ -103,7 +35,7 @@ socket_option_group!(
}
);
socket_option_group!(
option_group!(
#[doc = "TCP socket protocol-level options"]
pub enum TcpSocketOptionVariant<'de> {
#[doc = "If `true`, disables the Nagle's algorithm (which is not yet implemented)"]
@ -113,7 +45,7 @@ socket_option_group!(
}
);
socket_option_group!(
option_group!(
#[doc = "Raw socket options"]
pub enum RawSocketOptionVariant<'de> {
#[doc = "

63
lib/abi/src/option.rs Normal file
View File

@ -0,0 +1,63 @@
#![allow(missing_docs)]
use abi_serde::{wire, Deserialize, Serialize};
use crate::error::Error;
pub trait OptionValue<'de> {
type Value: Deserialize<'de> + Serialize;
type Variant: Copy + Into<u32> + TryFrom<u32, Error = Error>;
const VARIANT: Self::Variant;
fn store(value: &Self::Value, buffer: &mut [u8]) -> Result<usize, Error> {
Ok(wire::to_slice(value, buffer)?)
}
fn load(buffer: &'de [u8]) -> Result<Self::Value, Error> {
Ok(wire::from_slice(buffer)?)
}
}
pub trait OptionSizeHint {
const SIZE_HINT: usize;
}
#[macro_export]
macro_rules! option_group {
(
$(#[$enum_meta:meta])*
$vis:vis enum $variant_ty:ident<$lifetime:lifetime> {
$(
$(#[$variant_meta:meta])*
$discriminant:literal: $variant:ident $(# $size_hint:literal)? ($value:ty)
),* $(,)?
}
) => {
$crate::primitive_enum! {
$(#[$enum_meta])*
$vis enum $variant_ty: u32 {
$(
$(#[$variant_meta])*
$variant = $discriminant
),*
}
}
$(
$(#[$variant_meta])*
$vis struct $variant;
impl<$lifetime> $crate::option::OptionValue<$lifetime> for $variant {
type Variant = $variant_ty;
type Value = $value;
const VARIANT: Self::Variant = $variant_ty::$variant;
}
$(
impl $crate::option::OptionSizeHint for $variant {
const SIZE_HINT: usize = $size_hint;
}
)?
)*
};
}

View File

@ -21,16 +21,19 @@ pub mod poll {
pub use abi::io::PollControl;
}
use core::mem::MaybeUninit;
pub use abi::io::{
AccessMode, DirectoryEntry, FileAttr, FileMetadataUpdate, FileMetadataUpdateMode, FileMode,
FileSync, FileTimesUpdate, FileType, OpenOptions, PipeOptions, RawFd, RemoveFlags, Rename,
options, AccessMode, DirectoryEntry, FileAttr, FileMetadataUpdate, FileMetadataUpdateMode,
FileMode, FileSync, FileTimesUpdate, FileType, OpenOptions, RawFd, RemoveFlags, Rename,
SeekFrom, TimerOptions,
};
pub use abi::option::OptionSizeHint;
pub mod paths;
pub use paths::*;
use abi::error::Error;
use abi::{error::Error, option::OptionValue};
use device::DeviceRequest;
@ -51,3 +54,73 @@ pub fn remove_directory(at: Option<RawFd>, path: &str) -> Result<(), Error> {
pub fn remove_directory_recursive(_at: Option<RawFd>, _path: &str) -> Result<(), Error> {
todo!()
}
fn configure_pipe(
read: RawFd,
write: RawFd,
read_nonblocking: bool,
write_nonblocking: bool,
) -> Result<(), Error> {
if read_nonblocking {
set_file_option::<options::NonBlocking>(read, &true)?;
}
if write_nonblocking {
set_file_option::<options::NonBlocking>(write, &true)?;
}
Ok(())
}
pub fn create_pipe_pair(
read_nonblocking: bool,
write_nonblocking: bool,
) -> Result<(RawFd, RawFd), Error> {
let mut fds = MaybeUninit::uninit_array();
unsafe { crate::sys::create_pipe(&mut fds) }?;
let fds = unsafe { MaybeUninit::array_assume_init(fds) };
let read = fds[0];
let write = fds[1];
match configure_pipe(read, write, read_nonblocking, write_nonblocking) {
Ok(()) => Ok((read, write)),
Err(error) => {
unsafe {
crate::sys::close(read).ok();
crate::sys::close(write).ok();
}
Err(error)
}
}
}
pub macro get_file_option($fd:expr, $variant_ty:ty) {{
let mut buffer = [0; <$variant_ty as $crate::io::OptionSizeHint>::SIZE_HINT];
$crate::io::get_file_option::<$variant_ty>($fd, &mut buffer)
}}
pub fn get_file_option<'de, T: OptionValue<'de>>(
fd: RawFd,
buffer: &'de mut [u8],
) -> Result<T::Value, Error> {
let len = unsafe { crate::sys::get_file_option(fd, T::VARIANT.into(), buffer) }?;
T::load(&buffer[..len])
}
pub fn set_file_option<'de, T: OptionValue<'de> + OptionSizeHint>(
fd: RawFd,
value: &T::Value,
) -> Result<(), Error>
where
[u8; T::SIZE_HINT]: Sized,
{
let mut buffer = [0; T::SIZE_HINT];
set_file_option_with::<T>(fd, &mut buffer, value)
}
pub fn set_file_option_with<'de, T: OptionValue<'de>>(
fd: RawFd,
buffer: &mut [u8],
value: &T::Value,
) -> Result<(), Error> {
let len = T::store(value, buffer)?;
unsafe { crate::sys::set_file_option(fd, T::VARIANT.into(), &buffer[..len]) }
}

View File

@ -6,7 +6,9 @@
linkage,
naked_functions,
thread_local,
generic_const_exprs
generic_const_exprs,
maybe_uninit_uninit_array,
maybe_uninit_array_assume_init
)]
#![no_std]
#![warn(missing_docs)]

View File

@ -4,44 +4,41 @@ use core::{net::SocketAddr, time::Duration};
use abi::{
error::Error,
io::RawFd,
net::{
options::{self, SocketOption, SocketOptionSizeHint},
SocketInterfaceQuery, SocketType,
},
net::{options, SocketInterfaceQuery, SocketType},
option::{OptionSizeHint, OptionValue},
};
use abi_serde::wire;
/// Short-hand macro for [get_socket_option].
///
/// Automatically sets up the `buffer` argument for socket options which implement
/// [SocketOptionSizeHint].
pub macro get_socket_option($fd:expr, $variant_ty:ty) {{
let mut buffer = [0; <$variant_ty as $crate::net::options::SocketOptionSizeHint>::SIZE_HINT];
let mut buffer = [0; <$variant_ty as $crate::io::OptionSizeHint>::SIZE_HINT];
$crate::net::get_socket_option::<$variant_ty>($fd, &mut buffer)
}}
/// Retrieves the value of a socket's option
pub fn get_socket_option<'de, T: SocketOption<'de>>(
pub fn get_socket_option<'de, T: OptionValue<'de>>(
fd: RawFd,
buffer: &'de mut [u8],
) -> Result<T::Value, Error> {
let len = unsafe { crate::sys::get_socket_option(fd, T::VARIANT.into(), buffer) }?;
Ok(wire::from_slice(&buffer[..len])?)
T::load(&buffer[..len])
}
/// Sets the value of a socket's option, using the buffer provided to marshall the payload
pub fn set_socket_option_with<'de, T: SocketOption<'de>>(
pub fn set_socket_option_with<'de, T: OptionValue<'de>>(
fd: RawFd,
buffer: &mut [u8],
value: &T::Value,
) -> Result<(), Error> {
let len = wire::to_slice(value, buffer)?;
let len = T::store(value, buffer)?;
unsafe { crate::sys::set_socket_option(fd, T::VARIANT.into(), &buffer[..len]) }
}
/// Sets the value of a socket's option, using a buffer set up automatically based on
/// [SocketOptionSizeHint]. See [set_socket_option_with].
pub fn set_socket_option<'de, T: SocketOption<'de> + SocketOptionSizeHint>(
pub fn set_socket_option<'de, T: OptionValue<'de> + OptionSizeHint>(
fd: RawFd,
value: &T::Value,
) -> Result<(), Error>

View File

@ -17,8 +17,8 @@ mod generated {
error::Error,
io::{
AccessMode, ChannelPublisherId, DirectoryEntry, FileAttr, FileMode, FileSync,
MountOptions, OpenOptions, PipeOptions, PollControl, RawFd, RemoveFlags,
TerminalOptions, TerminalSize, TimerOptions, UnmountOptions,
MountOptions, OpenOptions, PollControl, RawFd, RemoveFlags, TerminalOptions,
TerminalSize, TimerOptions, UnmountOptions,
},
mem::{MappingFlags, MappingSource},
net::{SocketShutdown, SocketType},