mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-19 12:36:46 +00:00
Implement UNIX abstract address namespace
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
aae9fdb331
commit
65aa156e92
@ -1,6 +1,13 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use crate::{fs::path::Dentry, net::socket::util::socket_addr::SocketAddr, prelude::*};
|
use keyable_arc::KeyableArc;
|
||||||
|
|
||||||
|
use super::ns::{self, AbstractHandle};
|
||||||
|
use crate::{
|
||||||
|
fs::{path::Dentry, utils::Inode},
|
||||||
|
net::socket::util::socket_addr::SocketAddr,
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum UnixSocketAddr {
|
pub enum UnixSocketAddr {
|
||||||
@ -9,10 +16,36 @@ pub enum UnixSocketAddr {
|
|||||||
Abstract(Arc<[u8]>),
|
Abstract(Arc<[u8]>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
impl UnixSocketAddr {
|
||||||
pub(super) enum UnixSocketAddrBound {
|
pub(super) fn bind(self) -> Result<UnixSocketAddrBound> {
|
||||||
Path(Arc<str>, Arc<Dentry>),
|
let bound = match self {
|
||||||
Abstract(Arc<[u8]>),
|
Self::Unnamed => UnixSocketAddrBound::Abstract(ns::alloc_ephemeral_abstract_name()?),
|
||||||
|
Self::Path(path) => {
|
||||||
|
let dentry = ns::create_socket_file(&path)?;
|
||||||
|
UnixSocketAddrBound::Path(path, dentry)
|
||||||
|
}
|
||||||
|
Self::Abstract(name) => UnixSocketAddrBound::Abstract(ns::create_abstract_name(name)?),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(bound)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn connect(&self) -> Result<UnixSocketAddrKey> {
|
||||||
|
let bound = match self {
|
||||||
|
Self::Unnamed => return_errno_with_message!(
|
||||||
|
Errno::EINVAL,
|
||||||
|
"the unnamed UNIX domain socket address is not valid for connecting"
|
||||||
|
),
|
||||||
|
Self::Path(path) => UnixSocketAddrKey::Path(KeyableArc::from(
|
||||||
|
ns::lookup_socket_file(path)?.inode().clone(),
|
||||||
|
)),
|
||||||
|
Self::Abstract(name) => {
|
||||||
|
UnixSocketAddrKey::Abstract(KeyableArc::from(ns::lookup_abstract_name(name)?))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(bound)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<SocketAddr> for UnixSocketAddr {
|
impl TryFrom<SocketAddr> for UnixSocketAddr {
|
||||||
@ -26,11 +59,34 @@ impl TryFrom<SocketAddr> for UnixSocketAddr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub(super) enum UnixSocketAddrBound {
|
||||||
|
Path(Arc<str>, Arc<Dentry>),
|
||||||
|
Abstract(Arc<AbstractHandle>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
|
||||||
|
pub(super) enum UnixSocketAddrKey {
|
||||||
|
Path(KeyableArc<dyn Inode>),
|
||||||
|
Abstract(KeyableArc<AbstractHandle>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnixSocketAddrBound {
|
||||||
|
pub(super) fn to_key(&self) -> UnixSocketAddrKey {
|
||||||
|
match self {
|
||||||
|
Self::Path(_, dentry) => {
|
||||||
|
UnixSocketAddrKey::Path(KeyableArc::from(dentry.inode().clone()))
|
||||||
|
}
|
||||||
|
Self::Abstract(handle) => UnixSocketAddrKey::Abstract(KeyableArc::from(handle.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<UnixSocketAddrBound> for UnixSocketAddr {
|
impl From<UnixSocketAddrBound> for UnixSocketAddr {
|
||||||
fn from(value: UnixSocketAddrBound) -> Self {
|
fn from(value: UnixSocketAddrBound) -> Self {
|
||||||
match value {
|
match value {
|
||||||
UnixSocketAddrBound::Path(path, _) => Self::Path(path),
|
UnixSocketAddrBound::Path(path, _) => Self::Path(path),
|
||||||
UnixSocketAddrBound::Abstract(name) => Self::Abstract(name),
|
UnixSocketAddrBound::Abstract(name) => Self::Abstract(name.name()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
mod addr;
|
mod addr;
|
||||||
|
mod ns;
|
||||||
mod stream;
|
mod stream;
|
||||||
|
|
||||||
pub use addr::UnixSocketAddr;
|
pub use addr::UnixSocketAddr;
|
||||||
|
122
kernel/src/net/socket/unix/ns/abs.rs
Normal file
122
kernel/src/net/socket/unix/ns/abs.rs
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use alloc::{collections::btree_map::Entry, format};
|
||||||
|
|
||||||
|
use keyable_arc::KeyableArc;
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct AbstractHandle(KeyableArc<[u8]>);
|
||||||
|
|
||||||
|
impl AbstractHandle {
|
||||||
|
fn new(name: Arc<[u8]>) -> Self {
|
||||||
|
Self(KeyableArc::from(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> Arc<[u8]> {
|
||||||
|
self.0.clone().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for AbstractHandle {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
HANDLE_TABLE.remove(self.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HANDLE_TABLE: HandleTable = HandleTable::new();
|
||||||
|
|
||||||
|
struct HandleTable {
|
||||||
|
handles: RwLock<BTreeMap<Arc<[u8]>, Weak<AbstractHandle>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HandleTable {
|
||||||
|
const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
handles: RwLock::new(BTreeMap::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(&self, name: Arc<[u8]>) -> Option<Arc<AbstractHandle>> {
|
||||||
|
let mut handles = self.handles.write();
|
||||||
|
|
||||||
|
let mut entry = handles.entry(name.clone());
|
||||||
|
|
||||||
|
if let Entry::Occupied(ref occupied) = entry {
|
||||||
|
// The handle is in use only if its strong count is greater than zero.
|
||||||
|
if occupied.get().strong_count() > 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_handle = Arc::new(AbstractHandle::new(name));
|
||||||
|
let weak_handle = Arc::downgrade(&new_handle);
|
||||||
|
|
||||||
|
match entry {
|
||||||
|
Entry::Occupied(ref mut occupied) => {
|
||||||
|
occupied.insert(weak_handle);
|
||||||
|
}
|
||||||
|
Entry::Vacant(vacant) => {
|
||||||
|
vacant.insert(weak_handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(new_handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&self, name: Arc<[u8]>) {
|
||||||
|
let mut handles = self.handles.write();
|
||||||
|
|
||||||
|
let Entry::Occupied(occupied) = handles.entry(name) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Due to race conditions between `AbstractHandle::drop` and `HandleTable::create`, the
|
||||||
|
// entry may be occupied by another handle.
|
||||||
|
//
|
||||||
|
// Therefore, before removing the entry, we must check again if the entry should be removed.
|
||||||
|
if occupied.get().strong_count() == 0 {
|
||||||
|
occupied.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lookup(&self, name: &[u8]) -> Option<Arc<AbstractHandle>> {
|
||||||
|
let handles = self.handles.read();
|
||||||
|
|
||||||
|
handles.get(name).and_then(Weak::upgrade)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_ephemeral(&self) -> Option<Arc<AbstractHandle>> {
|
||||||
|
// See "Autobind feature" in the man pages:
|
||||||
|
// <https://man7.org/linux/man-pages/man7/unix.7.html>.
|
||||||
|
//
|
||||||
|
// Note that false negatives are fine here. So we don't mind race conditions.
|
||||||
|
//
|
||||||
|
// TODO: Always starting with the first name is inefficient and leads to contention.
|
||||||
|
// Instead, we should generate some random names and check their availability.
|
||||||
|
(0..(1 << 20))
|
||||||
|
.map(|num| format!("{:05x}", num))
|
||||||
|
.map(|name| Arc::from(name.as_bytes()))
|
||||||
|
.filter_map(|name| self.create(name))
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_abstract_name(name: Arc<[u8]>) -> Result<Arc<AbstractHandle>> {
|
||||||
|
HANDLE_TABLE.create(name).ok_or_else(|| {
|
||||||
|
Error::with_message(Errno::EADDRINUSE, "the abstract name is already in use")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alloc_ephemeral_abstract_name() -> Result<Arc<AbstractHandle>> {
|
||||||
|
HANDLE_TABLE.alloc_ephemeral().ok_or_else(|| {
|
||||||
|
Error::with_message(Errno::ENOSPC, "no ephemeral abstract name is available")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lookup_abstract_name(name: &[u8]) -> Result<Arc<AbstractHandle>> {
|
||||||
|
HANDLE_TABLE
|
||||||
|
.lookup(name)
|
||||||
|
.ok_or_else(|| Error::with_message(Errno::ECONNREFUSED, "the abstract name does not exist"))
|
||||||
|
}
|
9
kernel/src/net/socket/unix/ns/mod.rs
Normal file
9
kernel/src/net/socket/unix/ns/mod.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
pub(super) use abs::{
|
||||||
|
alloc_ephemeral_abstract_name, create_abstract_name, lookup_abstract_name, AbstractHandle,
|
||||||
|
};
|
||||||
|
pub(super) use path::{create_socket_file, lookup_socket_file};
|
||||||
|
|
||||||
|
mod abs;
|
||||||
|
mod path;
|
57
kernel/src/net/socket/unix/ns/path.rs
Normal file
57
kernel/src/net/socket/unix/ns/path.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
fs::{
|
||||||
|
fs_resolver::{split_path, FsPath},
|
||||||
|
path::Dentry,
|
||||||
|
utils::{InodeMode, InodeType},
|
||||||
|
},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub 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.mode()?.is_readable() || !dentry.mode()?.is_writable() {
|
||||||
|
return_errno_with_message!(Errno::EACCES, "the socket file cannot be read or written")
|
||||||
|
}
|
||||||
|
|
||||||
|
if dentry.type_() != InodeType::Socket {
|
||||||
|
return_errno_with_message!(
|
||||||
|
Errno::ECONNREFUSED,
|
||||||
|
"the specified file is not a socket file"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(dentry)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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)?
|
||||||
|
};
|
||||||
|
|
||||||
|
parent
|
||||||
|
.new_fs_child(
|
||||||
|
file_name,
|
||||||
|
InodeType::Socket,
|
||||||
|
InodeMode::S_IRUSR | InodeMode::S_IWUSR,
|
||||||
|
)
|
||||||
|
.map_err(|err| {
|
||||||
|
if err.error() == Errno::EEXIST {
|
||||||
|
Error::with_message(Errno::EADDRINUSE, "the socket file already exists")
|
||||||
|
} else {
|
||||||
|
err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -2,11 +2,6 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
events::{IoEvents, Observer},
|
events::{IoEvents, Observer},
|
||||||
fs::{
|
|
||||||
fs_resolver::{split_path, FsPath},
|
|
||||||
path::Dentry,
|
|
||||||
utils::{InodeMode, InodeType},
|
|
||||||
},
|
|
||||||
net::socket::unix::addr::{UnixSocketAddr, UnixSocketAddrBound},
|
net::socket::unix::addr::{UnixSocketAddr, UnixSocketAddrBound},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::signal::{Pollee, Poller},
|
process::signal::{Pollee, Poller},
|
||||||
@ -30,14 +25,7 @@ impl Init {
|
|||||||
return_errno_with_message!(Errno::EINVAL, "the socket is already bound");
|
return_errno_with_message!(Errno::EINVAL, "the socket is already bound");
|
||||||
}
|
}
|
||||||
|
|
||||||
let bound_addr = match addr_to_bind {
|
let bound_addr = addr_to_bind.bind()?;
|
||||||
UnixSocketAddr::Unnamed => todo!(),
|
|
||||||
UnixSocketAddr::Abstract(_) => todo!(),
|
|
||||||
UnixSocketAddr::Path(path) => {
|
|
||||||
let dentry = create_socket_file(&path)?;
|
|
||||||
UnixSocketAddrBound::Path(path, dentry)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.addr = Some(bound_addr);
|
self.addr = Some(bound_addr);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -67,19 +55,3 @@ impl Init {
|
|||||||
self.pollee.unregister_observer(observer)
|
self.pollee.unregister_observer(observer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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.new_fs_child(
|
|
||||||
file_name,
|
|
||||||
InodeType::Socket,
|
|
||||||
InodeMode::S_IRUSR | InodeMode::S_IWUSR,
|
|
||||||
)?;
|
|
||||||
Ok(dentry)
|
|
||||||
}
|
|
||||||
|
@ -2,13 +2,14 @@
|
|||||||
|
|
||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
use keyable_arc::KeyableWeak;
|
|
||||||
|
|
||||||
use super::{connected::Connected, UnixStreamSocket};
|
use super::{connected::Connected, UnixStreamSocket};
|
||||||
use crate::{
|
use crate::{
|
||||||
events::{IoEvents, Observer},
|
events::{IoEvents, Observer},
|
||||||
fs::{file_handle::FileLike, path::Dentry, utils::Inode},
|
fs::file_handle::FileLike,
|
||||||
net::socket::{unix::addr::UnixSocketAddrBound, SocketAddr},
|
net::socket::{
|
||||||
|
unix::addr::{UnixSocketAddrBound, UnixSocketAddrKey},
|
||||||
|
SocketAddr,
|
||||||
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::signal::{Pollee, Poller},
|
process::signal::{Pollee, Poller},
|
||||||
};
|
};
|
||||||
@ -62,15 +63,14 @@ impl Listener {
|
|||||||
|
|
||||||
impl Drop for Listener {
|
impl Drop for Listener {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unregister_backlog(self.backlog.addr())
|
unregister_backlog(&self.backlog.addr().to_key())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static BACKLOG_TABLE: BacklogTable = BacklogTable::new();
|
static BACKLOG_TABLE: BacklogTable = BacklogTable::new();
|
||||||
|
|
||||||
struct BacklogTable {
|
struct BacklogTable {
|
||||||
backlog_sockets: RwLock<BTreeMap<KeyableWeak<dyn Inode>, Arc<Backlog>>>,
|
backlog_sockets: RwLock<BTreeMap<UnixSocketAddrKey, Arc<Backlog>>>,
|
||||||
// TODO: For linux, there is also abstract socket domain that a socket addr is not bound to an inode.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BacklogTable {
|
impl BacklogTable {
|
||||||
@ -81,41 +81,30 @@ impl BacklogTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add_backlog(&self, addr: UnixSocketAddrBound, backlog: usize) -> Option<Arc<Backlog>> {
|
fn add_backlog(&self, addr: UnixSocketAddrBound, backlog: usize) -> Option<Arc<Backlog>> {
|
||||||
let inode = {
|
let addr_key = addr.to_key();
|
||||||
let UnixSocketAddrBound::Path(_, ref dentry) = addr else {
|
|
||||||
todo!()
|
|
||||||
};
|
|
||||||
create_keyable_inode(dentry)
|
|
||||||
};
|
|
||||||
let new_backlog = Arc::new(Backlog::new(addr, backlog));
|
|
||||||
|
|
||||||
let mut backlog_sockets = self.backlog_sockets.write();
|
let mut backlog_sockets = self.backlog_sockets.write();
|
||||||
if backlog_sockets.contains_key(&inode) {
|
|
||||||
|
if backlog_sockets.contains_key(&addr_key) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
backlog_sockets.insert(inode, new_backlog.clone());
|
|
||||||
|
let new_backlog = Arc::new(Backlog::new(addr, backlog));
|
||||||
|
backlog_sockets.insert(addr_key, new_backlog.clone());
|
||||||
|
|
||||||
Some(new_backlog)
|
Some(new_backlog)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_backlog(&self, addr: &UnixSocketAddrBound) -> Option<Arc<Backlog>> {
|
fn get_backlog(&self, addr: &UnixSocketAddrKey) -> Option<Arc<Backlog>> {
|
||||||
let inode = {
|
self.backlog_sockets.read().get(addr).cloned()
|
||||||
let UnixSocketAddrBound::Path(_, dentry) = addr else {
|
|
||||||
todo!()
|
|
||||||
};
|
|
||||||
create_keyable_inode(dentry)
|
|
||||||
};
|
|
||||||
|
|
||||||
let backlog_sockets = self.backlog_sockets.read();
|
|
||||||
backlog_sockets.get(&inode).cloned()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_incoming(
|
fn push_incoming(
|
||||||
&self,
|
&self,
|
||||||
server_addr: &UnixSocketAddrBound,
|
server_key: &UnixSocketAddrKey,
|
||||||
client_addr: Option<UnixSocketAddrBound>,
|
client_addr: Option<UnixSocketAddrBound>,
|
||||||
) -> Result<Connected> {
|
) -> Result<Connected> {
|
||||||
let backlog = self.get_backlog(server_addr).ok_or_else(|| {
|
let backlog = self.get_backlog(server_key).ok_or_else(|| {
|
||||||
Error::with_message(
|
Error::with_message(
|
||||||
Errno::ECONNREFUSED,
|
Errno::ECONNREFUSED,
|
||||||
"no socket is listening at the remote address",
|
"no socket is listening at the remote address",
|
||||||
@ -125,13 +114,8 @@ impl BacklogTable {
|
|||||||
backlog.push_incoming(client_addr)
|
backlog.push_incoming(client_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_backlog(&self, addr: &UnixSocketAddrBound) {
|
fn remove_backlog(&self, addr_key: &UnixSocketAddrKey) {
|
||||||
let UnixSocketAddrBound::Path(_, dentry) = addr else {
|
self.backlog_sockets.write().remove(addr_key);
|
||||||
todo!()
|
|
||||||
};
|
|
||||||
|
|
||||||
let inode = create_keyable_inode(dentry);
|
|
||||||
self.backlog_sockets.write().remove(&inode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,18 +194,13 @@ impl Backlog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_keyable_inode(dentry: &Arc<Dentry>) -> KeyableWeak<dyn Inode> {
|
fn unregister_backlog(addr: &UnixSocketAddrKey) {
|
||||||
let weak_inode = Arc::downgrade(dentry.inode());
|
|
||||||
KeyableWeak::from(weak_inode)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unregister_backlog(addr: &UnixSocketAddrBound) {
|
|
||||||
BACKLOG_TABLE.remove_backlog(addr);
|
BACKLOG_TABLE.remove_backlog(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn push_incoming(
|
pub(super) fn push_incoming(
|
||||||
server_addr: &UnixSocketAddrBound,
|
server_key: &UnixSocketAddrKey,
|
||||||
client_addr: Option<UnixSocketAddrBound>,
|
client_addr: Option<UnixSocketAddrBound>,
|
||||||
) -> Result<Connected> {
|
) -> Result<Connected> {
|
||||||
BACKLOG_TABLE.push_incoming(server_addr, client_addr)
|
BACKLOG_TABLE.push_incoming(server_key, client_addr)
|
||||||
}
|
}
|
||||||
|
@ -11,14 +11,9 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
events::{IoEvents, Observer},
|
events::{IoEvents, Observer},
|
||||||
fs::{
|
fs::{file_handle::FileLike, utils::StatusFlags},
|
||||||
file_handle::FileLike,
|
|
||||||
fs_resolver::FsPath,
|
|
||||||
path::Dentry,
|
|
||||||
utils::{InodeType, StatusFlags},
|
|
||||||
},
|
|
||||||
net::socket::{
|
net::socket::{
|
||||||
unix::{addr::UnixSocketAddrBound, UnixSocketAddr},
|
unix::UnixSocketAddr,
|
||||||
util::{
|
util::{
|
||||||
copy_message_from_user, copy_message_to_user, create_message_buffer,
|
copy_message_from_user, copy_message_to_user, create_message_buffer,
|
||||||
send_recv_flags::SendRecvFlags, socket_addr::SocketAddr, MessageHeader,
|
send_recv_flags::SendRecvFlags, socket_addr::SocketAddr, MessageHeader,
|
||||||
@ -203,19 +198,7 @@ impl Socket for UnixStreamSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn connect(&self, socket_addr: SocketAddr) -> Result<()> {
|
fn connect(&self, socket_addr: SocketAddr) -> Result<()> {
|
||||||
let remote_addr = {
|
let remote_addr = UnixSocketAddr::try_from(socket_addr)?.connect()?;
|
||||||
let unix_socket_addr = UnixSocketAddr::try_from(socket_addr)?;
|
|
||||||
match unix_socket_addr {
|
|
||||||
UnixSocketAddr::Unnamed => todo!(),
|
|
||||||
UnixSocketAddr::Abstract(abstract_name) => {
|
|
||||||
UnixSocketAddrBound::Abstract(abstract_name)
|
|
||||||
}
|
|
||||||
UnixSocketAddr::Path(path) => {
|
|
||||||
let dentry = lookup_socket_file(&path)?;
|
|
||||||
UnixSocketAddrBound::Path(path, dentry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Note that the Linux kernel implementation locks the remote socket and checks to see if
|
// Note that the Linux kernel implementation locks the remote socket and checks to see if
|
||||||
// it is listening first. This is different from our implementation, which locks the local
|
// it is listening first. This is different from our implementation, which locks the local
|
||||||
@ -356,21 +339,3 @@ impl Socket for UnixStreamSocket {
|
|||||||
Ok((copied_bytes, message_header))
|
Ok((copied_bytes, message_header))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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.type_() != InodeType::Socket {
|
|
||||||
return_errno_with_message!(Errno::ENOTSOCK, "not a socket file")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !dentry.mode()?.is_readable() || !dentry.mode()?.is_writable() {
|
|
||||||
return_errno_with_message!(Errno::EACCES, "the socket cannot be read or written")
|
|
||||||
}
|
|
||||||
Ok(dentry)
|
|
||||||
}
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <sys/poll.h>
|
#include <sys/poll.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
@ -233,3 +234,63 @@ FN_TEST(listen)
|
|||||||
TEST_ERRNO(listen(sk_accepted, 10), EINVAL);
|
TEST_ERRNO(listen(sk_accepted, 10), EINVAL);
|
||||||
}
|
}
|
||||||
END_TEST()
|
END_TEST()
|
||||||
|
|
||||||
|
FN_TEST(ns_path)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = TEST_SUCC(creat("/tmp/.good", 0644));
|
||||||
|
TEST_ERRNO(bind(sk_unbound, (struct sockaddr *)&UNIX_ADDR("/tmp/.good"),
|
||||||
|
sizeof(struct sockaddr)),
|
||||||
|
EADDRINUSE);
|
||||||
|
TEST_ERRNO(connect(sk_unbound,
|
||||||
|
(struct sockaddr *)&UNIX_ADDR("/tmp/.good"),
|
||||||
|
sizeof(struct sockaddr)),
|
||||||
|
ECONNREFUSED);
|
||||||
|
TEST_SUCC(close(fd));
|
||||||
|
TEST_SUCC(unlink("/tmp/.good"));
|
||||||
|
|
||||||
|
fd = TEST_SUCC(creat("/tmp/.bad", 0000));
|
||||||
|
TEST_ERRNO(bind(sk_unbound, (struct sockaddr *)&UNIX_ADDR("/tmp/.bad"),
|
||||||
|
sizeof(struct sockaddr)),
|
||||||
|
EADDRINUSE);
|
||||||
|
TEST_ERRNO(connect(sk_unbound,
|
||||||
|
(struct sockaddr *)&UNIX_ADDR("/tmp/.bad"),
|
||||||
|
sizeof(struct sockaddr)),
|
||||||
|
EACCES);
|
||||||
|
TEST_SUCC(close(fd));
|
||||||
|
TEST_SUCC(unlink("/tmp/.bad"));
|
||||||
|
}
|
||||||
|
END_TEST()
|
||||||
|
|
||||||
|
FN_TEST(ns_abs)
|
||||||
|
{
|
||||||
|
int sk, sk2;
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
socklen_t addrlen;
|
||||||
|
|
||||||
|
sk = TEST_SUCC(socket(PF_UNIX, SOCK_STREAM, 0));
|
||||||
|
|
||||||
|
TEST_SUCC(bind(sk, (struct sockaddr *)&UNIX_ADDR(""), PATH_OFFSET));
|
||||||
|
addrlen = sizeof(addr);
|
||||||
|
TEST_RES(getsockname(sk, (struct sockaddr *)&addr, &addrlen),
|
||||||
|
addrlen == PATH_OFFSET + 6 && addr.sun_path[0] == '\0');
|
||||||
|
|
||||||
|
sk2 = TEST_SUCC(socket(PF_UNIX, SOCK_STREAM, 0));
|
||||||
|
|
||||||
|
TEST_ERRNO(bind(sk2, (struct sockaddr *)&addr, addrlen), EADDRINUSE);
|
||||||
|
TEST_ERRNO(connect(sk2, (struct sockaddr *)&addr, addrlen),
|
||||||
|
ECONNREFUSED);
|
||||||
|
TEST_SUCC(listen(sk, 1));
|
||||||
|
TEST_SUCC(connect(sk2, (struct sockaddr *)&addr, addrlen));
|
||||||
|
|
||||||
|
TEST_SUCC(close(sk));
|
||||||
|
TEST_SUCC(close(sk2));
|
||||||
|
|
||||||
|
sk = TEST_SUCC(socket(PF_UNIX, SOCK_STREAM, 0));
|
||||||
|
TEST_ERRNO(connect(sk, (struct sockaddr *)&addr, addrlen),
|
||||||
|
ECONNREFUSED);
|
||||||
|
TEST_SUCC(bind(sk, (struct sockaddr *)&addr, addrlen));
|
||||||
|
TEST_SUCC(close(sk));
|
||||||
|
}
|
||||||
|
END_TEST()
|
||||||
|
Reference in New Issue
Block a user