feat: Introduce userspace namespace manager and adapt all schemes.
This commit is contained in:
committed by
Jeremy Soller
parent
1753859f75
commit
334928f151
+15
-13
@@ -63,24 +63,24 @@ fn run(daemon: daemon::Daemon) -> Result<()> {
|
||||
.context("failed to get mac address from network adapter")?;
|
||||
|
||||
trace!("opening ip scheme socket");
|
||||
let ip_fd = Socket::nonblock("ip")
|
||||
.map_err(|e| anyhow!("failed to open create ip scheme socket: {}", e))?;
|
||||
let ip_fd = Socket::nonblock()
|
||||
.map_err(|e| anyhow!("failed to open create ip scheme socket: {:?}", e))?;
|
||||
|
||||
trace!("opening udp scheme socket");
|
||||
let udp_fd =
|
||||
Socket::nonblock("udp").map_err(|e| anyhow!("failed to open udp scheme socket: {}", e))?;
|
||||
Socket::nonblock().map_err(|e| anyhow!("failed to open udp scheme socket: {:?}", e))?;
|
||||
|
||||
trace!("opening tcp scheme socket");
|
||||
let tcp_fd =
|
||||
Socket::nonblock("tcp").map_err(|e| anyhow!("failed to open tcp scheme socket: {}", e))?;
|
||||
Socket::nonblock().map_err(|e| anyhow!("failed to open tcp scheme socket: {:?}", e))?;
|
||||
|
||||
trace!("opening icmp scheme socket");
|
||||
let icmp_fd = Socket::nonblock("icmp")
|
||||
.map_err(|e| anyhow!("failed to open icmp scheme socket: {}", e))?;
|
||||
let icmp_fd =
|
||||
Socket::nonblock().map_err(|e| anyhow!("failed to open icmp scheme socket: {:?}", e))?;
|
||||
|
||||
trace!("opening netcfg scheme socket");
|
||||
let netcfg_fd = Socket::nonblock("netcfg")
|
||||
.map_err(|e| anyhow!("failed to open netcfg scheme socket {}", e))?;
|
||||
let netcfg_fd =
|
||||
Socket::nonblock().map_err(|e| anyhow!("failed to open netcfg scheme socket {:?}", e))?;
|
||||
|
||||
let time_path = format!("/scheme/time/{}", syscall::CLOCK_MONOTONIC);
|
||||
let time_fd = Fd::open(&time_path, O_RDWR, 0).context("failed to open /scheme/time")?;
|
||||
@@ -97,17 +97,18 @@ fn run(daemon: daemon::Daemon) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
let event_queue = EventQueue::<EventSource>::new().context("failed to create event queue")?;
|
||||
let event_queue = EventQueue::<EventSource>::new()
|
||||
.map_err(|e| anyhow!("failed to create event queue: {:?}", e))?;
|
||||
|
||||
daemon.ready();
|
||||
|
||||
event_queue
|
||||
.subscribe(network_fd.raw(), EventSource::Network, EventFlags::READ)
|
||||
.context("failed to listen to network events")?;
|
||||
.map_err(|e| anyhow!("failed to listen to network events: {:?}", e))?;
|
||||
|
||||
event_queue
|
||||
.subscribe(time_fd.raw(), EventSource::Time, EventFlags::READ)
|
||||
.context("failed to listen to timer events")?;
|
||||
.map_err(|e| anyhow!("failed to listen to timer events: {:?}", e))?;
|
||||
|
||||
event_queue
|
||||
.subscribe(ip_fd.inner().raw(), EventSource::IpScheme, EventFlags::READ)
|
||||
@@ -154,7 +155,8 @@ fn run(daemon: daemon::Daemon) -> Result<()> {
|
||||
icmp_fd,
|
||||
time_fd,
|
||||
netcfg_fd,
|
||||
);
|
||||
)
|
||||
.context("smolnetd: failed to initialize smolnetd")?;
|
||||
|
||||
libredox::call::setrens(0, 0).context("smolnetd: failed to enter null namespace")?;
|
||||
|
||||
@@ -167,7 +169,7 @@ fn run(daemon: daemon::Daemon) -> Result<()> {
|
||||
.into_iter()
|
||||
.chain(event_queue.map(|r| r.map(|e| e.user_data)))
|
||||
{
|
||||
match event_res? {
|
||||
match event_res.map_err(|e| anyhow!("event result is error: {:?}", e))? {
|
||||
EventSource::Network => smolnetd.on_network_scheme_event(),
|
||||
EventSource::Time => smolnetd.on_time_event(),
|
||||
EventSource::IpScheme => smolnetd.on_ip_scheme_event(),
|
||||
|
||||
+25
-14
@@ -4,7 +4,7 @@ use crate::link::{loopback::LoopbackDevice, DeviceList};
|
||||
use crate::router::route_table::{RouteTable, Rule};
|
||||
use crate::router::Router;
|
||||
use crate::scheme::smoltcp::iface::SocketSet as SmoltcpSocketSet;
|
||||
use crate::scheme::socket::{SchemeSocket, SocketScheme};
|
||||
use crate::scheme::socket::{Handle, SchemeSocket, SocketScheme};
|
||||
use libredox::flag;
|
||||
use libredox::Fd;
|
||||
use redox_scheme::{
|
||||
@@ -87,7 +87,7 @@ impl Smolnetd {
|
||||
icmp_file: Socket,
|
||||
time_file: Fd,
|
||||
netcfg_file: Socket,
|
||||
) -> Smolnetd {
|
||||
) -> Result<Smolnetd> {
|
||||
let protocol_addrs = vec![
|
||||
//This is a placeholder IP for DHCP
|
||||
IpCidr::new(IpAddress::v4(0, 0, 0, 0), 8),
|
||||
@@ -131,43 +131,47 @@ impl Smolnetd {
|
||||
devices.borrow_mut().push(loopback);
|
||||
devices.borrow_mut().push(eth0);
|
||||
|
||||
Smolnetd {
|
||||
Ok(Smolnetd {
|
||||
iface: Rc::clone(&iface),
|
||||
router_device: network_device,
|
||||
socket_set: Rc::clone(&socket_set),
|
||||
timer: ::std::time::Instant::now(),
|
||||
time_file: unsafe { File::from_raw_fd(time_file.into_raw() as RawFd) },
|
||||
ip_scheme: IpScheme::new(
|
||||
"ip",
|
||||
Rc::clone(&iface),
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&socket_set),
|
||||
ip_file,
|
||||
),
|
||||
)?,
|
||||
udp_scheme: UdpScheme::new(
|
||||
"udp",
|
||||
Rc::clone(&iface),
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&socket_set),
|
||||
udp_file,
|
||||
),
|
||||
)?,
|
||||
tcp_scheme: TcpScheme::new(
|
||||
"tcp",
|
||||
Rc::clone(&iface),
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&socket_set),
|
||||
tcp_file,
|
||||
),
|
||||
)?,
|
||||
icmp_scheme: IcmpScheme::new(
|
||||
"icmp",
|
||||
Rc::clone(&iface),
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&socket_set),
|
||||
icmp_file,
|
||||
),
|
||||
)?,
|
||||
netcfg_scheme: NetCfgScheme::new(
|
||||
Rc::clone(&iface),
|
||||
netcfg_file,
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&devices),
|
||||
),
|
||||
}
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn on_network_scheme_event(&mut self) -> Result<()> {
|
||||
@@ -319,15 +323,19 @@ where
|
||||
SocketT: SchemeSocket + AnySocket<'static>,
|
||||
{
|
||||
pub fn new(
|
||||
name: &str,
|
||||
iface: Interface,
|
||||
route_table: Rc<RefCell<RouteTable>>,
|
||||
socket_set: Rc<RefCell<SocketSet>>,
|
||||
scheme_file: Socket,
|
||||
) -> Self {
|
||||
Self {
|
||||
scheme: SocketScheme::<SocketT>::new(iface, route_table, socket_set, scheme_file),
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
scheme: SocketScheme::<SocketT>::new(name, iface, route_table, socket_set, scheme_file)
|
||||
.map_err(|e| {
|
||||
Error::from_syscall_error(e, &format!("failed to initialize {} scheme", name))
|
||||
})?,
|
||||
wait_queue: Vec::new(),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub fn on_scheme_event(&mut self) -> Result<Option<()>> {
|
||||
let result = loop {
|
||||
@@ -442,7 +450,10 @@ where
|
||||
// Notify non-blocking sockets
|
||||
let scheme = &mut self.scheme;
|
||||
|
||||
for (&fd, ref mut file) in &mut scheme.files {
|
||||
for (&fd, handle) in &mut scheme.handles {
|
||||
let Handle::File(file) = handle else {
|
||||
continue;
|
||||
};
|
||||
let events = {
|
||||
let mut socket_set = scheme.socket_set.borrow_mut();
|
||||
file.events(&mut socket_set)
|
||||
|
||||
@@ -3,7 +3,8 @@ mod nodes;
|
||||
mod notifier;
|
||||
|
||||
use redox_scheme::{
|
||||
scheme::SchemeSync, CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, Socket,
|
||||
scheme::register_scheme_inner, scheme::SchemeSync, CallerCtx, OpenResult, RequestKind,
|
||||
Response, SignalBehavior, Socket,
|
||||
};
|
||||
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address};
|
||||
use std::cell::RefCell;
|
||||
@@ -324,10 +325,15 @@ impl NetCfgFile {
|
||||
}
|
||||
}
|
||||
|
||||
enum Handle {
|
||||
SchemeRoot,
|
||||
File(NetCfgFile),
|
||||
}
|
||||
|
||||
pub struct NetCfgScheme {
|
||||
scheme_file: Socket,
|
||||
next_fd: usize,
|
||||
files: BTreeMap<usize, NetCfgFile>,
|
||||
handles: BTreeMap<usize, Handle>,
|
||||
root_node: CfgNodeRef,
|
||||
notifier: NotifierRef,
|
||||
}
|
||||
@@ -338,15 +344,15 @@ impl NetCfgScheme {
|
||||
scheme_file: Socket,
|
||||
route_table: Rc<RefCell<RouteTable>>,
|
||||
devices: Rc<RefCell<DeviceList>>,
|
||||
) -> NetCfgScheme {
|
||||
) -> Result<NetCfgScheme> {
|
||||
let notifier = Notifier::new_ref();
|
||||
let dns_config = Rc::new(RefCell::new(DNSConfig {
|
||||
name_server: Ipv4Address::new(8, 8, 8, 8),
|
||||
}));
|
||||
NetCfgScheme {
|
||||
let mut scheme = NetCfgScheme {
|
||||
scheme_file,
|
||||
next_fd: 1,
|
||||
files: BTreeMap::new(),
|
||||
handles: BTreeMap::new(),
|
||||
root_node: mk_root_node(
|
||||
iface,
|
||||
Rc::clone(¬ifier),
|
||||
@@ -355,7 +361,14 @@ impl NetCfgScheme {
|
||||
devices,
|
||||
),
|
||||
notifier,
|
||||
}
|
||||
};
|
||||
let cap_id = scheme
|
||||
.scheme_root()
|
||||
.map_err(|e| Error::from_syscall_error(e, "failed to get scheme root id"))?;
|
||||
register_scheme_inner(&scheme.scheme_file, "netcfg", cap_id).map_err(|e| {
|
||||
Error::from_syscall_error(e, "failed to register netcfg scheme to namespace")
|
||||
})?;
|
||||
Ok(scheme)
|
||||
}
|
||||
|
||||
pub fn on_scheme_event(&mut self) -> Result<Option<()>> {
|
||||
@@ -418,7 +431,32 @@ impl NetCfgScheme {
|
||||
}
|
||||
|
||||
impl SchemeSync for NetCfgScheme {
|
||||
fn open(&mut self, path: &str, _flags: usize, ctx: &CallerCtx) -> SyscallResult<OpenResult> {
|
||||
fn scheme_root(&mut self) -> SyscallResult<usize> {
|
||||
let id = self.next_fd;
|
||||
self.next_fd += 1;
|
||||
self.handles.insert(id, Handle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> SyscallResult<OpenResult> {
|
||||
{
|
||||
let handle = self
|
||||
.handles
|
||||
.get(&dirfd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
if !matches!(handle, Handle::SchemeRoot) {
|
||||
return Err(SyscallError::new(syscall::EACCES));
|
||||
}
|
||||
}
|
||||
|
||||
let mut current_node = Rc::clone(&self.root_node);
|
||||
for part in path.split('/') {
|
||||
if part.is_empty() {
|
||||
@@ -435,9 +473,9 @@ impl SchemeSync for NetCfgScheme {
|
||||
let fd = self.next_fd;
|
||||
trace!("open {} {}", fd, path);
|
||||
self.next_fd += 1;
|
||||
self.files.insert(
|
||||
self.handles.insert(
|
||||
fd,
|
||||
NetCfgFile {
|
||||
Handle::File(NetCfgFile {
|
||||
path: path.to_owned(),
|
||||
is_dir: current_node.is_dir(),
|
||||
is_writable: current_node.is_writable(),
|
||||
@@ -452,7 +490,7 @@ impl SchemeSync for NetCfgScheme {
|
||||
read_buf,
|
||||
write_buf: vec![],
|
||||
done: false,
|
||||
},
|
||||
}),
|
||||
);
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: fd,
|
||||
@@ -462,10 +500,17 @@ impl SchemeSync for NetCfgScheme {
|
||||
|
||||
fn on_close(&mut self, fd: usize) {
|
||||
trace!("close {}", fd);
|
||||
if let Some(mut file) = self.files.remove(&fd) {
|
||||
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
|
||||
if !file.done {
|
||||
let _ = file.commit().map(|_| 0);
|
||||
if let Some(handle) = self.handles.remove(&fd) {
|
||||
match handle {
|
||||
Handle::SchemeRoot => {
|
||||
// SchemeRoot closed, nothing specific to clean up
|
||||
}
|
||||
Handle::File(mut file) => {
|
||||
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
|
||||
if !file.done {
|
||||
let _ = file.commit().map(|_| 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -478,11 +523,16 @@ impl SchemeSync for NetCfgScheme {
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> SyscallResult<usize> {
|
||||
let file = self
|
||||
.files
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match handle {
|
||||
Handle::File(file) => file,
|
||||
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
if file.done {
|
||||
return Err(SyscallError::new(syscall::EBADF));
|
||||
}
|
||||
@@ -514,11 +564,16 @@ impl SchemeSync for NetCfgScheme {
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> SyscallResult<usize> {
|
||||
let file = self
|
||||
.files
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match handle {
|
||||
Handle::File(file) => file,
|
||||
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
let mut i = 0;
|
||||
while i < buf.len() && file.pos < file.read_buf.len() {
|
||||
buf[i] = file.read_buf[file.pos];
|
||||
@@ -529,21 +584,26 @@ impl SchemeSync for NetCfgScheme {
|
||||
}
|
||||
|
||||
fn fstat(&mut self, fd: usize, stat: &mut Stat, _ctx: &CallerCtx) -> SyscallResult<()> {
|
||||
let file = self
|
||||
.files
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
stat.st_mode = if file.is_dir { MODE_DIR } else { MODE_FILE };
|
||||
if file.is_writable {
|
||||
stat.st_mode |= 0o222;
|
||||
match handle {
|
||||
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
|
||||
Handle::File(file) => {
|
||||
stat.st_mode = if file.is_dir { MODE_DIR } else { MODE_FILE };
|
||||
if file.is_writable {
|
||||
stat.st_mode |= 0o222;
|
||||
}
|
||||
if file.is_readable {
|
||||
stat.st_mode |= 0o444;
|
||||
}
|
||||
stat.st_uid = 0;
|
||||
stat.st_gid = 0;
|
||||
stat.st_size = file.read_buf.len() as u64;
|
||||
}
|
||||
}
|
||||
if file.is_readable {
|
||||
stat.st_mode |= 0o444;
|
||||
}
|
||||
stat.st_uid = 0;
|
||||
stat.st_gid = 0;
|
||||
stat.st_size = file.read_buf.len() as u64;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -554,24 +614,35 @@ impl SchemeSync for NetCfgScheme {
|
||||
events: SyscallEventFlags,
|
||||
_ctx: &CallerCtx,
|
||||
) -> SyscallResult<SyscallEventFlags> {
|
||||
let file = self
|
||||
.files
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
if events.contains(syscall::EVENT_READ) {
|
||||
self.notifier.borrow_mut().subscribe(&file.path, fd);
|
||||
} else {
|
||||
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
|
||||
|
||||
match handle {
|
||||
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
|
||||
Handle::File(file) => {
|
||||
if events.contains(syscall::EVENT_READ) {
|
||||
self.notifier.borrow_mut().subscribe(&file.path, fd);
|
||||
} else {
|
||||
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(SyscallEventFlags::empty())
|
||||
}
|
||||
|
||||
fn fsync(&mut self, fd: usize, _ctx: &CallerCtx) -> SyscallResult<()> {
|
||||
let file = self
|
||||
.files
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match handle {
|
||||
Handle::File(file) => file,
|
||||
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
if !file.done {
|
||||
let res = file.commit();
|
||||
file.done = true;
|
||||
|
||||
+181
-129
@@ -12,7 +12,7 @@ use std::str;
|
||||
use libredox::flag::CLOCK_MONOTONIC;
|
||||
use redox_rt::protocol::SocketCall;
|
||||
use redox_scheme::{
|
||||
scheme::{Op, SchemeSync},
|
||||
scheme::{register_scheme_inner, Op, SchemeSync},
|
||||
CallerCtx, OpenResult, Socket,
|
||||
};
|
||||
use syscall::data::TimeSpec;
|
||||
@@ -239,13 +239,21 @@ where
|
||||
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize>;
|
||||
}
|
||||
|
||||
pub enum Handle<SocketT>
|
||||
where
|
||||
SocketT: SchemeSocket,
|
||||
{
|
||||
SchemeRoot,
|
||||
Null(NullFile),
|
||||
File(SchemeFile<SocketT>),
|
||||
}
|
||||
|
||||
pub struct SocketScheme<SocketT>
|
||||
where
|
||||
SocketT: SchemeSocket + AnySocket<'static>,
|
||||
{
|
||||
next_fd: usize,
|
||||
nulls: BTreeMap<usize, NullFile>,
|
||||
pub files: BTreeMap<usize, SchemeFile<SocketT>>,
|
||||
pub handles: BTreeMap<usize, Handle<SocketT>>,
|
||||
ref_counts: BTreeMap<SocketHandle, usize>,
|
||||
context: Context,
|
||||
pub socket_set: Rc<RefCell<SocketSet>>,
|
||||
@@ -259,33 +267,36 @@ where
|
||||
SocketT: SchemeSocket + AnySocket<'static>,
|
||||
{
|
||||
pub fn new(
|
||||
name: &str,
|
||||
iface: Interface,
|
||||
route_table: Rc<RefCell<RouteTable>>,
|
||||
socket_set: Rc<RefCell<SocketSet>>,
|
||||
scheme_file: Socket,
|
||||
) -> SocketScheme<SocketT> {
|
||||
SocketScheme {
|
||||
) -> SyscallResult<SocketScheme<SocketT>> {
|
||||
let mut scheme = SocketScheme {
|
||||
next_fd: 1,
|
||||
nulls: BTreeMap::new(),
|
||||
files: BTreeMap::new(),
|
||||
handles: BTreeMap::new(),
|
||||
ref_counts: BTreeMap::new(),
|
||||
socket_set,
|
||||
scheme_data: SocketT::new_scheme_data(),
|
||||
scheme_file,
|
||||
_phantom_socket: PhantomData,
|
||||
context: Context { iface, route_table },
|
||||
}
|
||||
};
|
||||
let cap_id = scheme.scheme_root()?;
|
||||
register_scheme_inner(&scheme.scheme_file, name, cap_id)?;
|
||||
Ok(scheme)
|
||||
}
|
||||
|
||||
pub fn handle_block(&mut self, op: &Op) -> SyscallResult<Option<TimeSpec>> {
|
||||
let fd = op.file_id().expect("op is not fd based request");
|
||||
let (read_timeout, write_timeout) = {
|
||||
let file = self
|
||||
.files
|
||||
let handle = self
|
||||
.handles
|
||||
.get(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
if let SchemeFile::Socket(ref scheme_file) = *file {
|
||||
if let Handle::File(SchemeFile::Socket(ref scheme_file)) = *handle {
|
||||
Ok((scheme_file.read_timeout, scheme_file.write_timeout))
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EBADF))
|
||||
@@ -319,14 +330,13 @@ where
|
||||
buf: &mut [u8],
|
||||
) -> SyscallResult<usize> {
|
||||
let file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match *file {
|
||||
SchemeFile::Socket(ref mut file) => file,
|
||||
_ => {
|
||||
return Err(SyscallError::new(syscall::EBADF));
|
||||
}
|
||||
Handle::File(SchemeFile::Socket(ref mut file)) => file,
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
match setting {
|
||||
@@ -369,14 +379,12 @@ where
|
||||
buf: &[u8],
|
||||
) -> SyscallResult<usize> {
|
||||
let file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
let file = match *file {
|
||||
SchemeFile::Socket(ref mut file) => file,
|
||||
_ => {
|
||||
return Err(SyscallError::new(syscall::EBADF));
|
||||
}
|
||||
Handle::File(SchemeFile::Socket(ref mut file)) => file,
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
match setting {
|
||||
Setting::ReadTimeout | Setting::WriteTimeout => {
|
||||
@@ -445,9 +453,14 @@ where
|
||||
// SocketCall::GetToken => self.handle_get_token(id, payload),
|
||||
SocketCall::GetPeerName => {
|
||||
let file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match *file {
|
||||
Handle::File(ref mut f) => f,
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
let socket = socket_set.get_mut::<SocketT>(file.socket_handle());
|
||||
|
||||
@@ -456,28 +469,31 @@ where
|
||||
SocketCall::Shutdown => {
|
||||
let how = metadata[1] as usize;
|
||||
|
||||
if let Some(null_file) = self.nulls.get_mut(&fd) {
|
||||
match how {
|
||||
0 => null_file.read_enabled = false,
|
||||
1 => null_file.write_enabled = false,
|
||||
2 => {
|
||||
null_file.read_enabled = false;
|
||||
null_file.write_enabled = false;
|
||||
}
|
||||
_ => return Err(SyscallError::new(EINVAL)),
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let file = self
|
||||
.files
|
||||
match self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?
|
||||
{
|
||||
Handle::File(file) => {
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
let socket = socket_set.get_mut::<SocketT>(file.socket_handle());
|
||||
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
let socket = socket_set.get_mut::<SocketT>(file.socket_handle());
|
||||
|
||||
SocketT::handle_shutdown(socket, file, how)
|
||||
SocketT::handle_shutdown(socket, file, how)
|
||||
}
|
||||
Handle::Null(null_file) => {
|
||||
match how {
|
||||
0 => null_file.read_enabled = false,
|
||||
1 => null_file.write_enabled = false,
|
||||
2 => {
|
||||
null_file.read_enabled = false;
|
||||
null_file.write_enabled = false;
|
||||
}
|
||||
_ => return Err(SyscallError::new(EINVAL)),
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
Handle::SchemeRoot => Err(SyscallError::new(syscall::EBADF)),
|
||||
}
|
||||
}
|
||||
_ => Err(SyscallError::new(EOPNOTSUPP)),
|
||||
}
|
||||
@@ -504,7 +520,7 @@ where
|
||||
let id = self.next_fd;
|
||||
self.next_fd += 1;
|
||||
|
||||
self.nulls.insert(id, null);
|
||||
self.handles.insert(id, Handle::Null(null));
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: id,
|
||||
@@ -536,7 +552,7 @@ where
|
||||
self.next_fd += 1;
|
||||
|
||||
self.ref_counts.insert(socket_handle, 1);
|
||||
self.files.insert(id, file);
|
||||
self.handles.insert(id, Handle::File(file));
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: id,
|
||||
@@ -550,8 +566,30 @@ impl<SocketT> SchemeSync for SocketScheme<SocketT>
|
||||
where
|
||||
SocketT: SchemeSocket + AnySocket<'static>,
|
||||
{
|
||||
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> SyscallResult<OpenResult> {
|
||||
self.open_inner(path, flags, ctx.uid, ctx.gid, true, true)
|
||||
fn scheme_root(&mut self) -> SyscallResult<usize> {
|
||||
let id = self.next_fd;
|
||||
self.next_fd += 1;
|
||||
self.handles.insert(id, Handle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn openat(
|
||||
&mut self,
|
||||
fd: usize,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> SyscallResult<OpenResult> {
|
||||
let handle = self
|
||||
.handles
|
||||
.get(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
match handle {
|
||||
Handle::SchemeRoot => self.open_inner(path, flags, ctx.uid, ctx.gid, true, true),
|
||||
_ => Err(SyscallError::new(syscall::EACCES)),
|
||||
}
|
||||
}
|
||||
|
||||
fn call(
|
||||
@@ -565,22 +603,11 @@ where
|
||||
}
|
||||
|
||||
fn on_close(&mut self, fd: usize) {
|
||||
if let Some(_null) = self.nulls.remove(&fd) {
|
||||
let handle = if let Some(handle) = self.handles.remove(&fd) {
|
||||
handle
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
let socket_handle = {
|
||||
let Some(file) = self.files.get(&fd) else {
|
||||
return;
|
||||
};
|
||||
file.socket_handle()
|
||||
};
|
||||
let scheme_file = self.files.remove(&fd);
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
if let Some(scheme_file) = scheme_file {
|
||||
let socket = socket_set.get::<SocketT>(socket_handle);
|
||||
let _ = socket.close_file(&scheme_file, &mut self.scheme_data);
|
||||
}
|
||||
|
||||
// incorrect, and kernel can't send close until all references are gone
|
||||
/*self.wait_queue.retain(
|
||||
@@ -590,30 +617,42 @@ where
|
||||
}| a != fd,
|
||||
);*/
|
||||
|
||||
let remove = match self.ref_counts.entry(socket_handle) {
|
||||
Entry::Vacant(_) => {
|
||||
warn!("Closing a socket_handle with no ref");
|
||||
true
|
||||
}
|
||||
Entry::Occupied(mut e) => {
|
||||
if *e.get() == 0 {
|
||||
warn!("Closing a socket_handle with no ref");
|
||||
e.remove();
|
||||
true
|
||||
} else {
|
||||
*e.get_mut() -= 1;
|
||||
if *e.get() == 0 {
|
||||
e.remove();
|
||||
match handle {
|
||||
Handle::SchemeRoot => return,
|
||||
Handle::Null(_) => return,
|
||||
Handle::File(scheme_file) => {
|
||||
let socket_handle = scheme_file.socket_handle();
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
|
||||
let socket = socket_set.get::<SocketT>(socket_handle);
|
||||
let _ = socket.close_file(&scheme_file, &mut self.scheme_data);
|
||||
|
||||
let remove = match self.ref_counts.entry(socket_handle) {
|
||||
Entry::Vacant(_) => {
|
||||
warn!("Closing a socket_handle with no ref");
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
Entry::Occupied(mut e) => {
|
||||
if *e.get() == 0 {
|
||||
warn!("Closing a socket_handle with no ref");
|
||||
e.remove();
|
||||
true
|
||||
} else {
|
||||
*e.get_mut() -= 1;
|
||||
if *e.get() == 0 {
|
||||
e.remove();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if remove {
|
||||
socket_set.remove(socket_handle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if remove {
|
||||
socket_set.remove(socket_handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -627,15 +666,15 @@ where
|
||||
) -> SyscallResult<usize> {
|
||||
let (fd, setting) = {
|
||||
let file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
match *file {
|
||||
SchemeFile::Setting(ref setting_handle) => {
|
||||
Handle::File(SchemeFile::Setting(ref setting_handle)) => {
|
||||
(setting_handle.fd, setting_handle.setting)
|
||||
}
|
||||
SchemeFile::Socket(ref mut file) => {
|
||||
Handle::File(SchemeFile::Socket(ref mut file)) => {
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
let socket = socket_set.get_mut::<SocketT>(file.socket_handle);
|
||||
let ret = SocketT::write_buf(socket, file, buf);
|
||||
@@ -646,6 +685,7 @@ where
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
}
|
||||
};
|
||||
self.update_setting(fd, setting, buf)
|
||||
@@ -661,14 +701,14 @@ where
|
||||
) -> SyscallResult<usize> {
|
||||
let (fd, setting) = {
|
||||
let file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
match *file {
|
||||
SchemeFile::Setting(ref setting_handle) => {
|
||||
Handle::File(SchemeFile::Setting(ref setting_handle)) => {
|
||||
(setting_handle.fd, setting_handle.setting)
|
||||
}
|
||||
SchemeFile::Socket(ref mut file) => {
|
||||
Handle::File(SchemeFile::Socket(ref mut file)) => {
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
let socket = socket_set.get_mut::<SocketT>(file.socket_handle);
|
||||
|
||||
@@ -681,6 +721,7 @@ where
|
||||
|
||||
return ret;
|
||||
}
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
}
|
||||
};
|
||||
self.get_setting(fd, setting, buf)
|
||||
@@ -689,27 +730,28 @@ where
|
||||
fn dup(&mut self, fd: usize, buf: &[u8], _ctx: &CallerCtx) -> SyscallResult<OpenResult> {
|
||||
let path = str::from_utf8(buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
|
||||
|
||||
if let Some((flags, uid, gid, read_enabled, write_enabled)) =
|
||||
self.nulls.get(&fd).map(|null| {
|
||||
(
|
||||
null.flags,
|
||||
null.uid,
|
||||
null.gid,
|
||||
null.read_enabled,
|
||||
null.write_enabled,
|
||||
)
|
||||
})
|
||||
{
|
||||
// dup from empty path to a new path
|
||||
return self.open_inner(path, flags, uid, gid, read_enabled, write_enabled);
|
||||
}
|
||||
|
||||
let new_file = {
|
||||
let file = self
|
||||
.files
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match *handle {
|
||||
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
|
||||
Handle::Null(ref null) => {
|
||||
let (flags, uid, gid, read_enabled, write_enabled) = (
|
||||
null.flags,
|
||||
null.uid,
|
||||
null.gid,
|
||||
null.read_enabled,
|
||||
null.write_enabled,
|
||||
);
|
||||
// dup from empty path to a new path
|
||||
return self.open_inner(path, flags, uid, gid, read_enabled, write_enabled);
|
||||
}
|
||||
Handle::File(ref mut file) => file,
|
||||
};
|
||||
|
||||
let socket_handle = file.socket_handle();
|
||||
|
||||
let (new_handle, update_with) = match path {
|
||||
@@ -757,7 +799,10 @@ where
|
||||
.and_modify(|e| *e = e.saturating_sub(1))
|
||||
.or_insert(0);
|
||||
|
||||
*self.ref_counts.entry(socket_handle).or_insert(0) += 1;
|
||||
*self
|
||||
.ref_counts
|
||||
.entry(new_handle.socket_handle())
|
||||
.or_insert(0) += 1;
|
||||
|
||||
file.socket_handle = socket_handle;
|
||||
file.data = data;
|
||||
@@ -771,7 +816,7 @@ where
|
||||
};
|
||||
|
||||
let id = self.next_fd;
|
||||
self.files.insert(id, new_file);
|
||||
self.handles.insert(id, Handle::File(new_file));
|
||||
self.next_fd += 1;
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
@@ -787,9 +832,15 @@ where
|
||||
_ctx: &CallerCtx,
|
||||
) -> SyscallResult<SyscallEventFlags> {
|
||||
let file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match *file {
|
||||
Handle::File(ref mut f) => f,
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
match *file {
|
||||
SchemeFile::Setting(_) => return Err(SyscallError::new(syscall::EBADF)),
|
||||
SchemeFile::Socket(ref mut file) => {
|
||||
@@ -806,7 +857,7 @@ where
|
||||
fn fsync(&mut self, fd: usize, _ctx: &CallerCtx) -> SyscallResult<()> {
|
||||
{
|
||||
let _file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
}
|
||||
@@ -817,10 +868,15 @@ where
|
||||
|
||||
fn fpath(&mut self, fd: usize, buf: &mut [u8], _ctx: &CallerCtx) -> SyscallResult<usize> {
|
||||
let file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match *file {
|
||||
Handle::File(ref mut f) => f,
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
let socket_set = self.socket_set.borrow();
|
||||
let socket = socket_set.get::<SocketT>(file.socket_handle());
|
||||
|
||||
@@ -834,33 +890,29 @@ where
|
||||
arg: usize,
|
||||
_ctx: &CallerCtx,
|
||||
) -> SyscallResult<usize> {
|
||||
if let Some(ref mut null) = self.nulls.get_mut(&fd) {
|
||||
match cmd {
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
match *handle {
|
||||
Handle::File(SchemeFile::Socket(ref mut socket_file)) => match cmd {
|
||||
syscall::F_GETFL => Ok(socket_file.flags),
|
||||
syscall::F_SETFL => {
|
||||
socket_file.flags = arg & !syscall::O_ACCMODE;
|
||||
Ok(0)
|
||||
}
|
||||
_ => Err(SyscallError::new(syscall::EINVAL)),
|
||||
},
|
||||
Handle::Null(ref mut null) => match cmd {
|
||||
syscall::F_GETFL => Ok(null.flags),
|
||||
syscall::F_SETFL => {
|
||||
null.flags = arg & !syscall::O_ACCMODE;
|
||||
Ok(0)
|
||||
}
|
||||
_ => Err(SyscallError::new(syscall::EINVAL)),
|
||||
}
|
||||
} else {
|
||||
let file = self
|
||||
.files
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
if let SchemeFile::Socket(ref mut socket_file) = *file {
|
||||
match cmd {
|
||||
syscall::F_GETFL => Ok(socket_file.flags),
|
||||
syscall::F_SETFL => {
|
||||
socket_file.flags = arg & !syscall::O_ACCMODE;
|
||||
Ok(0)
|
||||
}
|
||||
_ => Err(SyscallError::new(syscall::EINVAL)),
|
||||
}
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EBADF))
|
||||
}
|
||||
},
|
||||
_ => Err(SyscallError::new(syscall::EBADF)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user