Refactor unix stream socket implementation

This commit is contained in:
Jianfeng Jiang
2023-08-09 15:10:33 +08:00
committed by Tate, Hongliang Tian
parent 93429ae2c9
commit 3f15bcaf5d
17 changed files with 495 additions and 421 deletions

View File

@ -378,6 +378,19 @@ impl RamInode {
}) })
} }
fn new_socket(fs: &Arc<RamFS>, mode: InodeMode) -> Arc<Self> {
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<RamFS>, mode: InodeMode) -> Arc<Self> { fn new_symlink(fs: &Arc<RamFS>, mode: InodeMode) -> Arc<Self> {
Arc::new_cyclic(|weak_self| { Arc::new_cyclic(|weak_self| {
let inode = RamInode(RwLock::new(Inode_::new_symlink( let inode = RamInode(RwLock::new(Inode_::new_symlink(
@ -494,29 +507,12 @@ impl Inode for RamInode {
let new_inode = match type_ { let new_inode = match type_ {
InodeType::File => RamInode::new_file(&fs, mode), InodeType::File => RamInode::new_file(&fs, mode),
InodeType::SymLink => RamInode::new_symlink(&fs, mode), InodeType::SymLink => RamInode::new_symlink(&fs, mode),
InodeType::Socket => RamInode::new_socket(&fs, mode),
InodeType::Dir => { InodeType::Dir => {
let dir_inode = RamInode::new_dir(&fs, mode, &self_inode.this); let dir_inode = RamInode::new_dir(&fs, mode, &self_inode.this);
self_inode.metadata.nlinks += 1; self_inode.metadata.nlinks += 1;
dir_inode 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"); panic!("unsupported inode type");
} }

View File

@ -1,88 +1,63 @@
use crate::{ use crate::fs::utils::Dentry;
fs::{ use crate::net::socket::util::sockaddr::SocketAddr;
fs_resolver::{split_path, FsPath}, use crate::prelude::*;
utils::{Dentry, InodeMode, InodeType},
}, #[derive(Clone, Debug, PartialEq, Eq)]
net::socket::util::sockaddr::SocketAddr, pub enum UnixSocketAddr {
prelude::*, Path(String),
}; Abstract(String),
}
#[derive(Clone)] #[derive(Clone)]
pub enum UnixSocketAddr { pub(super) enum UnixSocketAddrBound {
Bound(Arc<Dentry>), Path(Arc<Dentry>),
Unbound(String), 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<SocketAddr> for UnixSocketAddr { impl TryFrom<SocketAddr> for UnixSocketAddr {
type Error = Error; type Error = Error;
fn try_from(value: SocketAddr) -> Result<Self> { fn try_from(value: SocketAddr) -> Result<Self> {
let SocketAddr::Unix(path) = value else { match value {
return_errno_with_message!(Errno::EINVAL, "Invalid unix socket addr") SocketAddr::Unix(unix_socket_addr) => Ok(unix_socket_addr),
}; _ => return_errno_with_message!(Errno::EINVAL, "Invalid unix socket addr"),
Ok(Self::Unbound(path))
}
}
impl From<UnixSocketAddr> 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<Arc<Dentry>> {
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);
} }
} }
} }
pub fn path(&self) -> String { impl From<UnixSocketAddrBound> for UnixSocketAddr {
match self { fn from(value: UnixSocketAddrBound) -> Self {
UnixSocketAddr::Bound(dentry) => dentry.abs_path(), match value {
UnixSocketAddr::Unbound(path) => path.clone(), UnixSocketAddrBound::Path(dentry) => {
let abs_path = dentry.abs_path();
Self::Path(abs_path)
}
UnixSocketAddrBound::Abstract(name) => Self::Abstract(name),
} }
} }
} }
impl From<UnixSocketAddrBound> for SocketAddr {
fn from(value: UnixSocketAddrBound) -> Self {
let unix_socket_addr = UnixSocketAddr::from(value);
SocketAddr::Unix(unix_socket_addr)
}
}

View File

@ -1,55 +1,50 @@
use crate::{
net::socket::{unix::addr::UnixSocketAddr, SockShutdownCmd},
prelude::*,
};
use super::endpoint::Endpoint; 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<Endpoint>, local_endpoint: Arc<Endpoint>,
// The peer addr is None if peer is unnamed.
// FIXME: can a socket be bound after the socket is connected?
peer_addr: Option<UnixSocketAddr>,
} }
impl Connected { impl Connected {
pub fn new(local_endpoint: Arc<Endpoint>) -> Self { pub(super) fn new(local_endpoint: Arc<Endpoint>) -> Self {
let peer_addr = local_endpoint.peer_addr(); Connected { local_endpoint }
Connected {
local_endpoint,
peer_addr,
}
} }
pub fn addr(&self) -> Option<UnixSocketAddr> { pub(super) fn addr(&self) -> Option<UnixSocketAddrBound> {
self.local_endpoint.addr() self.local_endpoint.addr()
} }
pub fn peer_addr(&self) -> Option<&UnixSocketAddr> { pub(super) fn peer_addr(&self) -> Option<UnixSocketAddrBound> {
self.peer_addr.as_ref() self.local_endpoint.peer_addr()
} }
pub fn is_bound(&self) -> bool { pub(super) fn is_bound(&self) -> bool {
self.addr().is_some() self.addr().is_some()
} }
pub fn write(&self, buf: &[u8]) -> Result<usize> { pub(super) fn write(&self, buf: &[u8]) -> Result<usize> {
self.local_endpoint.write(buf) self.local_endpoint.write(buf)
} }
pub fn read(&self, buf: &mut [u8]) -> Result<usize> { pub(super) fn read(&self, buf: &mut [u8]) -> Result<usize> {
self.local_endpoint.read(buf) 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) self.local_endpoint.shutdown(cmd)
} }
pub fn is_nonblocking(&self) -> bool { pub(super) fn is_nonblocking(&self) -> bool {
self.local_endpoint.is_nonblocking() 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(); 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)
}
} }

View File

@ -1,20 +1,20 @@
use crate::{ use crate::{
fs::utils::{Channel, Consumer, IoEvents, Poller, Producer, StatusFlags}, fs::utils::{Channel, Consumer, IoEvents, Poller, Producer, StatusFlags},
net::socket::{unix::addr::UnixSocketAddr, SockShutdownCmd}, net::socket::{unix::addr::UnixSocketAddrBound, SockShutdownCmd},
prelude::*, prelude::*,
}; };
pub struct Endpoint(Inner); pub(super) struct Endpoint(Inner);
struct Inner { struct Inner {
addr: RwLock<Option<UnixSocketAddr>>, addr: RwLock<Option<UnixSocketAddrBound>>,
reader: Consumer<u8>, reader: Consumer<u8>,
writer: Producer<u8>, writer: Producer<u8>,
peer: Weak<Endpoint>, peer: Weak<Endpoint>,
} }
impl Endpoint { impl Endpoint {
pub fn end_pair(is_nonblocking: bool) -> Result<(Arc<Endpoint>, Arc<Endpoint>)> { pub(super) fn new_pair(is_nonblocking: bool) -> Result<(Arc<Endpoint>, Arc<Endpoint>)> {
let flags = if is_nonblocking { let flags = if is_nonblocking {
StatusFlags::O_NONBLOCK StatusFlags::O_NONBLOCK
} else { } else {
@ -43,26 +43,26 @@ impl Endpoint {
}) })
} }
pub fn addr(&self) -> Option<UnixSocketAddr> { pub(super) fn addr(&self) -> Option<UnixSocketAddrBound> {
self.0.addr.read().clone() 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); *self.0.addr.write() = Some(addr);
} }
pub fn peer_addr(&self) -> Option<UnixSocketAddr> { pub(super) fn peer_addr(&self) -> Option<UnixSocketAddrBound> {
self.0.peer.upgrade().map(|peer| peer.addr()).flatten() 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 reader_status = self.0.reader.is_nonblocking();
let writer_status = self.0.writer.is_nonblocking(); let writer_status = self.0.writer.is_nonblocking();
debug_assert!(reader_status == writer_status); debug_assert!(reader_status == writer_status);
reader_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(); let reader_flags = self.0.reader.status_flags();
self.0 self.0
.reader .reader
@ -74,15 +74,15 @@ impl Endpoint {
Ok(()) Ok(())
} }
pub fn read(&self, buf: &mut [u8]) -> Result<usize> { pub(super) fn read(&self, buf: &mut [u8]) -> Result<usize> {
self.0.reader.read(buf) self.0.reader.read(buf)
} }
pub fn write(&self, buf: &[u8]) -> Result<usize> { pub(super) fn write(&self, buf: &[u8]) -> Result<usize> {
self.0.writer.write(buf) self.0.writer.write(buf)
} }
pub fn shutdown(&self, cmd: SockShutdownCmd) -> Result<()> { pub(super) fn shutdown(&self, cmd: SockShutdownCmd) -> Result<()> {
if !self.is_connected() { if !self.is_connected() {
return_errno_with_message!(Errno::ENOTCONN, "The socket is not connected."); return_errno_with_message!(Errno::ENOTCONN, "The socket is not connected.");
} }
@ -98,11 +98,11 @@ impl Endpoint {
Ok(()) Ok(())
} }
pub fn is_connected(&self) -> bool { pub(super) fn is_connected(&self) -> bool {
self.0.peer.upgrade().is_some() 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(); let mut events = IoEvents::empty();
// FIXME: should reader and writer use the same mask? // FIXME: should reader and writer use the same mask?
let reader_events = self.0.reader.poll(mask, poller); let reader_events = self.0.reader.poll(mask, poller);

View File

@ -1,50 +1,99 @@
use core::sync::atomic::{AtomicBool, Ordering}; use core::sync::atomic::{AtomicBool, Ordering};
use crate::fs::utils::{IoEvents, Pollee, Poller}; use crate::fs::fs_resolver::{split_path, FsPath};
use crate::net::socket::unix::addr::UnixSocketAddr; use crate::fs::utils::{Dentry, InodeMode, InodeType, IoEvents, Pollee, Poller};
use crate::net::socket::unix::addr::{UnixSocketAddr, UnixSocketAddrBound};
use crate::prelude::*; 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, is_nonblocking: AtomicBool,
bind_addr: Option<UnixSocketAddr>, addr: Mutex<Option<UnixSocketAddrBound>>,
pollee: Pollee, pollee: Pollee,
} }
impl Init { impl Init {
pub fn new(is_nonblocking: bool) -> Self { pub(super) fn new(is_nonblocking: bool) -> Self {
Self { Self {
is_nonblocking: AtomicBool::new(is_nonblocking), is_nonblocking: AtomicBool::new(is_nonblocking),
bind_addr: None, addr: Mutex::new(None),
pollee: Pollee::new(IoEvents::empty()), pollee: Pollee::new(IoEvents::empty()),
} }
} }
pub fn bind(&mut self, mut addr: UnixSocketAddr) -> Result<()> { pub(super) fn bind(&self, addr_to_bind: &UnixSocketAddr) -> Result<()> {
if self.bind_addr.is_some() { let mut addr = self.addr.lock();
if addr.is_some() {
return_errno_with_message!(Errno::EINVAL, "the socket is already bound"); 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(()) Ok(())
} }
pub fn is_bound(&self) -> bool { pub(super) fn connect(&self, remote_addr: &UnixSocketAddrBound) -> Result<Connected> {
self.bind_addr.is_none() 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");
}
} }
pub fn bound_addr(&self) -> Option<&UnixSocketAddr> { let (this_end, remote_end) = Endpoint::new_pair(self.is_nonblocking())?;
self.bind_addr.as_ref() 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 is_nonblocking(&self) -> bool { pub(super) fn is_bound(&self) -> bool {
self.addr.lock().is_some()
}
pub(super) fn addr(&self) -> Option<UnixSocketAddrBound> {
self.addr.lock().clone()
}
pub(super) fn is_nonblocking(&self) -> bool {
self.is_nonblocking.load(Ordering::Acquire) 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); 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) self.pollee.poll(mask, poller)
} }
} }
fn create_socket_file(path: &str) -> Result<Arc<Dentry>> {
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)
}

View File

@ -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);
}
}

View File

@ -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 keyable_arc::KeyableWeak;
use spin::RwLockReadGuard;
use crate::{ pub(super) struct Listener {
fs::utils::{Inode, IoEvents, Pollee, Poller}, addr: UnixSocketAddrBound,
net::socket::unix::addr::UnixSocketAddr, is_nonblocking: AtomicBool,
prelude::*, }
impl Listener {
pub(super) fn new(
addr: UnixSocketAddrBound,
backlog: usize,
nonblocking: bool,
) -> Result<Self> {
BACKLOG_TABLE.add_backlog(&addr, backlog)?;
Ok(Self {
addr,
is_nonblocking: AtomicBool::new(nonblocking),
})
}
pub(super) fn addr(&self) -> &UnixSocketAddrBound {
&self.addr
}
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<dyn FileLike>, 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)
}; };
use super::endpoint::Endpoint; let peer_addr = match connected.peer_addr() {
None => SocketAddr::Unix(UnixSocketAddr::Path(String::new())),
Some(addr) => SocketAddr::from(addr.clone()),
};
pub static ACTIVE_LISTENERS: ActiveListeners = ActiveListeners::new(); let socket = Arc::new(UnixStreamSocket::new_connected(connected));
pub struct ActiveListeners { Ok((socket, peer_addr))
listeners: RwLock<BTreeMap<KeyableWeak<dyn Inode>, Arc<Listener>>>, }
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<BTreeMap<KeyableWeak<dyn Inode>, Arc<Backlog>>>,
// TODO: For linux, there is also abstract socket domain that a socket addr is not bound to an inode. // TODO: For linux, there is also abstract socket domain that a socket addr is not bound to an inode.
} }
impl ActiveListeners { impl BacklogTable {
pub const fn new() -> Self { const fn new() -> Self {
Self { Self {
listeners: RwLock::new(BTreeMap::new()), backlog_sockets: RwLock::new(BTreeMap::new()),
} }
} }
pub(super) fn add_listener(&self, addr: &UnixSocketAddr, backlog: usize) -> Result<()> { fn add_backlog(&self, addr: &UnixSocketAddrBound, backlog: usize) -> Result<()> {
let inode = create_keyable_inode(addr)?; let inode = {
let mut listeners = self.listeners.write(); let UnixSocketAddrBound::Path(dentry) = addr else {
if listeners.contains_key(&inode) { 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"); return_errno_with_message!(Errno::EADDRINUSE, "the addr is already used");
} }
let new_listener = Arc::new(Listener::new(backlog)); let new_backlog = Arc::new(Backlog::new(backlog));
listeners.insert(inode, new_listener); backlog_sockets.insert(inode, new_backlog);
Ok(()) Ok(())
} }
pub(super) fn get_listener(&self, addr: &UnixSocketAddr) -> Result<Arc<Listener>> { fn get_backlog(&self, addr: &UnixSocketAddrBound) -> Result<Arc<Backlog>> {
let listeners = self.listeners.read(); let inode = {
get_listener(&listeners, addr) 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( fn pop_incoming(&self, nonblocking: bool, addr: &UnixSocketAddrBound) -> Result<Arc<Endpoint>> {
&self,
nonblocking: bool,
addr: &UnixSocketAddr,
) -> Result<Arc<Endpoint>> {
let poller = Poller::new(); let poller = Poller::new();
loop { loop {
let listener = { let backlog = self.get_backlog(addr)?;
let listeners = self.listeners.read();
get_listener(&listeners, addr)? if let Some(endpoint) = backlog.pop_incoming() {
};
if let Some(endpoint) = listener.pop_incoming() {
return Ok(endpoint); return Ok(endpoint);
} }
if nonblocking { if nonblocking {
return_errno_with_message!(Errno::EAGAIN, "no connection comes"); return_errno_with_message!(Errno::EAGAIN, "no connection comes");
} }
let events = { let events = {
let mask = IoEvents::IN; let mask = IoEvents::IN;
listener.poll(mask, Some(&poller)) backlog.poll(mask, Some(&poller))
}; };
if events.contains(IoEvents::ERR) | events.contains(IoEvents::HUP) { 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() { if events.is_empty() {
poller.wait(); poller.wait();
} }
} }
} }
pub(super) fn push_incoming( fn push_incoming(&self, addr: &UnixSocketAddrBound, endpoint: Arc<Endpoint>) -> Result<()> {
&self, let backlog = self.get_backlog(addr).map_err(|_| {
addr: &UnixSocketAddr,
endpoint: Arc<Endpoint>,
) -> Result<()> {
let listeners = self.listeners.read();
let listener = get_listener(&listeners, addr).map_err(|_| {
Error::with_message( Error::with_message(
Errno::ECONNREFUSED, Errno::ECONNREFUSED,
"no socket is listened at the remote address", "no socket is listened at the remote address",
) )
})?; })?;
listener.push_incoming(endpoint)
backlog.push_incoming(endpoint)
} }
pub(super) fn remove_listener(&self, addr: &UnixSocketAddr) { fn remove_backlog(&self, addr: &UnixSocketAddrBound) {
let Ok(inode) = create_keyable_inode(addr) else { let UnixSocketAddrBound::Path(dentry) = addr else {
return; todo!()
}; };
self.listeners.write().remove(&inode);
let inode = create_keyable_inode(dentry);
self.backlog_sockets.write().remove(&inode);
} }
} }
fn get_listener( struct Backlog {
listeners: &RwLockReadGuard<BTreeMap<KeyableWeak<dyn Inode>, Arc<Listener>>>,
addr: &UnixSocketAddr,
) -> Result<Arc<Listener>> {
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 {
pollee: Pollee, pollee: Pollee,
backlog: usize, backlog: usize,
incoming_endpoints: Mutex<VecDeque<Arc<Endpoint>>>, incoming_endpoints: Mutex<VecDeque<Arc<Endpoint>>>,
} }
impl Listener { impl Backlog {
pub fn new(backlog: usize) -> Self { fn new(backlog: usize) -> Self {
Self { Self {
pollee: Pollee::new(IoEvents::empty()), pollee: Pollee::new(IoEvents::empty()),
backlog, backlog,
@ -118,7 +173,7 @@ impl Listener {
} }
} }
pub fn push_incoming(&self, endpoint: Arc<Endpoint>) -> Result<()> { fn push_incoming(&self, endpoint: Arc<Endpoint>) -> Result<()> {
let mut endpoints = self.incoming_endpoints.lock(); let mut endpoints = self.incoming_endpoints.lock();
if endpoints.len() >= self.backlog { if endpoints.len() >= self.backlog {
return_errno_with_message!(Errno::ECONNREFUSED, "incoming_endpoints is full"); return_errno_with_message!(Errno::ECONNREFUSED, "incoming_endpoints is full");
@ -128,24 +183,34 @@ impl Listener {
Ok(()) Ok(())
} }
pub fn pop_incoming(&self) -> Option<Arc<Endpoint>> { fn pop_incoming(&self) -> Option<Arc<Endpoint>> {
let mut incoming_endpoints = self.incoming_endpoints.lock(); let mut incoming_endpoints = self.incoming_endpoints.lock();
let endpoint = incoming_endpoints.pop_front(); let endpoint = incoming_endpoints.pop_front();
if endpoint.is_none() { if incoming_endpoints.is_empty() {
self.pollee.del_events(IoEvents::IN); self.pollee.del_events(IoEvents::IN);
} }
endpoint 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 // Lock to avoid any events may change pollee state when we poll
let _lock = self.incoming_endpoints.lock(); let _lock = self.incoming_endpoints.lock();
self.pollee.poll(mask, poller) self.pollee.poll(mask, poller)
} }
} }
fn create_keyable_inode(addr: &UnixSocketAddr) -> Result<KeyableWeak<dyn Inode>> { fn create_keyable_inode(dentry: &Arc<Dentry>) -> KeyableWeak<dyn Inode> {
let dentry = addr.dentry()?;
let inode = dentry.inode(); 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<Endpoint>,
) -> Result<()> {
BACKLOG_TABLE.push_incoming(remote_addr, remote_end)
} }

View File

@ -1,9 +1,7 @@
mod connected; mod connected;
mod endpoint; mod endpoint;
mod init; mod init;
mod listen;
mod listener; mod listener;
pub mod stream; mod stream;
pub use listener::{ActiveListeners, ACTIVE_LISTENERS};
pub use stream::UnixStreamSocket; pub use stream::UnixStreamSocket;

View File

@ -1,6 +1,8 @@
use crate::fs::file_handle::FileLike; use crate::fs::file_handle::FileLike;
use crate::fs::utils::{IoEvents, Poller, StatusFlags}; use crate::fs::fs_resolver::FsPath;
use crate::net::socket::unix::addr::UnixSocketAddr; 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::send_recv_flags::SendRecvFlags;
use crate::net::socket::util::sockaddr::SocketAddr; use crate::net::socket::util::sockaddr::SocketAddr;
use crate::net::socket::{SockShutdownCmd, Socket}; use crate::net::socket::{SockShutdownCmd, Socket};
@ -9,40 +11,59 @@ use crate::prelude::*;
use super::connected::Connected; use super::connected::Connected;
use super::endpoint::Endpoint; use super::endpoint::Endpoint;
use super::init::Init; use super::init::Init;
use super::listen::Listen; use super::listener::{unregister_backlog, Listener};
use super::ACTIVE_LISTENERS;
pub struct UnixStreamSocket(RwLock<Status>); pub struct UnixStreamSocket(RwLock<State>);
enum Status { impl UnixStreamSocket {
Init(Init), pub(super) fn new_init(init: Init) -> Self {
Listen(Listen), Self(RwLock::new(State::Init(Arc::new(init))))
Connected(Connected), }
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<Init>),
Listen(Arc<Listener>),
Connected(Arc<Connected>),
} }
impl UnixStreamSocket { impl UnixStreamSocket {
pub fn new(nonblocking: bool) -> Self { pub fn new(nonblocking: bool) -> Self {
let status = Status::Init(Init::new(nonblocking)); let init = Init::new(nonblocking);
Self(RwLock::new(status)) Self::new_init(init)
} }
pub fn new_pair(nonblocking: bool) -> Result<(Arc<Self>, Arc<Self>)> { pub fn new_pair(nonblocking: bool) -> Result<(Arc<Self>, Arc<Self>)> {
let (end_a, end_b) = Endpoint::end_pair(nonblocking)?; let (end_a, end_b) = Endpoint::new_pair(nonblocking)?;
let connected_a = UnixStreamSocket(RwLock::new(Status::Connected(Connected::new(end_a)))); let connected_a = {
let connected_b = UnixStreamSocket(RwLock::new(Status::Connected(Connected::new(end_b)))); 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))) Ok((Arc::new(connected_a), Arc::new(connected_b)))
} }
fn bound_addr(&self) -> Option<UnixSocketAddr> { fn bound_addr(&self) -> Option<UnixSocketAddrBound> {
let status = self.0.read(); let status = self.0.read();
match &*status { match &*status {
Status::Init(init) => init.bound_addr().map(Clone::clone), State::Init(init) => init.addr(),
Status::Listen(listen) => Some(listen.addr().clone()), State::Listen(listen) => Some(listen.addr().clone()),
Status::Connected(connected) => connected.addr(), 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 SUPPORTED_FLAGS: StatusFlags = StatusFlags::O_NONBLOCK;
const UNSUPPORTED_FLAGS: StatusFlags = SUPPORTED_FLAGS.complement(); const UNSUPPORTED_FLAGS: StatusFlags = SUPPORTED_FLAGS.complement();
@ -71,22 +92,18 @@ impl FileLike for UnixStreamSocket {
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
let inner = self.0.read(); let inner = self.0.read();
match &*inner { match &*inner {
Status::Init(init) => init.poll(mask, poller), State::Init(init) => init.poll(mask, poller),
Status::Listen(listen) => { State::Listen(listen) => listen.poll(mask, poller),
let addr = listen.addr(); State::Connected(connected) => connected.poll(mask, poller),
let listener = ACTIVE_LISTENERS.get_listener(addr).unwrap();
listener.poll(mask, poller)
}
Status::Connected(connet) => todo!(),
} }
} }
fn status_flags(&self) -> StatusFlags { fn status_flags(&self) -> StatusFlags {
let inner = self.0.read(); let inner = self.0.read();
let is_nonblocking = match &*inner { let is_nonblocking = match &*inner {
Status::Init(init) => init.is_nonblocking(), State::Init(init) => init.is_nonblocking(),
Status::Listen(listen) => listen.is_nonblocking(), State::Listen(listen) => listen.is_nonblocking(),
Status::Connected(connected) => connected.is_nonblocking(), State::Connected(connected) => connected.is_nonblocking(),
}; };
if is_nonblocking { if is_nonblocking {
@ -98,15 +115,15 @@ impl FileLike for UnixStreamSocket {
fn set_status_flags(&self, new_flags: StatusFlags) -> Result<()> { fn set_status_flags(&self, new_flags: StatusFlags) -> Result<()> {
let is_nonblocking = { 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) supported_flags.contains(StatusFlags::O_NONBLOCK)
}; };
let mut inner = self.0.write(); let mut inner = self.0.write();
match &mut *inner { match &mut *inner {
Status::Init(init) => init.set_nonblocking(is_nonblocking), State::Init(init) => init.set_nonblocking(is_nonblocking),
Status::Listen(listen) => listen.set_nonblocking(is_nonblocking), State::Listen(listen) => listen.set_nonblocking(is_nonblocking),
Status::Connected(connected) => connected.set_nonblocking(is_nonblocking), State::Connected(connected) => connected.set_nonblocking(is_nonblocking),
} }
Ok(()) Ok(())
} }
@ -115,114 +132,93 @@ impl FileLike for UnixStreamSocket {
impl Socket for UnixStreamSocket { impl Socket for UnixStreamSocket {
fn bind(&self, sockaddr: SocketAddr) -> Result<()> { fn bind(&self, sockaddr: SocketAddr) -> Result<()> {
let addr = UnixSocketAddr::try_from(sockaddr)?; let addr = UnixSocketAddr::try_from(sockaddr)?;
let mut inner = self.0.write();
match &mut *inner { let init = match &*self.0.read() {
Status::Init(init) => init.bind(addr), State::Init(init) => init.clone(),
Status::Listen(_) | Status::Connected(_) => { _ => return_errno_with_message!(
return_errno_with_message!(
Errno::EINVAL, Errno::EINVAL,
"cannot bind a listening or connected socket" "cannot bind a listening or connected socket"
); ),
} // FIXME: Maybe binding a connected sockted should also be allowed? // FIXME: Maybe binding a connected socket should also be allowed?
} };
init.bind(&addr)
} }
fn connect(&self, sockaddr: SocketAddr) -> Result<()> { fn connect(&self, sockaddr: SocketAddr) -> Result<()> {
let mut inner = self.0.write(); let remote_addr = {
match &*inner { let unix_socket_addr = UnixSocketAddr::try_from(sockaddr)?;
Status::Init(init) => { match unix_socket_addr {
let remote_addr = UnixSocketAddr::try_from(sockaddr)?; UnixSocketAddr::Abstract(abstract_name) => {
let addr = init.bound_addr(); UnixSocketAddrBound::Abstract(abstract_name)
if let Some(addr) = addr { }
if addr.path() == remote_addr.path() { UnixSocketAddr::Path(path) => {
return_errno_with_message!( let dentry = lookup_socket_file(&path)?;
Errno::EINVAL, UnixSocketAddrBound::Path(dentry)
"try to connect to self is invalid"
);
} }
} }
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)); let init = match &*self.0.read() {
Ok(()) State::Init(init) => init.clone(),
} State::Listen(_) => return_errno_with_message!(Errno::EINVAL, "the socket is listened"),
Status::Listen(_) => { State::Connected(_) => {
return_errno_with_message!(Errno::EINVAL, "the socket is listened")
}
Status::Connected(_) => {
return_errno_with_message!(Errno::EISCONN, "the socket is 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<()> { fn listen(&self, backlog: usize) -> Result<()> {
let mut inner = self.0.write(); let init = match &*self.0.read() {
match &*inner { State::Init(init) => init.clone(),
Status::Init(init) => { State::Listen(_) => {
let addr = init.bound_addr().ok_or(Error::with_message( return_errno_with_message!(Errno::EINVAL, "the socket is already listening")
}
State::Connected(_) => {
return_errno_with_message!(Errno::EISCONN, "the socket is already connected")
}
};
let addr = init.addr().ok_or(Error::with_message(
Errno::EINVAL, Errno::EINVAL,
"the socket is not bound", "the socket is not bound",
))?; ))?;
ACTIVE_LISTENERS.add_listener(addr, backlog)?;
*inner = Status::Listen(Listen::new(addr.clone(), init.is_nonblocking())); let listener = Listener::new(addr.clone(), backlog, init.is_nonblocking())?;
return Ok(()); *self.0.write() = State::Listen(Arc::new(listener));
} Ok(())
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")
}
};
} }
fn accept(&self) -> Result<(Arc<dyn FileLike>, SocketAddr)> { fn accept(&self) -> Result<(Arc<dyn FileLike>, SocketAddr)> {
let inner = self.0.read(); let listen = match &*self.0.read() {
match &*inner { State::Listen(listen) => listen.clone(),
Status::Listen(listen) => { _ => return_errno_with_message!(Errno::EINVAL, "the socket is not listening"),
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 peer_addr = match connected.peer_addr() { listen.accept()
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")
}
}
} }
fn shutdown(&self, cmd: SockShutdownCmd) -> Result<()> { fn shutdown(&self, cmd: SockShutdownCmd) -> Result<()> {
let inner = self.0.read(); let connected = match &*self.0.read() {
if let Status::Connected(connected) = &*inner { State::Connected(connected) => connected.clone(),
_ => return_errno_with_message!(Errno::ENOTCONN, "the socked is not connected"),
};
connected.shutdown(cmd) connected.shutdown(cmd)
} else {
return_errno_with_message!(Errno::ENOTCONN, "the socked is not connected");
}
} }
fn addr(&self) -> Result<SocketAddr> { fn addr(&self) -> Result<SocketAddr> {
let inner = self.0.read(); let addr = match &*self.0.read() {
let addr = match &*inner { State::Init(init) => init.addr(),
Status::Init(init) => init.bound_addr().map(Clone::clone), State::Listen(listen) => Some(listen.addr().clone()),
Status::Listen(listen) => Some(listen.addr().clone()), State::Connected(connected) => connected.addr(),
Status::Connected(connected) => connected.addr(),
}; };
addr.map(Into::<SocketAddr>::into) addr.map(Into::<SocketAddr>::into)
.ok_or(Error::with_message( .ok_or(Error::with_message(
Errno::EINVAL, Errno::EINVAL,
@ -231,32 +227,29 @@ impl Socket for UnixStreamSocket {
} }
fn peer_addr(&self) -> Result<SocketAddr> { fn peer_addr(&self) -> Result<SocketAddr> {
let inner = self.0.read(); let connected = match &*self.0.read() {
if let Status::Connected(connected) = &*inner { State::Connected(connected) => connected.clone(),
_ => return_errno_with_message!(Errno::ENOTCONN, "the socket is not connected"),
};
match connected.peer_addr() { match connected.peer_addr() {
None => return Ok(SocketAddr::Unix(String::new())), None => return Ok(SocketAddr::Unix(UnixSocketAddr::Path(String::new()))),
Some(peer_addr) => { Some(peer_addr) => {
return Ok(SocketAddr::from(peer_addr.clone())); 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)> { fn recvfrom(&self, buf: &mut [u8], flags: SendRecvFlags) -> Result<(usize, SocketAddr)> {
let inner = self.0.read(); let connected = match &*self.0.read() {
// TODO: deal with flags State::Connected(connected) => connected.clone(),
match &*inner { _ => return_errno_with_message!(Errno::ENOTCONN, "the socket is not connected"),
Status::Connected(connected) => { };
let read_size = connected.read(buf)?;
let peer_addr = self.peer_addr()?; let peer_addr = self.peer_addr()?;
let read_size = connected.read(buf)?;
Ok((read_size, peer_addr)) Ok((read_size, peer_addr))
} }
Status::Init(_) | Status::Listen(_) => {
return_errno_with_message!(Errno::EINVAL, "the socket is not connected")
}
}
}
fn sendto( fn sendto(
&self, &self,
@ -266,13 +259,12 @@ impl Socket for UnixStreamSocket {
) -> Result<usize> { ) -> Result<usize> {
debug_assert!(remote.is_none()); debug_assert!(remote.is_none());
// TODO: deal with flags // TODO: deal with flags
let inner = self.0.read(); let connected = match &*self.0.read() {
match &*inner { State::Connected(connected) => connected.clone(),
Status::Connected(connected) => connected.write(buf), _ => return_errno_with_message!(Errno::ENOTCONN, "the socket is not connected"),
Status::Init(_) | Status::Listen(_) => { };
return_errno_with_message!(Errno::EINVAL, "the socket is not connected")
} connected.write(buf)
}
} }
} }
@ -282,6 +274,26 @@ impl Drop for UnixStreamSocket {
return; 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<Arc<Dentry>> {
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);
}

View File

@ -1,10 +1,10 @@
use crate::prelude::*; use crate::prelude::*;
bitflags! { bitflags! {
#[repr(C)]
#[derive(Pod)]
/// Flags used for send/recv. /// Flags used for send/recv.
/// The definiton is from https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/socket.h /// 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 { pub struct SendRecvFlags: i32 {
const MSG_OOB = 1; const MSG_OOB = 1;
const MSG_PEEK = 2; const MSG_PEEK = 2;

View File

@ -1,10 +1,10 @@
use crate::prelude::*; use crate::prelude::*;
/// Shutdown types
/// From https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/net.h
#[repr(i32)] #[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromInt)] #[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromInt)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
/// Shutdown types
/// From https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/net.h
pub enum SockShutdownCmd { pub enum SockShutdownCmd {
/// Shutdown receptions /// Shutdown receptions
SHUT_RD = 0, SHUT_RD = 0,

View File

@ -1,10 +1,10 @@
use crate::prelude::*; 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)] #[repr(i32)]
#[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq, PartialOrd, Ord)]
#[allow(non_camel_case_types)] #[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 { pub enum SockOptionName {
SO_DEBUG = 1, SO_DEBUG = 1,
SO_REUSEADDR = 2, SO_REUSEADDR = 2,
@ -27,10 +27,10 @@ pub enum SockOptionName {
SO_SNDTIMEO_NEW = 67, 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)] #[repr(i32)]
#[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq)] #[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq)]
#[allow(non_camel_case_types)] #[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 { pub enum SockOptionLevel {
SOL_IP = 0, SOL_IP = 0,
SOL_SOCKET = 1, SOL_SOCKET = 1,

View File

@ -1,12 +1,13 @@
use crate::net::iface::{IpAddress, Ipv4Address}; use crate::net::iface::{IpAddress, Ipv4Address};
use crate::net::iface::{IpEndpoint, IpListenEndpoint}; use crate::net::iface::{IpEndpoint, IpListenEndpoint};
use crate::net::socket::unix::UnixSocketAddr;
use crate::prelude::*; use crate::prelude::*;
type PortNum = u16; type PortNum = u16;
#[derive(Debug)] #[derive(Debug)]
pub enum SocketAddr { pub enum SocketAddr {
Unix(String), Unix(UnixSocketAddr),
IPv4(Ipv4Address, PortNum), IPv4(Ipv4Address, PortNum),
IPv6, IPv6,
} }

View File

@ -19,12 +19,12 @@ pub(crate) use core::fmt::Debug;
pub(crate) use int_to_c_enum::TryFromInt; pub(crate) use int_to_c_enum::TryFromInt;
pub(crate) use jinux_frame::config::PAGE_SIZE; pub(crate) use jinux_frame::config::PAGE_SIZE;
// pub(crate) use jinux_frame::sync::{Mutex, MutexGuard}; // 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::sync::{SpinLock, SpinLockGuard};
pub(crate) use jinux_frame::vm::Vaddr; pub(crate) use jinux_frame::vm::Vaddr;
pub(crate) use jinux_frame::{print, println}; pub(crate) use jinux_frame::{print, println};
pub(crate) use log::{debug, error, info, trace, warn}; pub(crate) use log::{debug, error, info, trace, warn};
pub(crate) use pod::Pod; pub(crate) use pod::Pod;
pub(crate) use spin::RwLock;
pub(crate) use spin::{Mutex, MutexGuard}; pub(crate) use spin::{Mutex, MutexGuard};
/// return current process /// return current process

View File

@ -72,7 +72,7 @@ pub fn handle_pending_signal(context: &mut UserContext) -> Result<()> {
SigDefaultAction::Core | SigDefaultAction::Term => { SigDefaultAction::Core | SigDefaultAction::Term => {
warn!( warn!(
"{:?}: terminating on signal {}", "{:?}: terminating on signal {}",
current.executable_path().read(), &*current.executable_path().read(),
sig_num.sig_name() sig_num.sig_name()
); );
// FIXME: How to set correct status if process is terminated // FIXME: How to set correct status if process is terminated

View File

@ -1,4 +1,5 @@
use crate::net::iface::Ipv4Address; use crate::net::iface::Ipv4Address;
use crate::net::socket::unix::UnixSocketAddr;
use crate::net::socket::SocketAddr; use crate::net::socket::SocketAddr;
use crate::prelude::*; use crate::prelude::*;
use crate::util::{read_bytes_from_user, read_val_from_user, write_val_to_user}; 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<Socket
bytes bytes
}; };
let path = { let unix_socket_addr = if bytes.starts_with(&[0]) {
// Abstract unix socket addr
let cstr = CStr::from_bytes_until_nul(&bytes[1..])?;
let abstract_path = cstr.to_string_lossy().to_string();
UnixSocketAddr::Abstract(abstract_path)
} else {
// Normal unix sockket addr
let cstr = CStr::from_bytes_until_nul(&bytes)?; let cstr = CStr::from_bytes_until_nul(&bytes)?;
cstr.to_string_lossy().to_string() let path = cstr.to_string_lossy().to_string();
UnixSocketAddr::Path(path)
}; };
SocketAddr::Unix(path) SocketAddr::Unix(unix_socket_addr)
} }
SaFamily::AF_INET => { SaFamily::AF_INET => {
debug_assert!(addr_len >= core::mem::size_of::<SockAddrInet>()); debug_assert!(addr_len >= core::mem::size_of::<SockAddrInet>());
@ -58,7 +66,7 @@ pub fn write_socket_addr_to_user(
let max_len = read_val_from_user::<i32>(addrlen_ptr)? as usize; let max_len = read_val_from_user::<i32>(addrlen_ptr)? as usize;
let write_size = match socket_addr { let write_size = match socket_addr {
SocketAddr::Unix(path) => { 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::<SockAddrUnix>(); let write_size = core::mem::size_of::<SockAddrUnix>();
debug_assert!(max_len >= write_size); debug_assert!(max_len >= write_size);
write_val_to_user(dest, &sock_addr_unix)?; write_val_to_user(dest, &sock_addr_unix)?;
@ -80,9 +88,9 @@ pub fn write_socket_addr_to_user(
Ok(()) Ok(())
} }
/// PlaceHolder
#[derive(Debug, Clone, Copy, Pod)] #[derive(Debug, Clone, Copy, Pod)]
#[repr(C)] #[repr(C)]
/// PlaceHolder
pub struct SockAddr { pub struct SockAddr {
sa_family: u16, // SaFamily sa_family: u16, // SaFamily
sa_data: [u8; 14], sa_data: [u8; 14],
@ -103,9 +111,9 @@ pub struct SockAddrUnix {
sun_path: [u8; SOCK_ADDR_UNIX_LEN], sun_path: [u8; SOCK_ADDR_UNIX_LEN],
} }
/// IPv4 4-byte address
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, Pod)] #[derive(Debug, Clone, Copy, Pod)]
/// IPv4 4-byte address
pub struct InetAddr { pub struct InetAddr {
s_addr: [u8; 4], s_addr: [u8; 4],
} }
@ -140,9 +148,9 @@ impl PortNum {
} }
} }
/// IPv4 socket address
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, Pod)] #[derive(Debug, Clone, Copy, Pod)]
/// IPv4 socket address
pub struct SockAddrInet { pub struct SockAddrInet {
/// always SaFamily::AF_INET /// always SaFamily::AF_INET
sin_family: u16, sin_family: u16,
@ -168,7 +176,6 @@ impl SockAddrInet {
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, Pod)] #[derive(Debug, Clone, Copy, Pod)]
/// IPv6 address
pub struct Inet6Addr { pub struct Inet6Addr {
s6_addr: [u8; 16], s6_addr: [u8; 16],
} }
@ -278,12 +285,14 @@ impl From<SockAddrInet> for SocketAddr {
} }
} }
impl TryFrom<&str> for SockAddrUnix { impl TryFrom<&UnixSocketAddr> for SockAddrUnix {
type Error = Error; type Error = Error;
fn try_from(value: &str) -> Result<Self> { fn try_from(value: &UnixSocketAddr) -> Result<Self> {
let mut sun_path = [0u8; SOCK_ADDR_UNIX_LEN]; let mut sun_path = [0u8; SOCK_ADDR_UNIX_LEN];
let bytes = value.as_bytes(); match value {
UnixSocketAddr::Path(path) => {
let bytes = path.as_bytes();
let copy_len = bytes.len().min(SOCK_ADDR_UNIX_LEN - 1); let copy_len = bytes.len().min(SOCK_ADDR_UNIX_LEN - 1);
sun_path[..copy_len].copy_from_slice(&bytes[..copy_len]); sun_path[..copy_len].copy_from_slice(&bytes[..copy_len]);
Ok(SockAddrUnix { Ok(SockAddrUnix {
@ -291,4 +300,7 @@ impl TryFrom<&str> for SockAddrUnix {
sun_path, sun_path,
}) })
} }
UnixSocketAddr::Abstract(_) => todo!(),
}
}
} }

View File

@ -1,10 +1,10 @@
use crate::prelude::*; 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)] #[repr(i32)]
#[derive(Debug, Clone, Copy, TryFromInt)] #[derive(Debug, Clone, Copy, TryFromInt)]
#[allow(non_camel_case_types)] #[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 { pub enum Protocol {
IPPROTO_IP = 0, /* Dummy protocol for TCP */ IPPROTO_IP = 0, /* Dummy protocol for TCP */
IPPROTO_ICMP = 1, /* Internet Control Message Protocol */ IPPROTO_ICMP = 1, /* Internet Control Message Protocol */
@ -34,11 +34,11 @@ pub enum Protocol {
IPPROTO_MPTCP = 262, /* Multipath TCP connection */ IPPROTO_MPTCP = 262, /* Multipath TCP connection */
} }
/// Socket types.
/// From https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/net.h
#[repr(i32)] #[repr(i32)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, TryFromInt)] #[derive(Debug, Clone, Copy, TryFromInt)]
/// Socket types.
/// From https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/net.h
pub enum SockType { pub enum SockType {
/// Stream socket /// Stream socket
SOCK_STREAM = 1, SOCK_STREAM = 1,