mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 08:53:29 +00:00
Refactor unix stream socket implementation
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
93429ae2c9
commit
3f15bcaf5d
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
impl From<UnixSocketAddrBound> for UnixSocketAddr {
|
||||||
fn from(value: UnixSocketAddr) -> Self {
|
fn from(value: UnixSocketAddrBound) -> Self {
|
||||||
SocketAddr::Unix(value.path())
|
match value {
|
||||||
}
|
UnixSocketAddrBound::Path(dentry) => {
|
||||||
}
|
let abs_path = dentry.abs_path();
|
||||||
|
Self::Path(abs_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);
|
|
||||||
}
|
}
|
||||||
}
|
UnixSocketAddrBound::Abstract(name) => Self::Abstract(name),
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path(&self) -> String {
|
|
||||||
match self {
|
|
||||||
UnixSocketAddr::Bound(dentry) => dentry.abs_path(),
|
|
||||||
UnixSocketAddr::Unbound(path) => path.clone(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<UnixSocketAddrBound> for SocketAddr {
|
||||||
|
fn from(value: UnixSocketAddrBound) -> Self {
|
||||||
|
let unix_socket_addr = UnixSocketAddr::from(value);
|
||||||
|
SocketAddr::Unix(unix_socket_addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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> {
|
pub(super) fn is_bound(&self) -> bool {
|
||||||
self.bind_addr.as_ref()
|
self.addr.lock().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_nonblocking(&self) -> bool {
|
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)
|
||||||
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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::*,
|
}
|
||||||
};
|
|
||||||
|
|
||||||
use super::endpoint::Endpoint;
|
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 static ACTIVE_LISTENERS: ActiveListeners = ActiveListeners::new();
|
pub(super) fn addr(&self) -> &UnixSocketAddrBound {
|
||||||
|
&self.addr
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ActiveListeners {
|
pub(super) fn is_nonblocking(&self) -> bool {
|
||||||
listeners: RwLock<BTreeMap<KeyableWeak<dyn Inode>, Arc<Listener>>>,
|
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)
|
||||||
|
};
|
||||||
|
|
||||||
|
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<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)
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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 socket should also be allowed?
|
||||||
} // FIXME: Maybe binding a connected sockted 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));
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
Status::Listen(_) => {
|
};
|
||||||
return_errno_with_message!(Errno::EINVAL, "the socket is listened")
|
|
||||||
}
|
let init = match &*self.0.read() {
|
||||||
Status::Connected(_) => {
|
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")
|
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")
|
||||||
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(());
|
|
||||||
}
|
}
|
||||||
Status::Listen(_) => {
|
State::Connected(_) => {
|
||||||
return_errno_with_message!(Errno::EINVAL, "the socket is already listened")
|
return_errno_with_message!(Errno::EISCONN, "the socket is already connected")
|
||||||
}
|
|
||||||
Status::Connected(_) => {
|
|
||||||
return_errno_with_message!(Errno::EINVAL, "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<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(),
|
||||||
connected.shutdown(cmd)
|
_ => return_errno_with_message!(Errno::ENOTCONN, "the socked is not connected"),
|
||||||
} else {
|
};
|
||||||
return_errno_with_message!(Errno::ENOTCONN, "the socked is not connected");
|
|
||||||
}
|
connected.shutdown(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
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,31 +227,28 @@ 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(),
|
||||||
match connected.peer_addr() {
|
_ => return_errno_with_message!(Errno::ENOTCONN, "the socket is not connected"),
|
||||||
None => return Ok(SocketAddr::Unix(String::new())),
|
};
|
||||||
Some(peer_addr) => {
|
|
||||||
return Ok(SocketAddr::from(peer_addr.clone()));
|
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)> {
|
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()?;
|
||||||
Ok((read_size, peer_addr))
|
let read_size = connected.read(buf)?;
|
||||||
}
|
Ok((read_size, peer_addr))
|
||||||
Status::Init(_) | Status::Listen(_) => {
|
|
||||||
return_errno_with_message!(Errno::EINVAL, "the socket is not connected")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sendto(
|
fn sendto(
|
||||||
@ -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);
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,17 +285,22 @@ 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 {
|
||||||
let copy_len = bytes.len().min(SOCK_ADDR_UNIX_LEN - 1);
|
UnixSocketAddr::Path(path) => {
|
||||||
sun_path[..copy_len].copy_from_slice(&bytes[..copy_len]);
|
let bytes = path.as_bytes();
|
||||||
Ok(SockAddrUnix {
|
let copy_len = bytes.len().min(SOCK_ADDR_UNIX_LEN - 1);
|
||||||
sun_family: SaFamily::AF_UNIX as u16,
|
sun_path[..copy_len].copy_from_slice(&bytes[..copy_len]);
|
||||||
sun_path,
|
Ok(SockAddrUnix {
|
||||||
})
|
sun_family: SaFamily::AF_UNIX as u16,
|
||||||
|
sun_path,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
UnixSocketAddr::Abstract(_) => todo!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
Reference in New Issue
Block a user