Merge pull request #14 from batonius/netcfg

The netcfg scheme
This commit is contained in:
Jeremy Soller
2018-01-30 12:41:01 -07:00
committed by GitHub
11 changed files with 742 additions and 61 deletions
+18 -1
View File
@@ -31,7 +31,18 @@ fn run() -> Result<()> {
.map_err(|e| Error::from_syscall_error(e, "failed to open time:"))?
as RawFd;
let (dns_file, time_file) = unsafe { (File::from_raw_fd(dns_fd), File::from_raw_fd(time_fd)) };
let nameserver_fd = syscall::open(
"netcfg:resolv/nameserver",
syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK,
).map_err(|e| Error::from_syscall_error(e, "failed to open nameserver:"))?
as RawFd;
let (dns_file, time_file) = unsafe {
(
File::from_raw_fd(dns_fd),
File::from_raw_fd(time_fd),
)
};
let dnsd = Rc::new(RefCell::new(Dnsd::new(dns_file, time_file)));
@@ -46,6 +57,12 @@ fn run() -> Result<()> {
let dnsd_ = Rc::clone(&dnsd);
event_queue
.add(nameserver_fd, move |_| dnsd_.borrow_mut().on_nameserver_event())
.map_err(|e| Error::from_io_error(e, "failed to listen to nameserver"))?;
let dnsd_ = Rc::clone(&dnsd);
event_queue.set_default_callback(move |fd, _| dnsd_.borrow_mut().on_unknown_fd_event(fd));
event_queue
+39 -13
View File
@@ -9,7 +9,9 @@ use std::io::{Read, Write};
use std::mem;
use std::os::unix::io::RawFd;
use std::str;
use std::str::FromStr;
use std::rc::Rc;
use std::net::Ipv4Addr;
use syscall::data::TimeSpec;
use syscall::{Error as SyscallError, Packet as SyscallPacket, Result as SyscallResult, SchemeMut};
use syscall;
@@ -40,6 +42,7 @@ enum DnsParsingResult {
}
struct Domains {
nameserver: Ipv4Addr,
domains: BTreeMap<Rc<str>, Domain>,
requests: BTreeMap<RawFd, Rc<str>>,
resolved_timeouts: VecDeque<(TimeSpec, Rc<str>)>,
@@ -48,11 +51,28 @@ struct Domains {
impl Domains {
fn new() -> Domains {
Domains {
let mut domains = Domains {
nameserver: Ipv4Addr::new(8, 8, 8, 8),
domains: BTreeMap::new(),
requests: BTreeMap::new(),
resolved_timeouts: VecDeque::new(),
requested_timeouts: VecDeque::new(),
};
domains.update_nameserver();
domains
}
pub fn update_nameserver(&mut self) {
if let Ok(mut file) = File::open("netcfg:resolv/nameserver") {
let mut nameserver = String::new();
if let Ok(_) = file.read_to_string(&mut nameserver) {
if let Some(line) = nameserver.lines().next() {
if let Ok(ip) = Ipv4Addr::from_str(&line) {
trace!("Changing nameserver to {}", ip);
self.nameserver = ip;
}
}
}
}
}
@@ -62,7 +82,7 @@ impl Domains {
builder.add_question(domain, QueryType::A, QueryClass::IN);
let packet = builder.build().ok()?;
let udp_fd = syscall::open(
"udp:8.8.8.8:53",
&format!("udp:{}:53", self.nameserver),
syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK,
).ok()? as RawFd;
if syscall::write(udp_fd as usize, &packet) != Ok(packet.len()) {
@@ -131,13 +151,13 @@ impl Domains {
}
Entry::Occupied(e) => e,
};
let mut buf = [0u8; 4096];
let mut buf = [0u8; 0x1000];
let readed = syscall::read(fd as usize, &mut buf).ok()?;
if readed == 0 {
return None;
}
let pkt = DNSPacket::parse(&buf).ok()?;
if pkt.header.response_code != ResponseCode::NoError || pkt.answers.len() == 0 {
if pkt.header.response_code != ResponseCode::NoError || pkt.answers.is_empty() {
if let Some(query) = pkt.questions.iter().next() {
if query.qname.to_string().to_lowercase() == e.get().as_ref() {
unsubscribe_from_fd(fd).ok()?;
@@ -290,11 +310,11 @@ impl Dnsd {
let fds_to_wakeup = self.domains.on_time_event(&time);
if !fds_to_wakeup.is_empty() {
for fd in &fds_to_wakeup {
if let Some(file) = self.files.get_mut(&fd) {
if let Some(file) = self.files.get_mut(fd) {
*file = DnsFile::Timeout;
}
}
self.wakeup_fds(fds_to_wakeup);
self.wakeup_fds(&fds_to_wakeup);
}
time.tv_sec += Dnsd::TIME_EVENT_TIMEOUT_S;
@@ -323,6 +343,7 @@ impl Dnsd {
}
pub fn on_unknown_fd_event(&mut self, fd: RawFd) -> Result<Option<()>> {
trace!("Unknown fd event {}", fd);
let mut cur_time = TimeSpec::default();
syscall::clock_gettime(syscall::CLOCK_MONOTONIC, &mut cur_time)
.map_err(|e| Error::from_syscall_error(e, "Can't get time"))?;
@@ -330,24 +351,29 @@ impl Dnsd {
match self.domains.on_fd_event(fd, &cur_time) {
Some(DnsParsingResult::FailFiles(fds_to_fail)) => {
for fd in &fds_to_fail {
if let Some(file) = self.files.get_mut(&fd) {
if let Some(file) = self.files.get_mut(fd) {
*file = DnsFile::Failed;
}
}
self.wakeup_fds(fds_to_fail);
self.wakeup_fds(&fds_to_fail);
}
Some(DnsParsingResult::WakeUpFiles(fds_to_wakeup)) => {
self.wakeup_fds(fds_to_wakeup);
self.wakeup_fds(&fds_to_wakeup);
}
None => {}
}
Ok(None)
}
fn wakeup_fds(&mut self, fds_to_wakeup: BTreeSet<usize>) {
pub fn on_nameserver_event(&mut self) -> Result<Option<()>> {
self.domains.update_nameserver();
Ok(None)
}
fn wakeup_fds(&mut self, fds_to_wakeup: &BTreeSet<usize>) {
let mut syscall_packets = vec![];
for fd in &fds_to_wakeup {
if let Some(packet) = self.wait_map.remove(&fd) {
for fd in fds_to_wakeup {
if let Some(packet) = self.wait_map.remove(fd) {
syscall_packets.push(packet);
}
}
@@ -375,7 +401,7 @@ impl Dnsd {
}
}
return true;
true
}
}
+1 -1
View File
@@ -8,7 +8,7 @@ impl Log for Logger {
}
fn log(&self, record: &LogRecord) {
println!("{}: {}", record.level(), record.args());
println!("{}: {}", record.target(), record.args());
}
}
+17 -2
View File
@@ -52,12 +52,17 @@ fn run() -> Result<()> {
.map_err(|e| Error::from_syscall_error(e, "failed to open :icmp"))?
as RawFd;
trace!("opening :netcfg");
let netcfg_fd = syscall::open(":netcfg", O_RDWR | O_CREAT | O_NONBLOCK)
.map_err(|e| Error::from_syscall_error(e, "failed to open :netcfg"))?
as RawFd;
let time_path = format!("time:{}", syscall::CLOCK_MONOTONIC);
let time_fd = syscall::open(&time_path, syscall::O_RDWR)
.map_err(|e| Error::from_syscall_error(e, "failed to open time:"))?
as RawFd;
let (network_file, ip_file, time_file, udp_file, tcp_file, icmp_file) = unsafe {
let (network_file, ip_file, time_file, udp_file, tcp_file, icmp_file, netcfg_file) = unsafe {
(
File::from_raw_fd(network_fd),
File::from_raw_fd(ip_fd),
@@ -65,6 +70,7 @@ fn run() -> Result<()> {
File::from_raw_fd(udp_fd),
File::from_raw_fd(tcp_fd),
File::from_raw_fd(icmp_fd),
File::from_raw_fd(netcfg_fd),
)
};
@@ -75,6 +81,7 @@ fn run() -> Result<()> {
tcp_file,
icmp_file,
time_file,
netcfg_file,
)));
let mut event_queue = EventQueue::<(), Error>::new()
@@ -120,10 +127,18 @@ fn run() -> Result<()> {
})
.map_err(|e| Error::from_io_error(e, "failed to listen to icmp events"))?;
let smolnetd_ = Rc::clone(&smolnetd);
event_queue
.add(time_fd, move |_| smolnetd.borrow_mut().on_time_event())
.add(time_fd, move |_| smolnetd_.borrow_mut().on_time_event())
.map_err(|e| Error::from_io_error(e, "failed to listen to time events"))?;
event_queue
.add(netcfg_fd, move |_| {
smolnetd.borrow_mut().on_netcfg_scheme_event()
})
.map_err(|e| Error::from_io_error(e, "failed to listen to netcfg events"))?;
event_queue.trigger_all(0)?;
event_queue.run()
+4 -2
View File
@@ -92,8 +92,10 @@ impl<'a, 'b> SchemeSocket for IcmpSocket<'a, 'b> {
tx_packets.push(IcmpPacketBuffer::new(vec![0; NetworkDevice::MTU]));
}
let socket = IcmpSocket::new(IcmpSocketBuffer::new(rx_packets),
IcmpSocketBuffer::new(tx_packets));
let socket = IcmpSocket::new(
IcmpSocketBuffer::new(rx_packets),
IcmpSocketBuffer::new(tx_packets),
);
let handle = socket_set.add(socket);
let mut icmp_socket = socket_set.get::<IcmpSocket>(handle);
let ident = ident_set
+46 -33
View File
@@ -1,10 +1,10 @@
use netutils::getcfg;
use smoltcp;
use smoltcp::iface::{NeighborCache, EthernetInterface, EthernetInterfaceBuilder};
use smoltcp::iface::{EthernetInterface, EthernetInterfaceBuilder, NeighborCache};
use smoltcp::socket::SocketSet as SmoltcpSocketSet;
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, IpEndpoint, Ipv4Address};
use std::cell::RefCell;
use std::collections::{VecDeque, BTreeMap};
use std::collections::{BTreeMap, VecDeque};
use std::fs::File;
use std::io::{Read, Write};
use std::mem::size_of;
@@ -21,20 +21,23 @@ use self::ip::IpScheme;
use self::tcp::TcpScheme;
use self::udp::UdpScheme;
use self::icmp::IcmpScheme;
use self::netcfg::NetCfgScheme;
mod ip;
mod socket;
mod tcp;
mod udp;
mod icmp;
mod netcfg;
type SocketSet = SmoltcpSocketSet<'static, 'static, 'static>;
type Interface = Rc<RefCell<EthernetInterface<'static, 'static, NetworkDevice>>>;
pub struct Smolnetd {
network_file: Rc<RefCell<File>>,
time_file: File,
iface: EthernetInterface<'static, 'static, NetworkDevice>,
iface: Interface,
socket_set: Rc<RefCell<SocketSet>>,
startup_time: Instant,
@@ -43,6 +46,7 @@ pub struct Smolnetd {
udp_scheme: UdpScheme,
tcp_scheme: TcpScheme,
icmp_scheme: IcmpScheme,
netcfg_scheme: NetCfgScheme,
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
buffer_pool: Rc<RefCell<BufferPool>>,
@@ -61,12 +65,13 @@ impl Smolnetd {
tcp_file: File,
icmp_file: File,
time_file: File,
netcfg_file: File,
) -> Smolnetd {
let hardware_addr = EthernetAddress::from_str(getcfg("mac").unwrap().trim())
.expect("Can't parse the 'mac' cfg");
let local_ip =
IpAddress::from_str(getcfg("ip").unwrap().trim()).expect("Can't parse the 'ip' cfg.");
let protocol_addrs = [
let protocol_addrs = vec![
IpCidr::new(local_ip, 24),
IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8),
];
@@ -83,14 +88,15 @@ impl Smolnetd {
Rc::clone(&buffer_pool),
);
let iface = EthernetInterfaceBuilder::new(network_device)
.neighbor_cache(NeighborCache::new(BTreeMap::new()))
.ethernet_addr(hardware_addr)
.ip_addrs(protocol_addrs)
.ipv4_gateway(default_gw)
.finalize();
.neighbor_cache(NeighborCache::new(BTreeMap::new()))
.ethernet_addr(hardware_addr)
.ip_addrs(protocol_addrs)
.ipv4_gateway(default_gw)
.finalize();
let iface = Rc::new(RefCell::new(iface));
let socket_set = Rc::new(RefCell::new(SocketSet::new(vec![])));
Smolnetd {
iface,
iface: Rc::clone(&iface),
socket_set: Rc::clone(&socket_set),
startup_time: Instant::now(),
time_file,
@@ -98,6 +104,7 @@ impl Smolnetd {
udp_scheme: UdpScheme::new(Rc::clone(&socket_set), udp_file),
tcp_scheme: TcpScheme::new(Rc::clone(&socket_set), tcp_file),
icmp_scheme: IcmpScheme::new(Rc::clone(&socket_set), icmp_file),
netcfg_scheme: NetCfgScheme::new(Rc::clone(&iface), netcfg_file),
input_queue,
network_file,
buffer_pool,
@@ -141,6 +148,11 @@ impl Smolnetd {
Ok(None)
}
pub fn on_netcfg_scheme_event(&mut self) -> Result<Option<()>> {
self.netcfg_scheme.on_scheme_event()?;
Ok(None)
}
fn schedule_time_event(&mut self, timeout: i64) -> Result<()> {
let mut time = TimeSpec::default();
if self.time_file.read(&mut time)? < size_of::<TimeSpec>() {
@@ -160,30 +172,33 @@ impl Smolnetd {
}
fn poll(&mut self) -> Result<i64> {
let mut iter_limit = 10usize;
let timeout = loop {
iter_limit -= 1;
if iter_limit == 0 {
break 0;
}
let timeout = {
let mut iter_limit = 10usize;
let mut iface = self.iface.borrow_mut();
let mut socket_set = self.socket_set.borrow_mut();
let timestamp = self.get_timestamp();
match self.iface.poll(&mut *self.socket_set.borrow_mut(), timestamp) {
Ok(_) => (),
Err(smoltcp::Error::Unrecognized) => (),
Err(e) => {
error!("poll error: {}", e);
break 0
loop {
if iter_limit == 0 {
break 0;
}
iter_limit -= 1;
match iface.poll(&mut socket_set, timestamp) {
Ok(_) | Err(smoltcp::Error::Unrecognized) => (),
Err(e) => {
error!("poll error: {}", e);
break 0;
}
}
match iface.poll_at(&socket_set, timestamp) {
Some(n) if n > timestamp => {
break ::std::cmp::min(::std::i64::MAX as u64, n - timestamp) as i64
}
Some(_) => {}
None => break ::std::i64::MAX,
}
}
self.notify_sockets()?;
match self.iface.poll_at(&*self.socket_set.borrow(), timestamp) {
Some(n) if n > timestamp => {
break ::std::cmp::min(::std::i64::MAX as u64, n - timestamp) as i64
},
Some(_) => {},
None => break ::std::i64::MAX
}
};
self.notify_sockets()?;
Ok(::std::cmp::min(
::std::cmp::max(Smolnetd::MIN_CHECK_TIMEOUT_MS, timeout),
Smolnetd::MAX_CHECK_TIMEOUT_MS,
@@ -197,9 +212,7 @@ impl Smolnetd {
let count = self.network_file
.borrow_mut()
.read(&mut buffer)
.map_err(|e| {
Error::from_io_error(e, "Failed to read from network file")
})?;
.map_err(|e| Error::from_io_error(e, "Failed to read from network file"))?;
if count == 0 {
break;
}
+346
View File
@@ -0,0 +1,346 @@
#[macro_use]
mod nodes;
mod notifier;
use smoltcp::wire::{EthernetAddress, IpCidr, Ipv4Address};
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::{Read, Write};
use std::rc::Rc;
use std::str::FromStr;
use std::str;
use syscall::data::Stat;
use syscall::flag::{MODE_DIR, MODE_FILE};
use syscall::{Error as SyscallError, Packet as SyscallPacket, Result as SyscallResult, SchemeMut};
use syscall;
use self::nodes::*;
use self::notifier::*;
use redox_netstack::error::Result;
use super::{post_fevent, Interface};
const WRITE_BUFFER_MAX_SIZE: usize = 0xffff;
fn parse_default_gw(value: &str) -> SyscallResult<Ipv4Address> {
let mut routes = value.lines();
if let Some(route) = routes.next() {
if !routes.next().is_none() {
return Err(SyscallError::new(syscall::EINVAL));
}
let mut words = route.split_whitespace();
if let Some("default") = words.next() {
if let Some("via") = words.next() {
if let Some(ip) = words.next() {
return Ipv4Address::from_str(ip)
.map_err(|_| SyscallError::new(syscall::EINVAL));
}
}
}
}
Err(SyscallError::new(syscall::EINVAL))
}
fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRef) -> CfgNodeRef {
cfg_node!{
"resolv" => {
"nameserver" => {
rw [dns_config, notifier]
|| {
format!("{}\n", dns_config.borrow().name_server)
}
|name_server| {
let ip = Ipv4Address::from_str(name_server.trim())
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
if !ip.is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
dns_config.borrow_mut().name_server = ip;
notifier.borrow_mut().schedule_notify("resolv/nameserver");
Ok(0)
}
}
},
"route" => {
"list" => {
ro [iface] || {
if let Some(ip) = iface.borrow().ipv4_gateway() {
format!("default via {}\n", ip)
} else {
String::new()
}
}
},
"add" => {
wo [iface, notifier] |routes| {
let default_gw = parse_default_gw(routes)?;
iface.borrow_mut().set_ipv4_gateway(Some(default_gw));
notifier.borrow_mut().schedule_notify("route/list");
Ok(0)
}
},
"rm" => {
wo [iface, notifier] |routes| {
let default_gw = parse_default_gw(routes)?;
let mut iface = iface.borrow_mut();
if iface.ipv4_gateway() != Some(default_gw) {
return Err(SyscallError::new(syscall::EINVAL));
}
iface.set_ipv4_gateway(None);
notifier.borrow_mut().schedule_notify("route/list");
Ok(0)
}
}
},
"ifaces" => {
"eth0" => {
"mac" => {
rw [iface, notifier]
|| {
format!("{}\n", iface.borrow().ethernet_addr())
}
|mac| {
let mac = mac.lines().next()
.ok_or_else(|| SyscallError::new(syscall::EINVAL))?;
let mac = EthernetAddress::from_str(mac).
map_err(|_| SyscallError::new(syscall::EINVAL))?;
if !mac.is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
iface.borrow_mut().set_ethernet_addr(mac);
notifier.borrow_mut().schedule_notify("ifaces/eth0/mac");
Ok(0)
}
},
"addr" => {
"list" => {
ro [iface] || {
let mut ips = String::new();
for cidr in iface.borrow().ip_addrs() {
ips += &format!("{}\n", cidr);
}
ips
}
},
"add" => {
wo [iface, notifier] |input| {
let mut iface = iface.borrow_mut();
let mut cidrs = iface.ip_addrs().to_vec();
for cidr in input.lines() {
let cidr = IpCidr::from_str(cidr)
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
if !cidr.address().is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
cidrs.insert(0, cidr);
}
iface.update_ip_addrs(|s| {
*s = From::from(cidrs);
});
notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list");
Ok(0)
}
},
"rm" => {
wo [iface, notifier] |input| {
let mut iface = iface.borrow_mut();
let mut cidrs = iface.ip_addrs().to_vec();
for cidr in input.lines() {
let cidr = IpCidr::from_str(cidr)
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
if !cidr.address().is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
let pre_retain_len = cidrs.len();
cidrs.retain(|&c| c != cidr);
if pre_retain_len == cidrs.len() {
return Err(SyscallError::new(syscall::EINVAL));
}
}
iface.update_ip_addrs(|s| {
*s = From::from(cidrs);
});
notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list");
Ok(0)
}
},
}
}
}
}
}
struct DNSConfig {
name_server: Ipv4Address,
}
type DNSConfigRef = Rc<RefCell<DNSConfig>>;
struct NetCfgFile {
path: String,
cfg_node: CfgNodeRef,
read_buf: Vec<u8>,
write_buf: Vec<u8>,
pos: usize,
uid: u32,
}
pub struct NetCfgScheme {
scheme_file: File,
next_fd: usize,
files: BTreeMap<usize, NetCfgFile>,
root_node: CfgNodeRef,
notifier: NotifierRef,
}
impl NetCfgScheme {
pub fn new(iface: Interface, scheme_file: File) -> NetCfgScheme {
let notifier = Notifier::new_ref();
let dns_config = Rc::new(RefCell::new(DNSConfig {
name_server: Ipv4Address::new(8, 8, 8, 8),
}));
NetCfgScheme {
scheme_file,
next_fd: 1,
files: BTreeMap::new(),
root_node: mk_root_node(iface, Rc::clone(&notifier), dns_config),
notifier,
}
}
pub fn on_scheme_event(&mut self) -> Result<Option<()>> {
loop {
let mut packet = SyscallPacket::default();
if self.scheme_file.read(&mut packet)? == 0 {
break;
}
self.handle(&mut packet);
self.scheme_file.write_all(&packet)?;
}
self.notify_scheduled_fds();
Ok(None)
}
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, 1);
}
}
}
impl SchemeMut for NetCfgScheme {
fn open(&mut self, url: &[u8], _flags: usize, uid: u32, _gid: u32) -> SyscallResult<usize> {
let path = str::from_utf8(url).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
let mut current_node = Rc::clone(&self.root_node);
for part in path.split('/') {
if part.is_empty() {
continue;
}
let next_node = current_node
.borrow_mut()
.open(part)
.ok_or_else(|| SyscallError::new(syscall::EINVAL))?;
current_node = next_node;
}
let read_buf = Vec::from(current_node.borrow().read());
let fd = self.next_fd;
trace!("open {} {}", fd, path);
self.next_fd += 1;
self.files.insert(
fd,
NetCfgFile {
path: path.to_owned(),
cfg_node: current_node,
uid,
pos: 0,
read_buf,
write_buf: vec![],
},
);
Ok(fd)
}
fn close(&mut self, fd: usize) -> SyscallResult<usize> {
trace!("close {}", fd);
if let Some(file) = self.files.remove(&fd) {
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
let node = file.cfg_node.borrow();
if node.is_writable() {
let value = str::from_utf8(&file.write_buf)
.or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
node.write(value)
} else {
Ok(0)
}
} else {
Err(SyscallError::new(syscall::EBADF))
}
}
fn write(&mut self, fd: usize, buf: &[u8]) -> SyscallResult<usize> {
let file = self.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
if file.uid != 0 {
return Err(SyscallError::new(syscall::EACCES));
}
if (WRITE_BUFFER_MAX_SIZE - file.write_buf.len()) < buf.len() {
return Err(SyscallError::new(syscall::EMSGSIZE));
}
file.write_buf.extend_from_slice(buf);
Ok(buf.len())
}
fn read(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult<usize> {
let file = self.files
.get_mut(&fd)
.ok_or_else(|| 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];
i += 1;
file.pos += 1;
}
Ok(i)
}
fn fstat(&mut self, fd: usize, stat: &mut Stat) -> SyscallResult<usize> {
let file = self.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let cfg_node = file.cfg_node.borrow();
stat.st_mode = if cfg_node.is_dir() {
MODE_DIR
} else {
MODE_FILE
};
if cfg_node.is_writable() {
stat.st_mode |= 0o222;
}
if cfg_node.is_readable() {
stat.st_mode |= 0o444;
}
stat.st_uid = 0;
stat.st_gid = 0;
stat.st_size = file.read_buf.len() as u64;
Ok(0)
}
fn fevent(&mut self, fd: usize, events: usize) -> SyscallResult<usize> {
let file = self.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
if events & syscall::EVENT_READ == syscall::EVENT_READ {
self.notifier.borrow_mut().subscribe(&file.path, fd);
} else {
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
}
Ok(fd)
}
}
+199
View File
@@ -0,0 +1,199 @@
use std::cell::RefCell;
use std::rc::Rc;
use std::collections::BTreeMap;
use syscall::Result as SyscallResult;
pub type CfgNodeRef = Rc<RefCell<CfgNode>>;
pub trait CfgNode {
fn is_dir(&self) -> bool {
false
}
fn is_writable(&self) -> bool {
false
}
fn is_readable(&self) -> bool {
true
}
fn read(&self) -> String {
String::new()
}
fn write(&self, _buf: &str) -> SyscallResult<usize> {
Ok(0)
}
fn open(&self, _file: &str) -> Option<CfgNodeRef> {
None
}
}
pub struct RONode<F>
where
F: Fn() -> String,
{
read_fun: F,
}
impl<F> CfgNode for RONode<F>
where
F: Fn() -> String,
{
fn read(&self) -> String {
(self.read_fun)()
}
}
impl<F> RONode<F>
where
F: 'static + Fn() -> String,
{
pub fn new_ref(read_fun: F) -> CfgNodeRef {
Rc::new(RefCell::new(RONode { read_fun }))
}
}
pub struct WONode<F>
where
F: Fn(&str) -> SyscallResult<usize>,
{
write_fun: F,
}
impl<F> CfgNode for WONode<F>
where
F: Fn(&str) -> SyscallResult<usize>,
{
fn write(&self, buf: &str) -> SyscallResult<usize> {
(self.write_fun)(buf)
}
fn is_readable(&self) -> bool {
false
}
fn is_writable(&self) -> bool {
true
}
}
impl<F> WONode<F>
where
F: 'static + Fn(&str) -> SyscallResult<usize>,
{
pub fn new_ref(write_fun: F) -> CfgNodeRef {
Rc::new(RefCell::new(WONode { write_fun }))
}
}
pub struct RWNode<F, G>
where
F: Fn() -> String,
G: Fn(&str) -> SyscallResult<usize>,
{
read_fun: F,
write_fun: G,
}
impl<F, G> CfgNode for RWNode<F, G>
where
F: Fn() -> String,
G: Fn(&str) -> SyscallResult<usize>,
{
fn read(&self) -> String {
(self.read_fun)()
}
fn write(&self, buf: &str) -> SyscallResult<usize> {
(self.write_fun)(buf)
}
fn is_writable(&self) -> bool {
true
}
}
impl<F, G> RWNode<F, G>
where
F: 'static + Fn() -> String,
G: 'static + Fn(&str) -> SyscallResult<usize>,
{
pub fn new_ref(read_fun: F, write_fun: G) -> CfgNodeRef {
Rc::new(RefCell::new(RWNode {
read_fun,
write_fun,
}))
}
}
pub struct StaticDirNode {
child_nodes: BTreeMap<String, CfgNodeRef>,
}
impl CfgNode for StaticDirNode {
fn is_dir(&self) -> bool {
true
}
fn read(&self) -> String {
let mut files = String::new();
for child in self.child_nodes.keys() {
if !files.is_empty() {
files.push('\n');
}
files += child;
}
files
}
fn open(&self, file: &str) -> Option<CfgNodeRef> {
self.child_nodes.get(file).map(|node| Rc::clone(node))
}
}
impl StaticDirNode {
pub fn new_ref(child_nodes: BTreeMap<String, CfgNodeRef>) -> CfgNodeRef {
Rc::new(RefCell::new(StaticDirNode { child_nodes }))
}
}
macro_rules! cfg_node {
(val $e:expr) => {
$e
};
(ro [ $($c:ident),* ] || $b:block ) => {
{
$(let $c = $c.clone();)*
RONode::new_ref(move|| $b)
}
};
(wo [ $($c:ident),* ] |$i:ident| $b:block ) => {
{
$(let $c = $c.clone();)*
WONode::new_ref(move |$i: &str| $b)
}
};
(rw [ $($c:ident),* ] || $rb:block |$i:ident| $wb:block ) => {
{
let read_fun = {
$(#[allow(unused_variables)] let $c = $c.clone();)*
move || $rb
};
let write_fun = {
$(#[allow(unused_variables)] let $c = $c.clone();)*
move |$i: &str| $wb
};
RWNode::new_ref(read_fun, write_fun)
}
};
($($e:expr => { $($t:tt)* }),* $(,)*) => {
{
let mut children = BTreeMap::new();
$(children.insert($e.into(), cfg_node!($($t)*));)*
StaticDirNode::new_ref(children)
}
};
}
+62
View File
@@ -0,0 +1,62 @@
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::{BTreeMap, BTreeSet};
use std::collections::btree_map::Entry;
pub struct Notifier {
listeners: BTreeMap<String, BTreeSet<usize>>,
notified: BTreeSet<usize>,
}
pub type NotifierRef = Rc<RefCell<Notifier>>;
impl Notifier {
pub fn new_ref() -> NotifierRef {
Rc::new(RefCell::new(Notifier {
listeners: BTreeMap::new(),
notified: BTreeSet::new(),
}))
}
pub fn subscribe(&mut self, path: &str, fd: usize) {
trace!("Sub fd {} to {}", fd, path);
match self.listeners.entry(path.to_owned()) {
Entry::Occupied(mut e) => {
e.get_mut().insert(fd);
}
Entry::Vacant(e) => {
let mut fds = BTreeSet::new();
fds.insert(fd);
e.insert(fds);
}
}
}
pub fn unsubscribe(&mut self, path: &str, fd: usize) {
let empty = if let Some(fds) = self.listeners.get_mut(path) {
if fds.remove(&fd) {
trace!("Unsub fd {} from {}", fd, path);
}
fds.is_empty()
} else {
false
};
if empty {
self.listeners.remove(path);
}
}
pub fn schedule_notify(&mut self, path: &str) {
trace!("Notifying {}", path);
if let Some(fds) = self.listeners.get(path) {
self.notified.extend(fds);
}
}
pub fn get_notified_fds(&mut self) -> BTreeSet<usize> {
use std::mem::swap;
let mut notified = BTreeSet::new();
swap(&mut self.notified, &mut notified);
notified
}
}
+6 -5
View File
@@ -84,8 +84,8 @@ where
{
pub fn socket_handle(&self) -> SocketHandle {
match *self {
SchemeFile::Socket(SocketFile { socket_handle, .. }) |
SchemeFile::Setting(SettingFile { socket_handle, .. }) => socket_handle,
SchemeFile::Socket(SocketFile { socket_handle, .. })
| SchemeFile::Setting(SettingFile { socket_handle, .. }) => socket_handle,
}
}
}
@@ -580,9 +580,10 @@ where
}
fn dup(&mut self, fd: usize, buf: &[u8]) -> SyscallResult<usize> {
if let Some((flags, uid, gid)) = self.nulls.get(&fd).map(|null| {
(null.flags, null.uid, null.gid)
}) {
if let Some((flags, uid, gid)) = self.nulls
.get(&fd)
.map(|null| (null.flags, null.uid, null.gid))
{
return self.open(buf, flags, uid, gid);
}
+4 -4
View File
@@ -65,8 +65,8 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
return Err(SyscallError::new(syscall::EACCES));
}
let rx_packets = vec![0; 65_535];
let tx_packets = vec![0; 65_535];
let rx_packets = vec![0; 0xffff];
let tx_packets = vec![0; 0xffff];
let rx_buffer = TcpSocketBuffer::new(rx_packets);
let tx_buffer = TcpSocketBuffer::new(tx_packets);
let socket = TcpSocket::new(rx_buffer, tx_buffer);
@@ -164,8 +164,8 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
trace!("TCP creating new listening socket");
let new_handle = SchemeFile::Socket(tcp_handle.clone_with_data(()));
let rx_packets = vec![0; 65_535];
let tx_packets = vec![0; 65_535];
let rx_packets = vec![0; 0xffff];
let tx_packets = vec![0; 0xffff];
let rx_buffer = TcpSocketBuffer::new(rx_packets);
let tx_buffer = TcpSocketBuffer::new(tx_packets);
let socket = TcpSocket::new(rx_buffer, tx_buffer);