diff --git a/services/libs/jinux-std/src/fs/ramfs/fs.rs b/services/libs/jinux-std/src/fs/ramfs/fs.rs index 7c1b86d74..71a6f20be 100644 --- a/services/libs/jinux-std/src/fs/ramfs/fs.rs +++ b/services/libs/jinux-std/src/fs/ramfs/fs.rs @@ -378,6 +378,19 @@ impl RamInode { }) } + fn new_socket(fs: &Arc, mode: InodeMode) -> Arc { + Arc::new_cyclic(|weak_self| { + let inode = RamInode(RwLock::new(Inode_::new_socket( + fs.alloc_id(), + mode, + &fs.sb(), + ))); + inode.0.write().fs = Arc::downgrade(fs); + inode.0.write().this = weak_self.clone(); + inode + }) + } + fn new_symlink(fs: &Arc, mode: InodeMode) -> Arc { Arc::new_cyclic(|weak_self| { let inode = RamInode(RwLock::new(Inode_::new_symlink( @@ -494,29 +507,12 @@ impl Inode for RamInode { let new_inode = match type_ { InodeType::File => RamInode::new_file(&fs, mode), InodeType::SymLink => RamInode::new_symlink(&fs, mode), + InodeType::Socket => RamInode::new_socket(&fs, mode), InodeType::Dir => { let dir_inode = RamInode::new_dir(&fs, mode, &self_inode.this); self_inode.metadata.nlinks += 1; dir_inode } - InodeType::SymLink => { - let sym_inode = Arc::new(RamInode(RwLock::new(Inode_::new_symlink( - fs.alloc_id(), - mode, - &fs.sb(), - )))); - sym_inode.0.write().fs = self_inode.fs.clone(); - sym_inode - } - InodeType::Socket => { - let socket_inode = Arc::new(RamInode(RwLock::new(Inode_::new_socket( - fs.alloc_id(), - mode, - &fs.sb(), - )))); - socket_inode.0.write().fs = self_inode.fs.clone(); - socket_inode - } _ => { panic!("unsupported inode type"); } diff --git a/services/libs/jinux-std/src/net/socket/unix/addr.rs b/services/libs/jinux-std/src/net/socket/unix/addr.rs index d3ebcbe72..313b57167 100644 --- a/services/libs/jinux-std/src/net/socket/unix/addr.rs +++ b/services/libs/jinux-std/src/net/socket/unix/addr.rs @@ -1,88 +1,63 @@ -use crate::{ - fs::{ - fs_resolver::{split_path, FsPath}, - utils::{Dentry, InodeMode, InodeType}, - }, - net::socket::util::sockaddr::SocketAddr, - prelude::*, -}; +use crate::fs::utils::Dentry; +use crate::net::socket::util::sockaddr::SocketAddr; +use crate::prelude::*; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum UnixSocketAddr { + Path(String), + Abstract(String), +} #[derive(Clone)] -pub enum UnixSocketAddr { - Bound(Arc), - Unbound(String), +pub(super) enum UnixSocketAddrBound { + Path(Arc), + Abstract(String), +} + +impl PartialEq for UnixSocketAddrBound { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Abstract(l0), Self::Abstract(r0)) => l0 == r0, + (Self::Path(l0), Self::Path(r0)) => { + let Some(linode) = l0.inode().upgrade() else { + return false; + }; + let Some(rinode) = r0.inode().upgrade() else { + return false; + }; + Arc::ptr_eq(&linode, &rinode) + } + _ => false, + } + } } impl TryFrom for UnixSocketAddr { type Error = Error; fn try_from(value: SocketAddr) -> Result { - let SocketAddr::Unix(path) = value else { - return_errno_with_message!(Errno::EINVAL, "Invalid unix socket addr") - }; - Ok(Self::Unbound(path)) + match value { + SocketAddr::Unix(unix_socket_addr) => Ok(unix_socket_addr), + _ => return_errno_with_message!(Errno::EINVAL, "Invalid unix socket addr"), + } } } -impl From for SocketAddr { - fn from(value: UnixSocketAddr) -> Self { - SocketAddr::Unix(value.path()) - } -} - -impl UnixSocketAddr { - pub fn create_file_and_bind(&mut self) -> Result<()> { - let Self::Unbound(path) = self else { - return_errno_with_message!(Errno::EINVAL, "the addr is already bound"); - }; - - let (parent_pathname, file_name) = split_path(path); - let parent = { - let current = current!(); - let fs = current.fs().read(); - let parent_path = FsPath::try_from(parent_pathname)?; - fs.lookup(&parent_path)? - }; - let dentry = parent.create( - file_name, - InodeType::Socket, - InodeMode::S_IRUSR | InodeMode::S_IWUSR, - )?; - *self = Self::Bound(dentry); - Ok(()) - } - - /// The dentry. If self is bound, return the bound dentry, otherwise lookup dentry in file system. - pub fn dentry(&self) -> Result> { - match self { - UnixSocketAddr::Bound(dentry) => Ok(dentry.clone()), - UnixSocketAddr::Unbound(path) => { - let dentry = { - let current = current!(); - let fs = current.fs().read(); - let fs_path = FsPath::try_from(path.as_str())?; - fs.lookup(&fs_path)? - }; - - if dentry.inode_type() != InodeType::Socket { - return_errno_with_message!(Errno::EACCES, "not a socket file") - } - - if !dentry.inode_mode().is_readable() || !dentry.inode_mode().is_writable() { - return_errno_with_message!( - Errno::EACCES, - "the socket cannot be read or written" - ) - } - return Ok(dentry); +impl From for UnixSocketAddr { + fn from(value: UnixSocketAddrBound) -> Self { + match value { + UnixSocketAddrBound::Path(dentry) => { + let abs_path = dentry.abs_path(); + Self::Path(abs_path) } - } - } - - pub fn path(&self) -> String { - match self { - UnixSocketAddr::Bound(dentry) => dentry.abs_path(), - UnixSocketAddr::Unbound(path) => path.clone(), + UnixSocketAddrBound::Abstract(name) => Self::Abstract(name), } } } + +impl From for SocketAddr { + fn from(value: UnixSocketAddrBound) -> Self { + let unix_socket_addr = UnixSocketAddr::from(value); + SocketAddr::Unix(unix_socket_addr) + } +} diff --git a/services/libs/jinux-std/src/net/socket/unix/stream/connected.rs b/services/libs/jinux-std/src/net/socket/unix/stream/connected.rs index 195dff259..859e5b35f 100644 --- a/services/libs/jinux-std/src/net/socket/unix/stream/connected.rs +++ b/services/libs/jinux-std/src/net/socket/unix/stream/connected.rs @@ -1,55 +1,50 @@ -use crate::{ - net::socket::{unix::addr::UnixSocketAddr, SockShutdownCmd}, - prelude::*, -}; - use super::endpoint::Endpoint; +use crate::fs::utils::{IoEvents, Poller}; +use crate::net::socket::{unix::addr::UnixSocketAddrBound, SockShutdownCmd}; +use crate::prelude::*; -pub struct Connected { +pub(super) struct Connected { local_endpoint: Arc, - // The peer addr is None if peer is unnamed. - // FIXME: can a socket be bound after the socket is connected? - peer_addr: Option, } impl Connected { - pub fn new(local_endpoint: Arc) -> Self { - let peer_addr = local_endpoint.peer_addr(); - Connected { - local_endpoint, - peer_addr, - } + pub(super) fn new(local_endpoint: Arc) -> Self { + Connected { local_endpoint } } - pub fn addr(&self) -> Option { + pub(super) fn addr(&self) -> Option { self.local_endpoint.addr() } - pub fn peer_addr(&self) -> Option<&UnixSocketAddr> { - self.peer_addr.as_ref() + pub(super) fn peer_addr(&self) -> Option { + self.local_endpoint.peer_addr() } - pub fn is_bound(&self) -> bool { + pub(super) fn is_bound(&self) -> bool { self.addr().is_some() } - pub fn write(&self, buf: &[u8]) -> Result { + pub(super) fn write(&self, buf: &[u8]) -> Result { self.local_endpoint.write(buf) } - pub fn read(&self, buf: &mut [u8]) -> Result { + pub(super) fn read(&self, buf: &mut [u8]) -> Result { self.local_endpoint.read(buf) } - pub fn shutdown(&self, cmd: SockShutdownCmd) -> Result<()> { + pub(super) fn shutdown(&self, cmd: SockShutdownCmd) -> Result<()> { self.local_endpoint.shutdown(cmd) } - pub fn is_nonblocking(&self) -> bool { + pub(super) fn is_nonblocking(&self) -> bool { self.local_endpoint.is_nonblocking() } - pub fn set_nonblocking(&self, is_nonblocking: bool) { + pub(super) fn set_nonblocking(&self, is_nonblocking: bool) { self.local_endpoint.set_nonblocking(is_nonblocking).unwrap(); } + + pub(super) fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + self.local_endpoint.poll(mask, poller) + } } diff --git a/services/libs/jinux-std/src/net/socket/unix/stream/endpoint.rs b/services/libs/jinux-std/src/net/socket/unix/stream/endpoint.rs index 6955eba9a..e56ba9226 100644 --- a/services/libs/jinux-std/src/net/socket/unix/stream/endpoint.rs +++ b/services/libs/jinux-std/src/net/socket/unix/stream/endpoint.rs @@ -1,20 +1,20 @@ use crate::{ fs::utils::{Channel, Consumer, IoEvents, Poller, Producer, StatusFlags}, - net::socket::{unix::addr::UnixSocketAddr, SockShutdownCmd}, + net::socket::{unix::addr::UnixSocketAddrBound, SockShutdownCmd}, prelude::*, }; -pub struct Endpoint(Inner); +pub(super) struct Endpoint(Inner); struct Inner { - addr: RwLock>, + addr: RwLock>, reader: Consumer, writer: Producer, peer: Weak, } impl Endpoint { - pub fn end_pair(is_nonblocking: bool) -> Result<(Arc, Arc)> { + pub(super) fn new_pair(is_nonblocking: bool) -> Result<(Arc, Arc)> { let flags = if is_nonblocking { StatusFlags::O_NONBLOCK } else { @@ -43,26 +43,26 @@ impl Endpoint { }) } - pub fn addr(&self) -> Option { + pub(super) fn addr(&self) -> Option { self.0.addr.read().clone() } - pub fn set_addr(&self, addr: UnixSocketAddr) { + pub(super) fn set_addr(&self, addr: UnixSocketAddrBound) { *self.0.addr.write() = Some(addr); } - pub fn peer_addr(&self) -> Option { + pub(super) fn peer_addr(&self) -> Option { self.0.peer.upgrade().map(|peer| peer.addr()).flatten() } - pub fn is_nonblocking(&self) -> bool { + pub(super) fn is_nonblocking(&self) -> bool { let reader_status = self.0.reader.is_nonblocking(); let writer_status = self.0.writer.is_nonblocking(); debug_assert!(reader_status == writer_status); reader_status } - pub fn set_nonblocking(&self, is_nonblocking: bool) -> Result<()> { + pub(super) fn set_nonblocking(&self, is_nonblocking: bool) -> Result<()> { let reader_flags = self.0.reader.status_flags(); self.0 .reader @@ -74,15 +74,15 @@ impl Endpoint { Ok(()) } - pub fn read(&self, buf: &mut [u8]) -> Result { + pub(super) fn read(&self, buf: &mut [u8]) -> Result { self.0.reader.read(buf) } - pub fn write(&self, buf: &[u8]) -> Result { + pub(super) fn write(&self, buf: &[u8]) -> Result { self.0.writer.write(buf) } - pub fn shutdown(&self, cmd: SockShutdownCmd) -> Result<()> { + pub(super) fn shutdown(&self, cmd: SockShutdownCmd) -> Result<()> { if !self.is_connected() { return_errno_with_message!(Errno::ENOTCONN, "The socket is not connected."); } @@ -98,11 +98,11 @@ impl Endpoint { Ok(()) } - pub fn is_connected(&self) -> bool { + pub(super) fn is_connected(&self) -> bool { self.0.peer.upgrade().is_some() } - pub fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + pub(super) fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { let mut events = IoEvents::empty(); // FIXME: should reader and writer use the same mask? let reader_events = self.0.reader.poll(mask, poller); diff --git a/services/libs/jinux-std/src/net/socket/unix/stream/init.rs b/services/libs/jinux-std/src/net/socket/unix/stream/init.rs index 68ffca23c..1ae3e05ab 100644 --- a/services/libs/jinux-std/src/net/socket/unix/stream/init.rs +++ b/services/libs/jinux-std/src/net/socket/unix/stream/init.rs @@ -1,50 +1,99 @@ use core::sync::atomic::{AtomicBool, Ordering}; -use crate::fs::utils::{IoEvents, Pollee, Poller}; -use crate::net::socket::unix::addr::UnixSocketAddr; +use crate::fs::fs_resolver::{split_path, FsPath}; +use crate::fs::utils::{Dentry, InodeMode, InodeType, IoEvents, Pollee, Poller}; +use crate::net::socket::unix::addr::{UnixSocketAddr, UnixSocketAddrBound}; use crate::prelude::*; -pub struct Init { +use super::connected::Connected; +use super::endpoint::Endpoint; +use super::listener::push_incoming; + +pub(super) struct Init { is_nonblocking: AtomicBool, - bind_addr: Option, + addr: Mutex>, pollee: Pollee, } impl Init { - pub fn new(is_nonblocking: bool) -> Self { + pub(super) fn new(is_nonblocking: bool) -> Self { Self { is_nonblocking: AtomicBool::new(is_nonblocking), - bind_addr: None, + addr: Mutex::new(None), pollee: Pollee::new(IoEvents::empty()), } } - pub fn bind(&mut self, mut addr: UnixSocketAddr) -> Result<()> { - if self.bind_addr.is_some() { + pub(super) fn bind(&self, addr_to_bind: &UnixSocketAddr) -> Result<()> { + let mut addr = self.addr.lock(); + if addr.is_some() { return_errno_with_message!(Errno::EINVAL, "the socket is already bound"); } - addr.create_file_and_bind()?; - self.bind_addr = Some(addr); + + let bound_addr = match addr_to_bind { + UnixSocketAddr::Abstract(_) => todo!(), + UnixSocketAddr::Path(path) => { + let dentry = create_socket_file(path)?; + UnixSocketAddrBound::Path(dentry) + } + }; + + *addr = Some(bound_addr); Ok(()) } - pub fn is_bound(&self) -> bool { - self.bind_addr.is_none() + pub(super) fn connect(&self, remote_addr: &UnixSocketAddrBound) -> Result { + let addr = self.addr(); + + if let Some(ref addr) = addr { + if *addr == *remote_addr { + return_errno_with_message!(Errno::EINVAL, "try to connect to self is invalid"); + } + } + + let (this_end, remote_end) = Endpoint::new_pair(self.is_nonblocking())?; + remote_end.set_addr(remote_addr.clone()); + if let Some(addr) = addr { + this_end.set_addr(addr.clone()); + }; + + push_incoming(remote_addr, remote_end)?; + Ok(Connected::new(this_end)) } - pub fn bound_addr(&self) -> Option<&UnixSocketAddr> { - self.bind_addr.as_ref() + pub(super) fn is_bound(&self) -> bool { + self.addr.lock().is_some() } - pub fn is_nonblocking(&self) -> bool { + pub(super) fn addr(&self) -> Option { + self.addr.lock().clone() + } + + pub(super) fn is_nonblocking(&self) -> bool { self.is_nonblocking.load(Ordering::Acquire) } - pub fn set_nonblocking(&self, is_nonblocking: bool) { + pub(super) fn set_nonblocking(&self, is_nonblocking: bool) { self.is_nonblocking.store(is_nonblocking, Ordering::Release); } - pub fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + pub(super) fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { self.pollee.poll(mask, poller) } } + +fn create_socket_file(path: &str) -> Result> { + let (parent_pathname, file_name) = split_path(path); + let parent = { + let current = current!(); + let fs = current.fs().read(); + let parent_path = FsPath::try_from(parent_pathname)?; + fs.lookup(&parent_path)? + }; + let dentry = parent.create( + file_name, + InodeType::Socket, + InodeMode::S_IRUSR | InodeMode::S_IWUSR, + )?; + Ok(dentry) +} diff --git a/services/libs/jinux-std/src/net/socket/unix/stream/listen.rs b/services/libs/jinux-std/src/net/socket/unix/stream/listen.rs deleted file mode 100644 index 8f5f6644a..000000000 --- a/services/libs/jinux-std/src/net/socket/unix/stream/listen.rs +++ /dev/null @@ -1,29 +0,0 @@ -use core::sync::atomic::{AtomicBool, Ordering}; - -use crate::net::socket::unix::addr::UnixSocketAddr; - -pub struct Listen { - addr: UnixSocketAddr, - is_nonblocking: AtomicBool, -} - -impl Listen { - pub fn new(addr: UnixSocketAddr, nonblocking: bool) -> Self { - Self { - addr, - is_nonblocking: AtomicBool::new(nonblocking), - } - } - - pub fn addr(&self) -> &UnixSocketAddr { - &self.addr - } - - pub fn is_nonblocking(&self) -> bool { - self.is_nonblocking.load(Ordering::Acquire) - } - - pub fn set_nonblocking(&self, is_nonblocking: bool) { - self.is_nonblocking.store(is_nonblocking, Ordering::Release); - } -} diff --git a/services/libs/jinux-std/src/net/socket/unix/stream/listener.rs b/services/libs/jinux-std/src/net/socket/unix/stream/listener.rs index 210ed21a0..4470183c5 100644 --- a/services/libs/jinux-std/src/net/socket/unix/stream/listener.rs +++ b/services/libs/jinux-std/src/net/socket/unix/stream/listener.rs @@ -1,116 +1,171 @@ +use super::{connected::Connected, endpoint::Endpoint, UnixStreamSocket}; +use crate::fs::file_handle::FileLike; +use crate::fs::utils::{Dentry, Inode, IoEvents, Pollee, Poller}; +use crate::net::socket::unix::addr::{UnixSocketAddr, UnixSocketAddrBound}; +use crate::net::socket::SocketAddr; +use crate::prelude::*; +use core::sync::atomic::{AtomicBool, Ordering}; use keyable_arc::KeyableWeak; -use spin::RwLockReadGuard; -use crate::{ - fs::utils::{Inode, IoEvents, Pollee, Poller}, - net::socket::unix::addr::UnixSocketAddr, - prelude::*, -}; +pub(super) struct Listener { + addr: UnixSocketAddrBound, + is_nonblocking: AtomicBool, +} -use super::endpoint::Endpoint; +impl Listener { + pub(super) fn new( + addr: UnixSocketAddrBound, + backlog: usize, + nonblocking: bool, + ) -> Result { + BACKLOG_TABLE.add_backlog(&addr, backlog)?; + Ok(Self { + addr, + is_nonblocking: AtomicBool::new(nonblocking), + }) + } -pub static ACTIVE_LISTENERS: ActiveListeners = ActiveListeners::new(); + pub(super) fn addr(&self) -> &UnixSocketAddrBound { + &self.addr + } -pub struct ActiveListeners { - listeners: RwLock, Arc>>, + pub(super) fn is_nonblocking(&self) -> bool { + self.is_nonblocking.load(Ordering::Acquire) + } + + pub(super) fn set_nonblocking(&self, is_nonblocking: bool) { + self.is_nonblocking.store(is_nonblocking, Ordering::Release); + } + + pub(super) fn accept(&self) -> Result<(Arc, SocketAddr)> { + let addr = self.addr().clone(); + let is_nonblocking = self.is_nonblocking(); + + let connected = { + let local_endpoint = BACKLOG_TABLE.pop_incoming(is_nonblocking, &addr)?; + Connected::new(local_endpoint) + }; + + let peer_addr = match connected.peer_addr() { + None => SocketAddr::Unix(UnixSocketAddr::Path(String::new())), + Some(addr) => SocketAddr::from(addr.clone()), + }; + + let socket = Arc::new(UnixStreamSocket::new_connected(connected)); + + Ok((socket, peer_addr)) + } + + pub(super) fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + let addr = self.addr(); + let backlog = BACKLOG_TABLE.get_backlog(addr).unwrap(); + backlog.poll(mask, poller) + } +} + +static BACKLOG_TABLE: BacklogTable = BacklogTable::new(); + +struct BacklogTable { + backlog_sockets: RwLock, Arc>>, // TODO: For linux, there is also abstract socket domain that a socket addr is not bound to an inode. } -impl ActiveListeners { - pub const fn new() -> Self { +impl BacklogTable { + const fn new() -> Self { Self { - listeners: RwLock::new(BTreeMap::new()), + backlog_sockets: RwLock::new(BTreeMap::new()), } } - pub(super) fn add_listener(&self, addr: &UnixSocketAddr, backlog: usize) -> Result<()> { - let inode = create_keyable_inode(addr)?; - let mut listeners = self.listeners.write(); - if listeners.contains_key(&inode) { + fn add_backlog(&self, addr: &UnixSocketAddrBound, backlog: usize) -> Result<()> { + let inode = { + let UnixSocketAddrBound::Path(dentry) = addr else { + todo!() + }; + create_keyable_inode(dentry) + }; + + let mut backlog_sockets = self.backlog_sockets.write(); + if backlog_sockets.contains_key(&inode) { return_errno_with_message!(Errno::EADDRINUSE, "the addr is already used"); } - let new_listener = Arc::new(Listener::new(backlog)); - listeners.insert(inode, new_listener); + let new_backlog = Arc::new(Backlog::new(backlog)); + backlog_sockets.insert(inode, new_backlog); Ok(()) } - pub(super) fn get_listener(&self, addr: &UnixSocketAddr) -> Result> { - let listeners = self.listeners.read(); - get_listener(&listeners, addr) + fn get_backlog(&self, addr: &UnixSocketAddrBound) -> Result> { + let inode = { + let UnixSocketAddrBound::Path(dentry) = addr else { + todo!() + }; + create_keyable_inode(dentry) + }; + + let backlog_sockets = self.backlog_sockets.read(); + backlog_sockets + .get(&inode) + .map(Arc::clone) + .ok_or_else(|| Error::with_message(Errno::EINVAL, "the socket is not listened")) } - pub(super) fn pop_incoming( - &self, - nonblocking: bool, - addr: &UnixSocketAddr, - ) -> Result> { + fn pop_incoming(&self, nonblocking: bool, addr: &UnixSocketAddrBound) -> Result> { let poller = Poller::new(); loop { - let listener = { - let listeners = self.listeners.read(); - get_listener(&listeners, addr)? - }; - if let Some(endpoint) = listener.pop_incoming() { + let backlog = self.get_backlog(addr)?; + + if let Some(endpoint) = backlog.pop_incoming() { return Ok(endpoint); } + if nonblocking { return_errno_with_message!(Errno::EAGAIN, "no connection comes"); } + let events = { let mask = IoEvents::IN; - listener.poll(mask, Some(&poller)) + backlog.poll(mask, Some(&poller)) }; + if events.contains(IoEvents::ERR) | events.contains(IoEvents::HUP) { - return_errno_with_message!(Errno::EINVAL, "connection is refused"); + return_errno_with_message!(Errno::ECONNABORTED, "connection is aborted"); } + if events.is_empty() { poller.wait(); } } } - pub(super) fn push_incoming( - &self, - addr: &UnixSocketAddr, - endpoint: Arc, - ) -> Result<()> { - let listeners = self.listeners.read(); - let listener = get_listener(&listeners, addr).map_err(|_| { + fn push_incoming(&self, addr: &UnixSocketAddrBound, endpoint: Arc) -> Result<()> { + let backlog = self.get_backlog(addr).map_err(|_| { Error::with_message( Errno::ECONNREFUSED, "no socket is listened at the remote address", ) })?; - listener.push_incoming(endpoint) + + backlog.push_incoming(endpoint) } - pub(super) fn remove_listener(&self, addr: &UnixSocketAddr) { - let Ok(inode) = create_keyable_inode(addr) else { - return; + fn remove_backlog(&self, addr: &UnixSocketAddrBound) { + let UnixSocketAddrBound::Path(dentry) = addr else { + todo!() }; - self.listeners.write().remove(&inode); + + let inode = create_keyable_inode(dentry); + self.backlog_sockets.write().remove(&inode); } } -fn get_listener( - listeners: &RwLockReadGuard, Arc>>, - addr: &UnixSocketAddr, -) -> Result> { - let dentry = create_keyable_inode(addr)?; - listeners - .get(&dentry) - .map(Arc::clone) - .ok_or_else(|| Error::with_message(Errno::EINVAL, "the socket is not listened")) -} - -pub(super) struct Listener { +struct Backlog { pollee: Pollee, backlog: usize, incoming_endpoints: Mutex>>, } -impl Listener { - pub fn new(backlog: usize) -> Self { +impl Backlog { + fn new(backlog: usize) -> Self { Self { pollee: Pollee::new(IoEvents::empty()), backlog, @@ -118,7 +173,7 @@ impl Listener { } } - pub fn push_incoming(&self, endpoint: Arc) -> Result<()> { + fn push_incoming(&self, endpoint: Arc) -> Result<()> { let mut endpoints = self.incoming_endpoints.lock(); if endpoints.len() >= self.backlog { return_errno_with_message!(Errno::ECONNREFUSED, "incoming_endpoints is full"); @@ -128,24 +183,34 @@ impl Listener { Ok(()) } - pub fn pop_incoming(&self) -> Option> { + fn pop_incoming(&self) -> Option> { let mut incoming_endpoints = self.incoming_endpoints.lock(); let endpoint = incoming_endpoints.pop_front(); - if endpoint.is_none() { + if incoming_endpoints.is_empty() { self.pollee.del_events(IoEvents::IN); } endpoint } - pub fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { // Lock to avoid any events may change pollee state when we poll let _lock = self.incoming_endpoints.lock(); self.pollee.poll(mask, poller) } } -fn create_keyable_inode(addr: &UnixSocketAddr) -> Result> { - let dentry = addr.dentry()?; +fn create_keyable_inode(dentry: &Arc) -> KeyableWeak { let inode = dentry.inode(); - Ok(KeyableWeak::from(inode)) + KeyableWeak::from(inode) +} + +pub(super) fn unregister_backlog(addr: &UnixSocketAddrBound) { + BACKLOG_TABLE.remove_backlog(&addr); +} + +pub(super) fn push_incoming( + remote_addr: &UnixSocketAddrBound, + remote_end: Arc, +) -> Result<()> { + BACKLOG_TABLE.push_incoming(remote_addr, remote_end) } diff --git a/services/libs/jinux-std/src/net/socket/unix/stream/mod.rs b/services/libs/jinux-std/src/net/socket/unix/stream/mod.rs index 498b7c0eb..ee410dc89 100644 --- a/services/libs/jinux-std/src/net/socket/unix/stream/mod.rs +++ b/services/libs/jinux-std/src/net/socket/unix/stream/mod.rs @@ -1,9 +1,7 @@ mod connected; mod endpoint; mod init; -mod listen; mod listener; -pub mod stream; +mod stream; -pub use listener::{ActiveListeners, ACTIVE_LISTENERS}; pub use stream::UnixStreamSocket; diff --git a/services/libs/jinux-std/src/net/socket/unix/stream/stream.rs b/services/libs/jinux-std/src/net/socket/unix/stream/stream.rs index 755dc136e..c6294bcd1 100644 --- a/services/libs/jinux-std/src/net/socket/unix/stream/stream.rs +++ b/services/libs/jinux-std/src/net/socket/unix/stream/stream.rs @@ -1,6 +1,8 @@ use crate::fs::file_handle::FileLike; -use crate::fs::utils::{IoEvents, Poller, StatusFlags}; -use crate::net::socket::unix::addr::UnixSocketAddr; +use crate::fs::fs_resolver::FsPath; +use crate::fs::utils::{Dentry, InodeType, IoEvents, Poller, StatusFlags}; +use crate::net::socket::unix::addr::UnixSocketAddrBound; +use crate::net::socket::unix::UnixSocketAddr; use crate::net::socket::util::send_recv_flags::SendRecvFlags; use crate::net::socket::util::sockaddr::SocketAddr; use crate::net::socket::{SockShutdownCmd, Socket}; @@ -9,40 +11,59 @@ use crate::prelude::*; use super::connected::Connected; use super::endpoint::Endpoint; use super::init::Init; -use super::listen::Listen; -use super::ACTIVE_LISTENERS; +use super::listener::{unregister_backlog, Listener}; -pub struct UnixStreamSocket(RwLock); +pub struct UnixStreamSocket(RwLock); -enum Status { - Init(Init), - Listen(Listen), - Connected(Connected), +impl UnixStreamSocket { + pub(super) fn new_init(init: Init) -> Self { + Self(RwLock::new(State::Init(Arc::new(init)))) + } + + pub(super) fn new_listen(listen: Listener) -> Self { + Self(RwLock::new(State::Listen(Arc::new(listen)))) + } + + pub(super) fn new_connected(connected: Connected) -> Self { + Self(RwLock::new(State::Connected(Arc::new(connected)))) + } +} + +enum State { + Init(Arc), + Listen(Arc), + Connected(Arc), } impl UnixStreamSocket { pub fn new(nonblocking: bool) -> Self { - let status = Status::Init(Init::new(nonblocking)); - Self(RwLock::new(status)) + let init = Init::new(nonblocking); + Self::new_init(init) } pub fn new_pair(nonblocking: bool) -> Result<(Arc, Arc)> { - let (end_a, end_b) = Endpoint::end_pair(nonblocking)?; - let connected_a = UnixStreamSocket(RwLock::new(Status::Connected(Connected::new(end_a)))); - let connected_b = UnixStreamSocket(RwLock::new(Status::Connected(Connected::new(end_b)))); + let (end_a, end_b) = Endpoint::new_pair(nonblocking)?; + let connected_a = { + let connected = Connected::new(end_a); + Self::new_connected(connected) + }; + let connected_b = { + let connected = Connected::new(end_b); + Self::new_connected(connected) + }; Ok((Arc::new(connected_a), Arc::new(connected_b))) } - fn bound_addr(&self) -> Option { + fn bound_addr(&self) -> Option { let status = self.0.read(); match &*status { - Status::Init(init) => init.bound_addr().map(Clone::clone), - Status::Listen(listen) => Some(listen.addr().clone()), - Status::Connected(connected) => connected.addr(), + State::Init(init) => init.addr(), + State::Listen(listen) => Some(listen.addr().clone()), + State::Connected(connected) => connected.addr(), } } - fn supported_flags(status_flags: &StatusFlags) -> StatusFlags { + fn mask_flags(status_flags: &StatusFlags) -> StatusFlags { const SUPPORTED_FLAGS: StatusFlags = StatusFlags::O_NONBLOCK; const UNSUPPORTED_FLAGS: StatusFlags = SUPPORTED_FLAGS.complement(); @@ -71,22 +92,18 @@ impl FileLike for UnixStreamSocket { fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { let inner = self.0.read(); match &*inner { - Status::Init(init) => init.poll(mask, poller), - Status::Listen(listen) => { - let addr = listen.addr(); - let listener = ACTIVE_LISTENERS.get_listener(addr).unwrap(); - listener.poll(mask, poller) - } - Status::Connected(connet) => todo!(), + State::Init(init) => init.poll(mask, poller), + State::Listen(listen) => listen.poll(mask, poller), + State::Connected(connected) => connected.poll(mask, poller), } } fn status_flags(&self) -> StatusFlags { let inner = self.0.read(); let is_nonblocking = match &*inner { - Status::Init(init) => init.is_nonblocking(), - Status::Listen(listen) => listen.is_nonblocking(), - Status::Connected(connected) => connected.is_nonblocking(), + State::Init(init) => init.is_nonblocking(), + State::Listen(listen) => listen.is_nonblocking(), + State::Connected(connected) => connected.is_nonblocking(), }; if is_nonblocking { @@ -98,15 +115,15 @@ impl FileLike for UnixStreamSocket { fn set_status_flags(&self, new_flags: StatusFlags) -> Result<()> { let is_nonblocking = { - let supported_flags = Self::supported_flags(&new_flags); + let supported_flags = Self::mask_flags(&new_flags); supported_flags.contains(StatusFlags::O_NONBLOCK) }; let mut inner = self.0.write(); match &mut *inner { - Status::Init(init) => init.set_nonblocking(is_nonblocking), - Status::Listen(listen) => listen.set_nonblocking(is_nonblocking), - Status::Connected(connected) => connected.set_nonblocking(is_nonblocking), + State::Init(init) => init.set_nonblocking(is_nonblocking), + State::Listen(listen) => listen.set_nonblocking(is_nonblocking), + State::Connected(connected) => connected.set_nonblocking(is_nonblocking), } Ok(()) } @@ -115,114 +132,93 @@ impl FileLike for UnixStreamSocket { impl Socket for UnixStreamSocket { fn bind(&self, sockaddr: SocketAddr) -> Result<()> { let addr = UnixSocketAddr::try_from(sockaddr)?; - let mut inner = self.0.write(); - match &mut *inner { - Status::Init(init) => init.bind(addr), - Status::Listen(_) | Status::Connected(_) => { - return_errno_with_message!( - Errno::EINVAL, - "cannot bind a listening or connected socket" - ); - } // FIXME: Maybe binding a connected sockted should also be allowed? - } + + let init = match &*self.0.read() { + State::Init(init) => init.clone(), + _ => return_errno_with_message!( + Errno::EINVAL, + "cannot bind a listening or connected socket" + ), + // FIXME: Maybe binding a connected socket should also be allowed? + }; + + init.bind(&addr) } fn connect(&self, sockaddr: SocketAddr) -> Result<()> { - let mut inner = self.0.write(); - match &*inner { - Status::Init(init) => { - let remote_addr = UnixSocketAddr::try_from(sockaddr)?; - let addr = init.bound_addr(); - if let Some(addr) = addr { - if addr.path() == remote_addr.path() { - return_errno_with_message!( - Errno::EINVAL, - "try to connect to self is invalid" - ); - } + let remote_addr = { + let unix_socket_addr = UnixSocketAddr::try_from(sockaddr)?; + match unix_socket_addr { + UnixSocketAddr::Abstract(abstract_name) => { + UnixSocketAddrBound::Abstract(abstract_name) + } + UnixSocketAddr::Path(path) => { + let dentry = lookup_socket_file(&path)?; + UnixSocketAddrBound::Path(dentry) } - let (this_end, remote_end) = Endpoint::end_pair(init.is_nonblocking())?; - remote_end.set_addr(remote_addr.clone()); - if let Some(addr) = addr { - this_end.set_addr(addr.clone()); - }; - ACTIVE_LISTENERS.push_incoming(&remote_addr, remote_end)?; - *inner = Status::Connected(Connected::new(this_end)); - Ok(()) } - Status::Listen(_) => { - return_errno_with_message!(Errno::EINVAL, "the socket is listened") - } - Status::Connected(_) => { + }; + + let init = match &*self.0.read() { + State::Init(init) => init.clone(), + State::Listen(_) => return_errno_with_message!(Errno::EINVAL, "the socket is listened"), + State::Connected(_) => { return_errno_with_message!(Errno::EISCONN, "the socket is connected") } - } + }; + + let connected = init.connect(&remote_addr)?; + + *self.0.write() = State::Connected(Arc::new(connected)); + Ok(()) } fn listen(&self, backlog: usize) -> Result<()> { - let mut inner = self.0.write(); - match &*inner { - Status::Init(init) => { - let addr = init.bound_addr().ok_or(Error::with_message( - Errno::EINVAL, - "the socket is not bound", - ))?; - ACTIVE_LISTENERS.add_listener(addr, backlog)?; - *inner = Status::Listen(Listen::new(addr.clone(), init.is_nonblocking())); - return Ok(()); + let init = match &*self.0.read() { + State::Init(init) => init.clone(), + State::Listen(_) => { + return_errno_with_message!(Errno::EINVAL, "the socket is already listening") } - Status::Listen(_) => { - return_errno_with_message!(Errno::EINVAL, "the socket is already listened") - } - Status::Connected(_) => { - return_errno_with_message!(Errno::EINVAL, "the socket is already connected") + State::Connected(_) => { + return_errno_with_message!(Errno::EISCONN, "the socket is already connected") } }; + + let addr = init.addr().ok_or(Error::with_message( + Errno::EINVAL, + "the socket is not bound", + ))?; + + let listener = Listener::new(addr.clone(), backlog, init.is_nonblocking())?; + *self.0.write() = State::Listen(Arc::new(listener)); + Ok(()) } fn accept(&self) -> Result<(Arc, SocketAddr)> { - let inner = self.0.read(); - match &*inner { - Status::Listen(listen) => { - let is_nonblocking = listen.is_nonblocking(); - let addr = listen.addr().clone(); - drop(inner); - // Avoid lock when waiting - let connected = { - let local_endpoint = ACTIVE_LISTENERS.pop_incoming(is_nonblocking, &addr)?; - Connected::new(local_endpoint) - }; + let listen = match &*self.0.read() { + State::Listen(listen) => listen.clone(), + _ => return_errno_with_message!(Errno::EINVAL, "the socket is not listening"), + }; - let peer_addr = match connected.peer_addr() { - None => SocketAddr::Unix(String::new()), - Some(addr) => SocketAddr::from(addr.clone()), - }; - - let socket = UnixStreamSocket(RwLock::new(Status::Connected(connected))); - return Ok((Arc::new(socket), peer_addr)); - } - Status::Connected(_) | Status::Init(_) => { - return_errno_with_message!(Errno::EINVAL, "the socket is not listened") - } - } + listen.accept() } fn shutdown(&self, cmd: SockShutdownCmd) -> Result<()> { - let inner = self.0.read(); - if let Status::Connected(connected) = &*inner { - connected.shutdown(cmd) - } else { - return_errno_with_message!(Errno::ENOTCONN, "the socked is not connected"); - } + let connected = match &*self.0.read() { + State::Connected(connected) => connected.clone(), + _ => return_errno_with_message!(Errno::ENOTCONN, "the socked is not connected"), + }; + + connected.shutdown(cmd) } fn addr(&self) -> Result { - let inner = self.0.read(); - let addr = match &*inner { - Status::Init(init) => init.bound_addr().map(Clone::clone), - Status::Listen(listen) => Some(listen.addr().clone()), - Status::Connected(connected) => connected.addr(), + let addr = match &*self.0.read() { + State::Init(init) => init.addr(), + State::Listen(listen) => Some(listen.addr().clone()), + State::Connected(connected) => connected.addr(), }; + addr.map(Into::::into) .ok_or(Error::with_message( Errno::EINVAL, @@ -231,31 +227,28 @@ impl Socket for UnixStreamSocket { } fn peer_addr(&self) -> Result { - let inner = self.0.read(); - if let Status::Connected(connected) = &*inner { - match connected.peer_addr() { - None => return Ok(SocketAddr::Unix(String::new())), - Some(peer_addr) => { - return Ok(SocketAddr::from(peer_addr.clone())); - } + let connected = match &*self.0.read() { + State::Connected(connected) => connected.clone(), + _ => return_errno_with_message!(Errno::ENOTCONN, "the socket is not connected"), + }; + + match connected.peer_addr() { + None => return Ok(SocketAddr::Unix(UnixSocketAddr::Path(String::new()))), + Some(peer_addr) => { + return Ok(SocketAddr::from(peer_addr.clone())); } } - return_errno_with_message!(Errno::EINVAL, "the socket is not connected"); } fn recvfrom(&self, buf: &mut [u8], flags: SendRecvFlags) -> Result<(usize, SocketAddr)> { - let inner = self.0.read(); - // TODO: deal with flags - match &*inner { - Status::Connected(connected) => { - let read_size = connected.read(buf)?; - let peer_addr = self.peer_addr()?; - Ok((read_size, peer_addr)) - } - Status::Init(_) | Status::Listen(_) => { - return_errno_with_message!(Errno::EINVAL, "the socket is not connected") - } - } + let connected = match &*self.0.read() { + State::Connected(connected) => connected.clone(), + _ => return_errno_with_message!(Errno::ENOTCONN, "the socket is not connected"), + }; + + let peer_addr = self.peer_addr()?; + let read_size = connected.read(buf)?; + Ok((read_size, peer_addr)) } fn sendto( @@ -266,13 +259,12 @@ impl Socket for UnixStreamSocket { ) -> Result { debug_assert!(remote.is_none()); // TODO: deal with flags - let inner = self.0.read(); - match &*inner { - Status::Connected(connected) => connected.write(buf), - Status::Init(_) | Status::Listen(_) => { - return_errno_with_message!(Errno::EINVAL, "the socket is not connected") - } - } + let connected = match &*self.0.read() { + State::Connected(connected) => connected.clone(), + _ => return_errno_with_message!(Errno::ENOTCONN, "the socket is not connected"), + }; + + connected.write(buf) } } @@ -282,6 +274,26 @@ impl Drop for UnixStreamSocket { return; }; - ACTIVE_LISTENERS.remove_listener(&bound_addr); + if let State::Listen(_) = &*self.0.read() { + unregister_backlog(&bound_addr); + } } } + +fn lookup_socket_file(path: &str) -> Result> { + let dentry = { + let current = current!(); + let fs = current.fs().read(); + let fs_path = FsPath::try_from(path)?; + fs.lookup(&fs_path)? + }; + + if dentry.inode_type() != InodeType::Socket { + return_errno_with_message!(Errno::ENOTSOCK, "not a socket file") + } + + if !dentry.inode_mode().is_readable() || !dentry.inode_mode().is_writable() { + return_errno_with_message!(Errno::EACCES, "the socket cannot be read or written") + } + return Ok(dentry); +} diff --git a/services/libs/jinux-std/src/net/socket/util/send_recv_flags.rs b/services/libs/jinux-std/src/net/socket/util/send_recv_flags.rs index 497f3707f..a8f36077b 100644 --- a/services/libs/jinux-std/src/net/socket/util/send_recv_flags.rs +++ b/services/libs/jinux-std/src/net/socket/util/send_recv_flags.rs @@ -1,10 +1,10 @@ use crate::prelude::*; bitflags! { - #[repr(C)] - #[derive(Pod)] /// Flags used for send/recv. /// The definiton is from https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/socket.h + #[repr(C)] + #[derive(Pod)] pub struct SendRecvFlags: i32 { const MSG_OOB = 1; const MSG_PEEK = 2; diff --git a/services/libs/jinux-std/src/net/socket/util/shutdown_cmd.rs b/services/libs/jinux-std/src/net/socket/util/shutdown_cmd.rs index 374682f99..81fa84f9e 100644 --- a/services/libs/jinux-std/src/net/socket/util/shutdown_cmd.rs +++ b/services/libs/jinux-std/src/net/socket/util/shutdown_cmd.rs @@ -1,10 +1,10 @@ use crate::prelude::*; +/// Shutdown types +/// From https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/net.h #[repr(i32)] #[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromInt)] #[allow(non_camel_case_types)] -/// Shutdown types -/// From https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/net.h pub enum SockShutdownCmd { /// Shutdown receptions SHUT_RD = 0, diff --git a/services/libs/jinux-std/src/net/socket/util/sock_options.rs b/services/libs/jinux-std/src/net/socket/util/sock_options.rs index 0c75e1c2b..4e46083c4 100644 --- a/services/libs/jinux-std/src/net/socket/util/sock_options.rs +++ b/services/libs/jinux-std/src/net/socket/util/sock_options.rs @@ -1,10 +1,10 @@ use crate::prelude::*; +/// The definition is from https://elixir.bootlin.com/linux/v6.0.9/source/include/uapi/asm-generic/socket.h. +/// We do not include all options here #[repr(i32)] #[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq, PartialOrd, Ord)] #[allow(non_camel_case_types)] -/// The definition is from https://elixir.bootlin.com/linux/v6.0.9/source/include/uapi/asm-generic/socket.h. -/// We do not include all options here pub enum SockOptionName { SO_DEBUG = 1, SO_REUSEADDR = 2, @@ -27,10 +27,10 @@ pub enum SockOptionName { SO_SNDTIMEO_NEW = 67, } +/// Sock Opt level. The definition is from https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/socket.h#L343 #[repr(i32)] #[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq)] #[allow(non_camel_case_types)] -/// Sock Opt level. The definition is from https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/socket.h#L343 pub enum SockOptionLevel { SOL_IP = 0, SOL_SOCKET = 1, diff --git a/services/libs/jinux-std/src/net/socket/util/sockaddr.rs b/services/libs/jinux-std/src/net/socket/util/sockaddr.rs index b77d195de..b9b92c27d 100644 --- a/services/libs/jinux-std/src/net/socket/util/sockaddr.rs +++ b/services/libs/jinux-std/src/net/socket/util/sockaddr.rs @@ -1,12 +1,13 @@ use crate::net::iface::{IpAddress, Ipv4Address}; use crate::net::iface::{IpEndpoint, IpListenEndpoint}; +use crate::net::socket::unix::UnixSocketAddr; use crate::prelude::*; type PortNum = u16; #[derive(Debug)] pub enum SocketAddr { - Unix(String), + Unix(UnixSocketAddr), IPv4(Ipv4Address, PortNum), IPv6, } diff --git a/services/libs/jinux-std/src/prelude.rs b/services/libs/jinux-std/src/prelude.rs index df30599b4..da7c42dd7 100644 --- a/services/libs/jinux-std/src/prelude.rs +++ b/services/libs/jinux-std/src/prelude.rs @@ -19,12 +19,12 @@ pub(crate) use core::fmt::Debug; pub(crate) use int_to_c_enum::TryFromInt; pub(crate) use jinux_frame::config::PAGE_SIZE; // pub(crate) use jinux_frame::sync::{Mutex, MutexGuard}; +pub(crate) use jinux_frame::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; pub(crate) use jinux_frame::sync::{SpinLock, SpinLockGuard}; pub(crate) use jinux_frame::vm::Vaddr; pub(crate) use jinux_frame::{print, println}; pub(crate) use log::{debug, error, info, trace, warn}; pub(crate) use pod::Pod; -pub(crate) use spin::RwLock; pub(crate) use spin::{Mutex, MutexGuard}; /// return current process diff --git a/services/libs/jinux-std/src/process/signal/mod.rs b/services/libs/jinux-std/src/process/signal/mod.rs index 949c5b636..8bcdf913b 100644 --- a/services/libs/jinux-std/src/process/signal/mod.rs +++ b/services/libs/jinux-std/src/process/signal/mod.rs @@ -72,7 +72,7 @@ pub fn handle_pending_signal(context: &mut UserContext) -> Result<()> { SigDefaultAction::Core | SigDefaultAction::Term => { warn!( "{:?}: terminating on signal {}", - current.executable_path().read(), + &*current.executable_path().read(), sig_num.sig_name() ); // FIXME: How to set correct status if process is terminated diff --git a/services/libs/jinux-std/src/util/net/addr.rs b/services/libs/jinux-std/src/util/net/addr.rs index 1af19e824..bb1a0ac0a 100644 --- a/services/libs/jinux-std/src/util/net/addr.rs +++ b/services/libs/jinux-std/src/util/net/addr.rs @@ -1,4 +1,5 @@ use crate::net::iface::Ipv4Address; +use crate::net::socket::unix::UnixSocketAddr; use crate::net::socket::SocketAddr; use crate::prelude::*; use crate::util::{read_bytes_from_user, read_val_from_user, write_val_to_user}; @@ -22,12 +23,19 @@ pub fn read_socket_addr_from_user(addr: Vaddr, addr_len: usize) -> Result { debug_assert!(addr_len >= core::mem::size_of::()); @@ -58,7 +66,7 @@ pub fn write_socket_addr_to_user( let max_len = read_val_from_user::(addrlen_ptr)? as usize; let write_size = match socket_addr { SocketAddr::Unix(path) => { - let sock_addr_unix = SockAddrUnix::try_from(path.as_str())?; + let sock_addr_unix = SockAddrUnix::try_from(path)?; let write_size = core::mem::size_of::(); debug_assert!(max_len >= write_size); write_val_to_user(dest, &sock_addr_unix)?; @@ -80,9 +88,9 @@ pub fn write_socket_addr_to_user( Ok(()) } +/// PlaceHolder #[derive(Debug, Clone, Copy, Pod)] #[repr(C)] -/// PlaceHolder pub struct SockAddr { sa_family: u16, // SaFamily sa_data: [u8; 14], @@ -103,9 +111,9 @@ pub struct SockAddrUnix { sun_path: [u8; SOCK_ADDR_UNIX_LEN], } +/// IPv4 4-byte address #[repr(C)] #[derive(Debug, Clone, Copy, Pod)] -/// IPv4 4-byte address pub struct InetAddr { s_addr: [u8; 4], } @@ -140,9 +148,9 @@ impl PortNum { } } +/// IPv4 socket address #[repr(C)] #[derive(Debug, Clone, Copy, Pod)] -/// IPv4 socket address pub struct SockAddrInet { /// always SaFamily::AF_INET sin_family: u16, @@ -168,7 +176,6 @@ impl SockAddrInet { #[repr(C)] #[derive(Debug, Clone, Copy, Pod)] -/// IPv6 address pub struct Inet6Addr { s6_addr: [u8; 16], } @@ -278,17 +285,22 @@ impl From for SocketAddr { } } -impl TryFrom<&str> for SockAddrUnix { +impl TryFrom<&UnixSocketAddr> for SockAddrUnix { type Error = Error; - fn try_from(value: &str) -> Result { + fn try_from(value: &UnixSocketAddr) -> Result { let mut sun_path = [0u8; SOCK_ADDR_UNIX_LEN]; - let bytes = value.as_bytes(); - let copy_len = bytes.len().min(SOCK_ADDR_UNIX_LEN - 1); - sun_path[..copy_len].copy_from_slice(&bytes[..copy_len]); - Ok(SockAddrUnix { - sun_family: SaFamily::AF_UNIX as u16, - sun_path, - }) + match value { + UnixSocketAddr::Path(path) => { + let bytes = path.as_bytes(); + let copy_len = bytes.len().min(SOCK_ADDR_UNIX_LEN - 1); + sun_path[..copy_len].copy_from_slice(&bytes[..copy_len]); + Ok(SockAddrUnix { + sun_family: SaFamily::AF_UNIX as u16, + sun_path, + }) + } + UnixSocketAddr::Abstract(_) => todo!(), + } } } diff --git a/services/libs/jinux-std/src/util/net/socket.rs b/services/libs/jinux-std/src/util/net/socket.rs index 47f963be0..986d58794 100644 --- a/services/libs/jinux-std/src/util/net/socket.rs +++ b/services/libs/jinux-std/src/util/net/socket.rs @@ -1,10 +1,10 @@ use crate::prelude::*; +/// Standard well-defined IP protocols. +/// From https://elixir.bootlin.com/linux/v6.0.9/source/include/uapi/linux/in.h. #[repr(i32)] #[derive(Debug, Clone, Copy, TryFromInt)] #[allow(non_camel_case_types)] -/// Standard well-defined IP protocols. -/// From https://elixir.bootlin.com/linux/v6.0.9/source/include/uapi/linux/in.h. pub enum Protocol { IPPROTO_IP = 0, /* Dummy protocol for TCP */ IPPROTO_ICMP = 1, /* Internet Control Message Protocol */ @@ -34,11 +34,11 @@ pub enum Protocol { IPPROTO_MPTCP = 262, /* Multipath TCP connection */ } +/// Socket types. +/// From https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/net.h #[repr(i32)] #[allow(non_camel_case_types)] #[derive(Debug, Clone, Copy, TryFromInt)] -/// Socket types. -/// From https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/net.h pub enum SockType { /// Stream socket SOCK_STREAM = 1,