use alloc::{borrow::Cow, format, sync::Arc};
use core::{ffi::c_int, ops::Deref, task::Context};
use ax_errno::{AxError, AxResult};
use axnet::{
RecvOptions, SendOptions, Socket as SocketInner, SocketOps,
options::{Configurable, GetSocketOption, SetSocketOption},
};
use axpoll::{IoEvents, Pollable};
use linux_raw_sys::general::S_IFSOCK;
use super::{FileLike, Kstat};
use crate::file::{IoDst, IoSrc, get_file_like};
pub struct Socket(pub SocketInner);
impl Deref for Socket {
type Target = SocketInner;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl FileLike for Socket {
fn read(&self, dst: &mut IoDst) -> AxResult<usize> {
self.recv(dst, RecvOptions::default())
}
fn write(&self, src: &mut IoSrc) -> AxResult<usize> {
self.send(src, SendOptions::default())
}
fn stat(&self) -> AxResult<Kstat> {
Ok(Kstat {
mode: S_IFSOCK | 0o777u32, blksize: 4096,
..Default::default()
})
}
fn nonblocking(&self) -> bool {
let mut result = false;
self.get_option(GetSocketOption::NonBlocking(&mut result))
.unwrap();
result
}
fn set_nonblocking(&self, nonblocking: bool) -> AxResult<()> {
self.0
.set_option(SetSocketOption::NonBlocking(&nonblocking))
}
fn path(&self) -> Cow<'_, str> {
format!("socket:[{}]", self as *const _ as usize).into()
}
fn from_fd(fd: c_int) -> AxResult<Arc<Self>>
where
Self: Sized + 'static,
{
get_file_like(fd)?
.downcast_arc()
.map_err(|_| AxError::NotASocket)
}
}
impl Pollable for Socket {
fn poll(&self) -> IoEvents {
self.0.poll()
}
fn register(&self, context: &mut Context<'_>, events: IoEvents) {
self.0.register(context, events);
}
}