diff --git a/Cargo.lock b/Cargo.lock index e476ebe0e1..fe7b63d4fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1679,7 +1679,7 @@ dependencies = [ "libredox", "log", "redox-log", - "redox-scheme 0.8.2 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", + "redox-scheme 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event", "redox_syscall", "smoltcp", diff --git a/netstack/Cargo.toml b/netstack/Cargo.toml index 77ef61ab29..29321b230a 100644 --- a/netstack/Cargo.toml +++ b/netstack/Cargo.toml @@ -14,8 +14,7 @@ redox_syscall = { version = "0.5", features = ["std"] } redox-log = "0.1" libredox = { version = "0.1.3", features = ["mkns"] } anyhow = "1.0.81" -#redox-scheme = "0.5.0" -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +redox-scheme = "0.8" [dependencies.log] version = "0.4" diff --git a/netstack/src/main.rs b/netstack/src/main.rs index cf77bd430f..bf461853f2 100644 --- a/netstack/src/main.rs +++ b/netstack/src/main.rs @@ -4,9 +4,10 @@ use std::process; use anyhow::{anyhow, bail, Context, Result}; use event::{EventFlags, EventQueue}; -use libredox::flag::{O_CREAT, O_NONBLOCK, O_RDWR}; +use libredox::flag::{O_NONBLOCK, O_RDWR}; use libredox::Fd; +use redox_scheme::Socket; use scheme::Smolnetd; use smoltcp::wire::EthernetAddress; @@ -61,24 +62,25 @@ fn run(daemon: daemon::Daemon) -> Result<()> { .map(|mac_address| EthernetAddress::from_bytes(&mac_address)) .context("failed to get mac address from network adapter")?; - trace!("opening :ip"); - let ip_fd = Fd::open(":ip", O_RDWR | O_CREAT | O_NONBLOCK, 0).context("failed to open :ip")?; + trace!("opening ip scheme socket"); + let ip_fd = Socket::nonblock("ip") + .map_err(|e| anyhow!("failed to open create ip scheme socket: {}", e))?; - trace!("opening :udp"); + trace!("opening udp scheme socket"); let udp_fd = - Fd::open(":udp", O_RDWR | O_CREAT | O_NONBLOCK, 0).context("failed to open :udp")?; + Socket::nonblock("udp").map_err(|e| anyhow!("failed to open udp scheme socket: {}", e))?; - trace!("opening :tcp"); + trace!("opening tcp scheme socket"); let tcp_fd = - Fd::open(":tcp", O_RDWR | O_CREAT | O_NONBLOCK, 0).context("failed to open :tcp")?; + Socket::nonblock("tcp").map_err(|e| anyhow!("failed to open tcp scheme socket: {}", e))?; - trace!("opening :icmp"); - let icmp_fd = - Fd::open(":icmp", O_RDWR | O_CREAT | O_NONBLOCK, 0).context("failed to open :icmp")?; + trace!("opening icmp scheme socket"); + let icmp_fd = Socket::nonblock("icmp") + .map_err(|e| anyhow!("failed to open icmp scheme socket: {}", e))?; - trace!("opening :netcfg"); - let netcfg_fd = - Fd::open(":netcfg", O_RDWR | O_CREAT | O_NONBLOCK, 0).context("failed to open :netcfg")?; + trace!("opening netcfg scheme socket"); + let netcfg_fd = Socket::nonblock("netcfg") + .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")?; @@ -108,23 +110,39 @@ fn run(daemon: daemon::Daemon) -> Result<()> { .context("failed to listen to timer events")?; event_queue - .subscribe(ip_fd.raw(), EventSource::IpScheme, EventFlags::READ) + .subscribe(ip_fd.inner().raw(), EventSource::IpScheme, EventFlags::READ) .context("failed to listen to ip scheme events")?; event_queue - .subscribe(udp_fd.raw(), EventSource::UdpScheme, EventFlags::READ) + .subscribe( + udp_fd.inner().raw(), + EventSource::UdpScheme, + EventFlags::READ, + ) .context("failed to listen to udp scheme events")?; event_queue - .subscribe(tcp_fd.raw(), EventSource::TcpScheme, EventFlags::READ) + .subscribe( + tcp_fd.inner().raw(), + EventSource::TcpScheme, + EventFlags::READ, + ) .context("failed to listen to tcp scheme events")?; event_queue - .subscribe(icmp_fd.raw(), EventSource::IcmpScheme, EventFlags::READ) + .subscribe( + icmp_fd.inner().raw(), + EventSource::IcmpScheme, + EventFlags::READ, + ) .context("failed to listen to icmp scheme events")?; event_queue - .subscribe(netcfg_fd.raw(), EventSource::NetcfgScheme, EventFlags::READ) + .subscribe( + netcfg_fd.inner().raw(), + EventSource::NetcfgScheme, + EventFlags::READ, + ) .context("failed to listen to netcfg scheme events")?; let mut smolnetd = Smolnetd::new( diff --git a/netstack/src/scheme/icmp.rs b/netstack/src/scheme/icmp.rs index 242c1fef5a..860795b458 100644 --- a/netstack/src/scheme/icmp.rs +++ b/netstack/src/scheme/icmp.rs @@ -9,12 +9,12 @@ use std::str; use syscall; use syscall::{Error as SyscallError, Result as SyscallResult}; -use super::socket::{Context, DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme}; -use super::{Smolnetd, SocketSet}; +use super::socket::{Context, DupResult, SchemeFile, SchemeSocket, SocketFile}; +use super::{SchemeWrapper, Smolnetd, SocketSet}; use crate::port_set::PortSet; use crate::router::Router; -pub type IcmpScheme = SocketScheme>; +pub type IcmpScheme = SchemeWrapper>; enum IcmpSocketType { Echo, @@ -170,7 +170,7 @@ impl<'a> SchemeSocket for IcmpSocket<'a> { &mut self, file: &mut SocketFile, buf: &[u8], - ) -> SyscallResult> { + ) -> SyscallResult { if self.can_send() { match file.data.socket_type { IcmpSocketType::Echo => { @@ -191,14 +191,14 @@ impl<'a> SchemeSocket for IcmpSocket<'a> { let mut icmp_packet = Icmpv4Packet::new_unchecked(icmp_payload); //TODO: replace Default with actual caps icmp_repr.emit(&mut icmp_packet, &Default::default()); - Ok(Some(buf.len())) + Ok(buf.len()) } IcmpSocketType::Udp => Err(SyscallError::new(syscall::EINVAL)), } } else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { Err(SyscallError::new(syscall::EAGAIN)) } else { - Ok(None) // internally scheduled to re-read + Err(SyscallError::new(syscall::EWOULDBLOCK)) // internally scheduled to re-read } } @@ -206,7 +206,7 @@ impl<'a> SchemeSocket for IcmpSocket<'a> { &mut self, file: &mut SocketFile, buf: &mut [u8], - ) -> SyscallResult> { + ) -> SyscallResult { while self.can_recv() { let (payload, _) = self.recv().expect("Can't recv icmp packet"); let icmp_packet = Icmpv4Packet::new_unchecked(&payload); @@ -223,14 +223,14 @@ impl<'a> SchemeSocket for IcmpSocket<'a> { buf[mem::size_of::() + i] = data[i]; } - return Ok(Some(mem::size_of::() + data.len())); + return Ok(mem::size_of::() + data.len()); } } if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { Err(SyscallError::new(syscall::EAGAIN)) } else { - Ok(None) // internally scheduled to re-read + Err(SyscallError::new(syscall::EWOULDBLOCK)) // internally scheduled to re-read } } diff --git a/netstack/src/scheme/ip.rs b/netstack/src/scheme/ip.rs index 231e22862a..9dd94d699e 100644 --- a/netstack/src/scheme/ip.rs +++ b/netstack/src/scheme/ip.rs @@ -9,10 +9,10 @@ use syscall::{Error as SyscallError, Result as SyscallResult}; use crate::router::Router; -use super::socket::{Context, DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme}; -use super::{Smolnetd, SocketSet}; +use super::socket::{Context, DupResult, SchemeFile, SchemeSocket, SocketFile}; +use super::{SchemeWrapper, Smolnetd, SocketSet}; -pub type IpScheme = SocketScheme>; +pub type IpScheme = SchemeWrapper>; impl<'a> SchemeSocket for RawSocket<'a> { type SchemeDataT = (); @@ -97,14 +97,14 @@ impl<'a> SchemeSocket for RawSocket<'a> { &mut self, file: &mut SocketFile, buf: &[u8], - ) -> SyscallResult> { + ) -> SyscallResult { if self.can_send() { self.send_slice(buf).expect("Can't send slice"); - Ok(Some(buf.len())) + Ok(buf.len()) } else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { Err(SyscallError::new(syscall::EAGAIN)) } else { - Ok(None) // internally scheduled to re-read + Err(SyscallError::new(syscall::EWOULDBLOCK)) // internally scheduled to re-read } } @@ -112,14 +112,14 @@ impl<'a> SchemeSocket for RawSocket<'a> { &mut self, file: &mut SocketFile, buf: &mut [u8], - ) -> SyscallResult> { + ) -> SyscallResult { if self.can_recv() { let length = self.recv_slice(buf).expect("Can't receive slice"); - Ok(Some(length)) + Ok(length) } else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { Err(SyscallError::new(syscall::EAGAIN)) } else { - Ok(None) // internally scheduled to re-read + Err(SyscallError::new(syscall::EWOULDBLOCK)) // internally scheduled to re-read } } diff --git a/netstack/src/scheme/mod.rs b/netstack/src/scheme/mod.rs index 26d8ce0c99..d3c00faf62 100644 --- a/netstack/src/scheme/mod.rs +++ b/netstack/src/scheme/mod.rs @@ -4,10 +4,17 @@ 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 libredox::flag; use libredox::Fd; +use redox_scheme::{ + scheme::{IntoTag, Op, SchemeResponse, SchemeSync}, + CallerCtx, RequestKind, Response, SignalBehavior, Socket, +}; use smoltcp; use smoltcp::iface::{Config, Interface as SmoltcpInterface}; use smoltcp::phy::Tracer; +use smoltcp::socket::AnySocket; use smoltcp::time::{Duration, Instant}; use smoltcp::wire::{ EthernetAddress, HardwareAddress, IpAddress, IpCidr, IpListenEndpoint, Ipv4Address, @@ -21,6 +28,7 @@ use std::rc::Rc; use std::str::FromStr; use syscall; use syscall::data::TimeSpec; +use syscall::Error as SyscallError; use self::icmp::IcmpScheme; use self::ip::IpScheme; @@ -73,12 +81,12 @@ impl Smolnetd { pub fn new( network_file: Fd, hardware_addr: EthernetAddress, - ip_file: Fd, - udp_file: Fd, - tcp_file: Fd, - icmp_file: Fd, + ip_file: Socket, + udp_file: Socket, + tcp_file: Socket, + icmp_file: Socket, time_file: Fd, - netcfg_file: Fd, + netcfg_file: Socket, ) -> Smolnetd { let protocol_addrs = vec![ //This is a placeholder IP for DHCP @@ -133,29 +141,29 @@ impl Smolnetd { Rc::clone(&iface), Rc::clone(&route_table), Rc::clone(&socket_set), - unsafe { File::from_raw_fd(ip_file.into_raw() as RawFd) }, + ip_file, ), udp_scheme: UdpScheme::new( Rc::clone(&iface), Rc::clone(&route_table), Rc::clone(&socket_set), - unsafe { File::from_raw_fd(udp_file.into_raw() as RawFd) }, + udp_file, ), tcp_scheme: TcpScheme::new( Rc::clone(&iface), Rc::clone(&route_table), Rc::clone(&socket_set), - unsafe { File::from_raw_fd(tcp_file.into_raw() as RawFd) }, + tcp_file, ), icmp_scheme: IcmpScheme::new( Rc::clone(&iface), Rc::clone(&route_table), Rc::clone(&socket_set), - unsafe { File::from_raw_fd(icmp_file.into_raw() as RawFd) }, + icmp_file, ), netcfg_scheme: NetCfgScheme::new( Rc::clone(&iface), - unsafe { File::from_raw_fd(netcfg_file.into_raw() as RawFd) }, + netcfg_file, Rc::clone(&route_table), Rc::clone(&devices), ), @@ -267,20 +275,13 @@ impl Smolnetd { } } -fn post_fevent(scheme_file: &mut File, fd: usize, event: usize, data_len: usize) -> Result<()> { - scheme_file - .write(&syscall::Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: fd, - c: event, - d: data_len, - }) - .map(|_| ()) - .map_err(|e| Error::from_io_error(e, "failed to post fevent")) +fn post_fevent(socket: &Socket, id: usize, flags: usize) -> syscall::error::Result<()> { + let fevent_response = Response::post_fevent(id, flags); + match socket.write_response(fevent_response, SignalBehavior::Restart) { + Ok(true) => Ok(()), // Write response success + Ok(false) => Err(syscall::error::Error::new(syscall::EAGAIN)), // Write response failed, retry. + Err(err) => Err(err), // Error writing response + } } fn parse_endpoint(socket: &str) -> IpListenEndpoint { @@ -297,3 +298,231 @@ fn parse_endpoint(socket: &str) -> IpListenEndpoint { .unwrap_or(0); IpListenEndpoint { addr: host, port } } + +struct WaitHandle { + until: Option, + cancelling: bool, + packet: (Op, CallerCtx), +} + +type WaitQueue = Vec; + +pub struct SchemeWrapper +where + SocketT: SchemeSocket + AnySocket<'static>, +{ + scheme: socket::SocketScheme, + wait_queue: WaitQueue, +} +impl SchemeWrapper +where + SocketT: SchemeSocket + AnySocket<'static>, +{ + pub fn new( + iface: Interface, + route_table: Rc>, + socket_set: Rc>, + scheme_file: Socket, + ) -> Self { + Self { + scheme: SocketScheme::::new(iface, route_table, socket_set, scheme_file), + wait_queue: Vec::new(), + } + } + pub fn on_scheme_event(&mut self) -> Result> { + let result = loop { + let request = match self + .scheme + .scheme_file + .next_request(SignalBehavior::Restart) + { + Ok(Some(req)) => req, + Ok(None) => { + break Some(()); + } + Err(error) + if error.errno == syscall::EWOULDBLOCK || error.errno == syscall::EAGAIN => + { + break None; + } + Err(other) => { + return Err(Error::from_syscall_error( + other, + "failed to receive new request", + )) + } + }; + + let req = match request.kind() { + RequestKind::Call(c) => c, + RequestKind::OnClose { id } => { + self.scheme.on_close(id); + continue; + } + RequestKind::Cancellation(req) => { + if let Some(idx) = self + .wait_queue + .iter() + .position(|q| q.packet.0.req_id() == req.id) + { + self.wait_queue[idx].cancelling = true; + } + continue; + } + _ => { + continue; + } + }; + let caller = req.caller(); + let mut op = match req.op() { + Ok(op) => op, + Err(req) => { + self.scheme + .scheme_file + .write_response( + Response::err(syscall::EOPNOTSUPP, req), + SignalBehavior::Restart, + ) + .map_err(|e| { + Error::from_syscall_error(e.into(), "failed to write response") + })?; + continue; + } + }; + let resp = match op.handle_sync_dont_consume(&caller, &mut self.scheme) { + SchemeResponse::Opened(Err(SyscallError { + errno: syscall::EWOULDBLOCK, + })) + | SchemeResponse::Regular(Err(SyscallError { + errno: syscall::EWOULDBLOCK, + })) if !op.is_explicitly_nonblock() => { + match self.scheme.handle_block(&op) { + Ok(timeout) => { + self.wait_queue.push(WaitHandle { + until: timeout, + cancelling: false, + packet: (op, caller), + }); + } + Err(err) => { + let _ = self + .scheme + .scheme_file + .write_response( + Response::err(err.errno, op), + SignalBehavior::Restart, + ) + .map_err(|e| { + Error::from_syscall_error(e.into(), "failed to write response") + })?; + return Err(Error::from_syscall_error( + err, + "Can't handle blocked socket", + )); + } + } + continue; + } + SchemeResponse::Regular(r) => Response::new(r, op), + SchemeResponse::Opened(o) => Response::open_dup_like(o, op), + }; + let _ = self + .scheme + .scheme_file + .write_response(resp, SignalBehavior::Restart) + .map_err(|e| Error::from_syscall_error(e.into(), "failed to write response"))?; + }; + Ok(result) + } + + pub fn notify_sockets(&mut self) -> Result<()> { + let cur_time = libredox::call::clock_gettime(flag::CLOCK_MONOTONIC) + .map_err(|e| Error::from_syscall_error(e.into(), "Can't get time"))?; + + // Notify non-blocking sockets + let scheme = &mut self.scheme; + + for (&fd, ref mut file) in &mut scheme.files { + let events = { + let mut socket_set = scheme.socket_set.borrow_mut(); + file.events(&mut socket_set) + }; + if events > 0 { + post_fevent(&scheme.scheme_file, fd, events) + .map_err(|e| Error::from_syscall_error(e.into(), "failed to post fevent"))?; + } + } + // Wake up blocking queue + let queue = &mut self.wait_queue; + let mut i = 0; + while i < queue.len() { + let handle = &mut queue[i]; + let (op, caller) = &mut handle.packet; + let res = op.handle_sync_dont_consume(caller, scheme); + + match res { + SchemeResponse::Opened(Err(SyscallError { + errno: syscall::EWOULDBLOCK, + })) + | SchemeResponse::Regular(Err(SyscallError { + errno: syscall::EWOULDBLOCK, + })) if !op.is_explicitly_nonblock() => { + if handle.cancelling { + let (op, _) = queue.swap_remove(i).packet; + scheme + .scheme_file + .write_response( + Response::err(syscall::ECANCELED, op), + SignalBehavior::Restart, + ) + .map_err(|e| { + Error::from_syscall_error(e.into(), "failed to write response") + })?; + continue; + } + match handle.until { + Some(until) + if (until.tv_sec < cur_time.tv_sec + || (until.tv_sec == cur_time.tv_sec + && i64::from(until.tv_nsec) < i64::from(cur_time.tv_nsec))) => + { + let (op, _) = queue.swap_remove(i).packet; + let _ = scheme + .scheme_file + .write_response( + Response::err(syscall::ETIMEDOUT, op), + SignalBehavior::Restart, + ) + .map_err(|e| { + Error::from_syscall_error(e.into(), "failed to write response") + })?; + } + _ => { + i += 1; + } + } + } + SchemeResponse::Regular(r) => { + let (op, _) = queue.swap_remove(i).packet; + let _ = scheme + .scheme_file + .write_response(Response::new(r, op), SignalBehavior::Restart) + .map_err(|e| { + Error::from_syscall_error(e.into(), "failed to write response") + })?; + } + SchemeResponse::Opened(o) => { + let (op, _) = queue.swap_remove(i).packet; + let _ = scheme + .scheme_file + .write_response(Response::open_dup_like(o, op), SignalBehavior::Restart) + .map_err(|e| { + Error::from_syscall_error(e.into(), "failed to write response") + })?; + } + }; + } + + Ok(()) + } +} diff --git a/netstack/src/scheme/netcfg/mod.rs b/netstack/src/scheme/netcfg/mod.rs index e5433b51ef..9fe4a71161 100644 --- a/netstack/src/scheme/netcfg/mod.rs +++ b/netstack/src/scheme/netcfg/mod.rs @@ -2,11 +2,12 @@ mod nodes; mod notifier; +use redox_scheme::{ + scheme::SchemeSync, CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, Socket, +}; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address}; use std::cell::RefCell; use std::collections::BTreeMap; -use std::fs::File; -use std::io::{ErrorKind, Read, Write}; use std::mem; use std::rc::Rc; use std::str; @@ -14,10 +15,8 @@ use std::str::FromStr; use syscall; use syscall::data::Stat; use syscall::flag::{MODE_DIR, MODE_FILE}; -use syscall::{ - Error as SyscallError, EventFlags as SyscallEventFlags, Packet as SyscallPacket, - Result as SyscallResult, SchemeMut, -}; +use syscall::schemev2::NewFdFlags; +use syscall::{Error as SyscallError, EventFlags as SyscallEventFlags, Result as SyscallResult}; use crate::error::{Error, Result}; use crate::link::DeviceList; @@ -326,7 +325,7 @@ impl NetCfgFile { } pub struct NetCfgScheme { - scheme_file: File, + scheme_file: Socket, next_fd: usize, files: BTreeMap, root_node: CfgNodeRef, @@ -336,7 +335,7 @@ pub struct NetCfgScheme { impl NetCfgScheme { pub fn new( iface: Interface, - scheme_file: File, + scheme_file: Socket, route_table: Rc>, devices: Rc>, ) -> NetCfgScheme { @@ -361,23 +360,50 @@ impl NetCfgScheme { pub fn on_scheme_event(&mut self) -> Result> { let result = loop { - let mut packet = SyscallPacket::default(); - match self.scheme_file.read(&mut packet) { - Ok(0) => { - //TODO: Cleanup must occur + let request = match self.scheme_file.next_request(SignalBehavior::Restart) { + Ok(Some(req)) => req, + Ok(None) => { break Some(()); } - Ok(_) => (), - Err(err) => { - if err.kind() == ErrorKind::WouldBlock { - break None; - } else { - return Err(Error::from(err)); - } + Err(error) + if error.errno == syscall::EWOULDBLOCK || error.errno == syscall::EAGAIN => + { + break None; } - } - self.handle(&mut packet); - self.scheme_file.write_all(&packet)?; + Err(other) => { + return Err(Error::from_syscall_error( + other, + "failed to receive new request", + )) + } + }; + + let req = match request.kind() { + RequestKind::Call(c) => c, + RequestKind::OnClose { id } => { + self.on_close(id); + continue; + } + _ => { + continue; + } + }; + let caller = req.caller(); + let op = match req.op() { + Ok(op) => op, + Err(req) => { + self.scheme_file.write_response( + Response::err(syscall::EOPNOTSUPP, req), + SignalBehavior::Restart, + ); + continue; + } + }; + let resp = op.handle_sync(caller, self); + let _ = self + .scheme_file + .write_response(resp, SignalBehavior::Restart) + .map_err(|e| Error::from_syscall_error(e.into(), "failed to write response"))?; }; self.notify_scheduled_fds(); Ok(result) @@ -386,13 +412,13 @@ impl NetCfgScheme { fn notify_scheduled_fds(&mut self) { let fds_to_notify = self.notifier.borrow_mut().get_notified_fds(); for fd in fds_to_notify { - let _ = post_fevent(&mut self.scheme_file, fd, syscall::EVENT_READ.bits(), 1); + let _ = post_fevent(&self.scheme_file, fd, syscall::EVENT_READ.bits()); } } } -impl SchemeMut for NetCfgScheme { - fn open(&mut self, path: &str, _flags: usize, uid: u32, _gid: u32) -> SyscallResult { +impl SchemeSync for NetCfgScheme { + fn open(&mut self, path: &str, _flags: usize, ctx: &CallerCtx) -> SyscallResult { let mut current_node = Rc::clone(&self.root_node); for part in path.split('/') { if part.is_empty() { @@ -421,31 +447,37 @@ impl SchemeMut for NetCfgScheme { } else { None }, - uid, + uid: ctx.uid, pos: 0, read_buf, write_buf: vec![], done: false, }, ); - Ok(fd) + Ok(OpenResult::ThisScheme { + number: fd, + flags: NewFdFlags::empty(), + }) } - fn close(&mut self, fd: usize) -> SyscallResult { + 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 { - file.commit().map(|_| 0) - } else { - Ok(0) + let _ = file.commit().map(|_| 0); } - } else { - Err(SyscallError::new(syscall::EBADF)) } } - fn write(&mut self, fd: usize, buf: &[u8]) -> SyscallResult { + fn write( + &mut self, + fd: usize, + buf: &[u8], + _offset: u64, + _fcntl_flags: u32, + _ctx: &CallerCtx, + ) -> SyscallResult { let file = self .files .get_mut(&fd) @@ -474,7 +506,14 @@ impl SchemeMut for NetCfgScheme { Ok(buf.len()) } - fn read(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult { + fn read( + &mut self, + fd: usize, + buf: &mut [u8], + _offset: u64, + _fcntl_flags: u32, + _ctx: &CallerCtx, + ) -> SyscallResult { let file = self .files .get_mut(&fd) @@ -489,7 +528,7 @@ impl SchemeMut for NetCfgScheme { Ok(i) } - fn fstat(&mut self, fd: usize, stat: &mut Stat) -> SyscallResult { + fn fstat(&mut self, fd: usize, stat: &mut Stat, _ctx: &CallerCtx) -> SyscallResult<()> { let file = self .files .get_mut(&fd) @@ -506,10 +545,15 @@ impl SchemeMut for NetCfgScheme { stat.st_gid = 0; stat.st_size = file.read_buf.len() as u64; - Ok(0) + Ok(()) } - fn fevent(&mut self, fd: usize, events: SyscallEventFlags) -> SyscallResult { + fn fevent( + &mut self, + fd: usize, + events: SyscallEventFlags, + _ctx: &CallerCtx, + ) -> SyscallResult { let file = self .files .get_mut(&fd) @@ -522,14 +566,14 @@ impl SchemeMut for NetCfgScheme { Ok(SyscallEventFlags::empty()) } - fn fsync(&mut self, fd: usize) -> SyscallResult { + fn fsync(&mut self, fd: usize, _ctx: &CallerCtx) -> SyscallResult<()> { let file = self .files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; if !file.done { - let res = file.commit().map(|_| 0); + let res = file.commit(); file.done = true; res } else { diff --git a/netstack/src/scheme/socket.rs b/netstack/src/scheme/socket.rs index 182333b106..58bcbadf1f 100644 --- a/netstack/src/scheme/socket.rs +++ b/netstack/src/scheme/socket.rs @@ -1,8 +1,7 @@ use std::cell::RefCell; use std::collections::btree_map::Entry; use std::collections::BTreeMap; -use std::fs::File; -use std::io::{ErrorKind, Read, Write}; +use std::io::{Read, Write}; use std::marker::PhantomData; use std::mem; use std::ops::Deref; @@ -10,22 +9,22 @@ use std::ops::DerefMut; use std::rc::Rc; use std::str; -use libredox::flag::{self, CLOCK_MONOTONIC}; +use libredox::flag::CLOCK_MONOTONIC; +use redox_scheme::{ + scheme::{Op, SchemeSync}, + CallerCtx, OpenResult, Socket, +}; use syscall::data::TimeSpec; use syscall::flag::{EVENT_READ, EVENT_WRITE}; -use syscall::{self, KSMSG_CANCEL}; -use syscall::{ - Error as SyscallError, EventFlags as SyscallEventFlags, Packet as SyscallPacket, - Result as SyscallResult, SchemeBlockMut, -}; +use syscall::schemev2::NewFdFlags; +use syscall::{Error as SyscallError, EventFlags as SyscallEventFlags, Result as SyscallResult}; use super::Interface; -use crate::error::{Error, Result}; use crate::router::route_table::RouteTable; use crate::scheme::smoltcp::iface::SocketHandle; use smoltcp::socket::AnySocket; -use super::{post_fevent, SocketSet}; +use super::SocketSet; pub struct Context { pub iface: Interface, @@ -153,15 +152,6 @@ where } } -#[derive(Default, Clone)] -struct WaitHandle { - until: Option, - cancelling: bool, - packet: SyscallPacket, -} - -type WaitQueue = Vec; - pub type DupResult = Option<( SchemeFile, Option<(SocketHandle, ::DataT)>, @@ -209,17 +199,14 @@ where data: &mut Self::SchemeDataT, ) -> SyscallResult<()>; - fn write_buf( - &mut self, - file: &mut SocketFile, - buf: &[u8], - ) -> SyscallResult>; + fn write_buf(&mut self, file: &mut SocketFile, buf: &[u8]) + -> SyscallResult; fn read_buf( &mut self, file: &mut SocketFile, buf: &mut [u8], - ) -> SyscallResult>; + ) -> SyscallResult; fn fpath(&self, file: &SchemeFile, buf: &mut [u8]) -> SyscallResult; @@ -237,12 +224,11 @@ where { next_fd: usize, nulls: BTreeMap, - files: BTreeMap>, + pub files: BTreeMap>, ref_counts: BTreeMap, context: Context, - socket_set: Rc>, - scheme_file: File, - wait_queue: WaitQueue, + pub socket_set: Rc>, + pub scheme_file: Socket, scheme_data: SocketT::SchemeDataT, _phantom_socket: PhantomData, } @@ -255,7 +241,7 @@ where iface: Interface, route_table: Rc>, socket_set: Rc>, - scheme_file: File, + scheme_file: Socket, ) -> SocketScheme { SocketScheme { next_fd: 1, @@ -265,117 +251,13 @@ where socket_set, scheme_data: SocketT::new_scheme_data(), scheme_file, - wait_queue: Vec::new(), _phantom_socket: PhantomData, context: Context { iface, route_table }, } } - pub fn on_scheme_event(&mut self) -> Result> { - let result = loop { - let mut packet = SyscallPacket::default(); - match self.scheme_file.read(&mut packet) { - Ok(0) => { - //TODO: Cleanup must occur - break Some(()); - } - Ok(_) => (), - Err(err) => { - if err.kind() == ErrorKind::WouldBlock { - break None; - } else { - return Err(Error::from(err)); - } - } - } - if packet.a == KSMSG_CANCEL { - if let Some(idx) = self - .wait_queue - .iter() - .position(|q| q.packet.id == packet.b as u64) - { - self.wait_queue[idx].cancelling = true; - } - continue; - } - if let Some(a) = self.handle(&mut packet) { - packet.a = a; - self.scheme_file.write_all(&packet)?; - } else { - match self.handle_block(&mut packet) { - Ok(timeout) => { - self.wait_queue.push(WaitHandle { - until: timeout, - cancelling: false, - packet, - }); - } - Err(err) => { - packet.a = (-err.errno) as usize; - self.scheme_file.write_all(&packet)?; - return Err(Error::from_syscall_error( - err, - "Can't handle blocked socket", - )); - } - } - } - }; - Ok(result) - } - - pub fn notify_sockets(&mut self) -> Result<()> { - let cur_time = libredox::call::clock_gettime(flag::CLOCK_MONOTONIC) - .map_err(|e| Error::from_syscall_error(e.into(), "Can't get time"))?; - - // Notify non-blocking sockets - for (&fd, ref mut file) in &mut self.files { - let events = { - let mut socket_set = self.socket_set.borrow_mut(); - file.events(&mut socket_set) - }; - if events > 0 { - post_fevent(&mut self.scheme_file, fd, events, 1)?; - } - } - - // Wake up blocking queue - let mut i = 0; - while i < self.wait_queue.len() { - let mut packet = self.wait_queue[i].packet; - if let Some(a) = self.handle(&packet) { - self.wait_queue.remove(i); - packet.a = a; - self.scheme_file.write_all(&packet)?; - } else { - if self.wait_queue[i].cancelling { - self.wait_queue.remove(i); - packet.a = (-syscall::ECANCELED) as usize; - self.scheme_file.write_all(&packet)?; - continue; - } - match self.wait_queue[i].until { - Some(until) - if (until.tv_sec < cur_time.tv_sec - || (until.tv_sec == cur_time.tv_sec - && i64::from(until.tv_nsec) < i64::from(cur_time.tv_nsec))) => - { - self.wait_queue.remove(i); - packet.a = (-syscall::ETIMEDOUT) as usize; - self.scheme_file.write_all(&packet)?; - } - _ => { - i += 1; - } - } - } - } - - Ok(()) - } - - fn handle_block(&mut self, packet: &mut SyscallPacket) -> SyscallResult> { - let fd = packet.b; + pub fn handle_block(&mut self, op: &Op) -> SyscallResult> { + let fd = op.file_id().expect("op is not fd based request"); let (read_timeout, write_timeout) = { let file = self .files @@ -389,9 +271,9 @@ where } }?; - let mut timeout = match packet.a { - syscall::SYS_WRITE => write_timeout, - syscall::SYS_READ => read_timeout, + let mut timeout = match op { + Op::Read(_) => write_timeout, + Op::Write(_) => read_timeout, _ => None, }; @@ -512,32 +394,26 @@ where Setting::Other(setting) => SocketT::set_setting(file, setting, buf), } } -} -impl syscall::SchemeBlockMut for SocketScheme -where - SocketT: SchemeSocket + AnySocket<'static>, -{ - fn open( + fn open_inner( &mut self, path: &str, flags: usize, uid: u32, - _gid: u32, - ) -> SyscallResult> { + gid: u32, + ) -> SyscallResult { if path.is_empty() { - let null = NullFile { - flags, - uid, - gid: _gid, - }; + let null = NullFile { flags, uid, gid }; let id = self.next_fd; self.next_fd += 1; self.nulls.insert(id, null); - Ok(Some(id)) + Ok(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::empty(), + }) } else { let (socket_handle, data) = SocketT::new_socket( &mut self.socket_set.borrow_mut(), @@ -564,27 +440,38 @@ where self.ref_counts.insert(socket_handle, 1); self.files.insert(id, file); - Ok(Some(id)) + Ok(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::empty(), + }) } } +} - fn close(&mut self, fd: usize) -> SyscallResult> { +impl SchemeSync for SocketScheme +where + SocketT: SchemeSocket + AnySocket<'static>, +{ + fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> SyscallResult { + self.open_inner(path, flags, ctx.uid, ctx.gid) + } + + fn on_close(&mut self, fd: usize) { if let Some(_null) = self.nulls.remove(&fd) { - return Ok(Some(0)); + return; } let socket_handle = { - let file = self - .files - .get(&fd) - .ok_or_else(|| SyscallError::new(syscall::EBADF))?; + 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::(socket_handle); - socket.close_file(&scheme_file, &mut self.scheme_data)?; + let _ = socket.close_file(&scheme_file, &mut self.scheme_data); } // incorrect, and kernel can't send close until all references are gone @@ -620,10 +507,16 @@ where if remove { socket_set.remove(socket_handle); } - Ok(Some(0)) } - fn write(&mut self, fd: usize, buf: &[u8]) -> SyscallResult> { + fn write( + &mut self, + fd: usize, + buf: &[u8], + _offset: u64, + _fcntl_flags: u32, + _ctx: &CallerCtx, + ) -> SyscallResult { let (fd, setting) = { let file = self .files @@ -639,17 +532,25 @@ where let socket = socket_set.get_mut::(file.socket_handle); let ret = SocketT::write_buf(socket, file, buf); match ret { - Ok(None) => {} + Err(e) if e.errno == syscall::EWOULDBLOCK || e.errno == syscall::EAGAIN => { + } _ => file.write_notified = false, } return ret; } } }; - self.update_setting(fd, setting, buf).map(Some) + self.update_setting(fd, setting, buf) } - fn read(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult> { + fn read( + &mut self, + fd: usize, + buf: &mut [u8], + _offset: u64, + _fcntl_flags: u32, + _ctx: &CallerCtx, + ) -> SyscallResult { let (fd, setting) = { let file = self .files @@ -665,7 +566,8 @@ where let ret = SocketT::read_buf(socket, file, buf); match ret { - Ok(None) => {} + Err(e) if e.errno == syscall::EWOULDBLOCK || e.errno == syscall::EAGAIN => { + } _ => file.read_notified = false, } @@ -673,10 +575,10 @@ where } } }; - self.get_setting(fd, setting, buf).map(Some) + self.get_setting(fd, setting, buf) } - fn dup(&mut self, fd: usize, buf: &[u8]) -> SyscallResult> { + fn dup(&mut self, fd: usize, buf: &[u8], _ctx: &CallerCtx) -> SyscallResult { let path = str::from_utf8(buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?; if let Some((flags, uid, gid)) = self @@ -684,7 +586,7 @@ where .get(&fd) .map(|null| (null.flags, null.uid, null.gid)) { - return self.open(path, flags, uid, gid); + return self.open_inner(path, flags, uid, gid); } let new_file = { @@ -727,7 +629,7 @@ where &mut self.scheme_data, )? { Some(some) => some, - None => return Ok(None), + None => return Err(SyscallError::new(syscall::EWOULDBLOCK)), }, }; @@ -757,14 +659,18 @@ where self.files.insert(id, new_file); self.next_fd += 1; - Ok(Some(id)) + Ok(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::empty(), + }) } fn fevent( &mut self, fd: usize, events: SyscallEventFlags, - ) -> SyscallResult> { + _ctx: &CallerCtx, + ) -> SyscallResult { let file = self .files .get_mut(&fd) @@ -779,22 +685,22 @@ where } let mut socket_set = self.socket_set.borrow_mut(); let revents = SyscallEventFlags::from_bits_truncate(file.events(&mut socket_set)); - Ok(Some(revents)) + Ok(revents) } - fn fsync(&mut self, fd: usize) -> SyscallResult> { + fn fsync(&mut self, fd: usize, _ctx: &CallerCtx) -> SyscallResult<()> { { let _file = self .files .get_mut(&fd) .ok_or_else(|| SyscallError::new(syscall::EBADF))?; } - Ok(Some(0)) + Ok(()) // TODO Implement fsyncing // self.0.network_fsync() } - fn fpath(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult> { + fn fpath(&mut self, fd: usize, buf: &mut [u8], _ctx: &CallerCtx) -> SyscallResult { let file = self .files .get_mut(&fd) @@ -803,16 +709,22 @@ where let socket_set = self.socket_set.borrow(); let socket = socket_set.get::(file.socket_handle()); - socket.fpath(file, buf).map(Some) + socket.fpath(file, buf) } - fn fcntl(&mut self, fd: usize, cmd: usize, arg: usize) -> SyscallResult> { + fn fcntl( + &mut self, + fd: usize, + cmd: usize, + arg: usize, + _ctx: &CallerCtx, + ) -> SyscallResult { if let Some(ref mut null) = self.nulls.get_mut(&fd) { match cmd { - syscall::F_GETFL => Ok(Some(null.flags)), + syscall::F_GETFL => Ok(null.flags), syscall::F_SETFL => { null.flags = arg & !syscall::O_ACCMODE; - Ok(Some(0)) + Ok(0) } _ => Err(SyscallError::new(syscall::EINVAL)), } @@ -824,10 +736,10 @@ where if let SchemeFile::Socket(ref mut socket_file) = *file { match cmd { - syscall::F_GETFL => Ok(Some(socket_file.flags)), + syscall::F_GETFL => Ok(socket_file.flags), syscall::F_SETFL => { socket_file.flags = arg & !syscall::O_ACCMODE; - Ok(Some(0)) + Ok(0) } _ => Err(SyscallError::new(syscall::EINVAL)), } diff --git a/netstack/src/scheme/tcp.rs b/netstack/src/scheme/tcp.rs index 3dcd13425f..ea72d43a0b 100644 --- a/netstack/src/scheme/tcp.rs +++ b/netstack/src/scheme/tcp.rs @@ -6,11 +6,11 @@ use std::str; use syscall; use syscall::{Error as SyscallError, Result as SyscallResult}; -use super::socket::{Context, DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme}; -use super::{parse_endpoint, SocketSet}; +use super::socket::{Context, DupResult, SchemeFile, SchemeSocket, SocketFile}; +use super::{parse_endpoint, SchemeWrapper, SocketSet}; use crate::port_set::PortSet; -pub type TcpScheme = SocketScheme>; +pub type TcpScheme = SchemeWrapper>; impl<'a> SchemeSocket for TcpSocket<'a> { type SchemeDataT = PortSet; @@ -150,16 +150,16 @@ impl<'a> SchemeSocket for TcpSocket<'a> { &mut self, file: &mut SocketFile, buf: &[u8], - ) -> SyscallResult> { + ) -> SyscallResult { if !self.is_active() { Err(SyscallError::new(syscall::ENOTCONN)) } else if self.can_send() { self.send_slice(buf).expect("Can't send slice"); - Ok(Some(buf.len())) + Ok(buf.len()) } else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { Err(SyscallError::new(syscall::EAGAIN)) } else { - Ok(None) // internally scheduled to re-write + Err(SyscallError::new(syscall::EWOULDBLOCK)) // internally scheduled to re-write } } @@ -167,18 +167,18 @@ impl<'a> SchemeSocket for TcpSocket<'a> { &mut self, file: &mut SocketFile, buf: &mut [u8], - ) -> SyscallResult> { + ) -> SyscallResult { if !self.is_active() { Err(SyscallError::new(syscall::ENOTCONN)) } else if self.can_recv() { let length = self.recv_slice(buf).expect("Can't receive slice"); - Ok(Some(length)) + Ok(length) } else if !self.may_recv() { - Ok(Some(0)) + Ok(0) } else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { Err(SyscallError::new(syscall::EAGAIN)) } else { - Ok(None) // internally scheduled to re-read + Err(SyscallError::new(syscall::EWOULDBLOCK)) // internally scheduled to re-read } } diff --git a/netstack/src/scheme/udp.rs b/netstack/src/scheme/udp.rs index e02a513d0c..eb9e0d4d93 100644 --- a/netstack/src/scheme/udp.rs +++ b/netstack/src/scheme/udp.rs @@ -7,12 +7,12 @@ use std::str; use syscall; use syscall::{Error as SyscallError, Result as SyscallResult}; -use super::socket::{Context, DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme}; -use super::{parse_endpoint, Smolnetd, SocketSet}; +use super::socket::{Context, DupResult, SchemeFile, SchemeSocket, SocketFile}; +use super::{parse_endpoint, SchemeWrapper, Smolnetd, SocketSet}; use crate::port_set::PortSet; use crate::router::Router; -pub type UdpScheme = SocketScheme>; +pub type UdpScheme = SchemeWrapper>; impl<'a> SchemeSocket for UdpSocket<'a> { type SchemeDataT = PortSet; @@ -117,7 +117,7 @@ impl<'a> SchemeSocket for UdpSocket<'a> { &mut self, file: &mut SocketFile, buf: &[u8], - ) -> SyscallResult> { + ) -> SyscallResult { if !file.data.is_specified() { return Err(SyscallError::new(syscall::EADDRNOTAVAIL)); } @@ -130,11 +130,11 @@ impl<'a> SchemeSocket for UdpSocket<'a> { endpoint.port, ); self.send_slice(buf, endpoint).expect("Can't send slice"); - Ok(Some(buf.len())) + Ok(buf.len()) } else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { Err(SyscallError::new(syscall::EAGAIN)) } else { - Ok(None) // internally scheduled to re-read + Err(SyscallError::new(syscall::EWOULDBLOCK)) // internally scheduled to re-read } } @@ -142,14 +142,14 @@ impl<'a> SchemeSocket for UdpSocket<'a> { &mut self, file: &mut SocketFile, buf: &mut [u8], - ) -> SyscallResult> { + ) -> SyscallResult { if self.can_recv() { let (length, _) = self.recv_slice(buf).expect("Can't receive slice"); - Ok(Some(length)) + Ok(length) } else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { Err(SyscallError::new(syscall::EAGAIN)) } else { - Ok(None) // internally scheduled to re-read + Err(SyscallError::new(syscall::EWOULDBLOCK)) // internally scheduled to re-read } }