Switch to libredox and redox-event.

This commit is contained in:
4lDO2
2024-03-18 17:10:07 +01:00
parent 7e86cc9f9f
commit 8e2d02232f
8 changed files with 447 additions and 368 deletions
+53 -54
View File
@@ -1,84 +1,74 @@
extern crate dns_parser;
extern crate event;
#[macro_use]
extern crate log;
extern crate redox_netstack;
extern crate syscall;
use anyhow::{Error, Result, Context};
use event::EventQueue;
use redox_netstack::error::{Error, Result};
use ioslice::IoSlice;
use libredox::Fd;
use redox_netstack::logger;
use scheme::Dnsd;
use std::cell::RefCell;
use std::fs::File;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::os::unix::io::{FromRawFd, RawFd};
use std::process;
use std::rc::Rc;
mod scheme;
fn run(daemon: redox_daemon::Daemon) -> Result<()> {
use syscall::flag::*;
use libredox::flag::*;
let dns_fd = syscall::open(":dns", O_RDWR | O_CREAT | O_NONBLOCK)
.map_err(|e| Error::from_syscall_error(e, "failed to open :dns"))?
as RawFd;
let dns_fd = Fd::open(":dns", O_RDWR | O_CREAT | O_NONBLOCK, 0)
.context("failed to open :dns")?;
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 time_path = format!("time:{}", CLOCK_MONOTONIC);
let time_fd = Fd::open(&time_path, O_RDWR, 0)
.context("failed to open time")?;
let nameserver_fd = syscall::open(
let nameserver_fd = Fd::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;
O_RDWR | O_CREAT | O_NONBLOCK,
0,
).context("failed to open nameserver")?;
let event_queue = EventQueue::<EventSource>::new()
.context("failed to create event queue")?;
event_queue
.subscribe(dns_fd.raw(), EventSource::DnsScheme, event::EventFlags::READ)
.context("failed to listen to time events")?;
event_queue
.subscribe(nameserver_fd.raw(), EventSource::NameserverScheme, event::EventFlags::READ)
.context("failed to listen to nameserver socket events")?;
event_queue
.subscribe(time_fd.raw(), EventSource::Timer, event::EventFlags::READ)
.context("failed to listen to timer events")?;
let (dns_file, time_file) = unsafe {
(
File::from_raw_fd(dns_fd),
File::from_raw_fd(time_fd),
File::from_raw_fd(dns_fd.into_raw() as RawFd),
File::from_raw_fd(time_fd.into_raw() as RawFd),
)
};
let mut event_queue = EventQueue::<(), Error>::new()
.map_err(|e| Error::from_io_error(e, "failed to create event queue"))?;
let mut dnsd = Dnsd::new(dns_file, time_file, &event_queue);
let dnsd = Rc::new(RefCell::new(Dnsd::new(dns_file, time_file, event_queue.file.as_raw_fd())));
let new_ns = syscall::mkns(&[["udp".as_ptr() as usize, "udp".len()]])
let new_ns = libredox::call::mkns(&[IoSlice::new(b"dns")])
.expect("dnsd: failed to create namespace");
syscall::setrens(new_ns, new_ns).expect("dnsd: failed to enter namespace");
libredox::call::setrens(new_ns, new_ns).expect("dnsd: failed to enter namespace");
daemon.ready().expect("dnsd: failed to notify parent");
let dnsd_ = Rc::clone(&dnsd);
event_queue
.add(dns_fd, move |_| dnsd_.borrow_mut().on_dns_file_event())
.map_err(|e| Error::from_io_error(e, "failed to listen to time events"))?;
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 |event| dnsd_.borrow_mut().on_unknown_fd_event(event.fd));
event_queue
.add(time_fd, move |_| dnsd.borrow_mut().on_time_event())
.map_err(|e| Error::from_io_error(e, "failed to listen to time events"))?;
event_queue.trigger_all(event::Event {
fd: 0,
flags: EventFlags::empty(),
})?;
event_queue.run()
for event_res in event_queue.iter() {
let event = event_res.context("failed to read from event queue")?;
match event.user_data {
EventSource::DnsScheme => if !dnsd.on_dns_file_event()? {
break
},
EventSource::NameserverScheme => dnsd.on_nameserver_event()?,
EventSource::Timer => dnsd.on_time_event()?,
EventSource::Other => dnsd.on_unknown_fd_event(event.fd as RawFd)?,
}
}
Ok(())
}
fn main() {
@@ -91,3 +81,12 @@ fn main() {
process::exit(0);
}).expect("dnsd: failed to daemonize");
}
event::user_data! {
enum EventSource {
DnsScheme,
NameserverScheme,
Timer,
Other,
}
}
+54 -48
View File
@@ -1,5 +1,3 @@
use redox_netstack::error::{Error, Result};
use event::{subscribe_to_fd, unsubscribe_from_fd};
use std::borrow::ToOwned;
use std::collections::{BTreeMap, BTreeSet};
use std::collections::VecDeque;
@@ -12,13 +10,19 @@ use std::str;
use std::str::FromStr;
use std::rc::Rc;
use std::net::Ipv4Addr;
use syscall::data::TimeSpec;
use syscall::{Error as SyscallError, EventFlags as SyscallEventFlags, Packet as SyscallPacket, Result as SyscallResult, SchemeMut};
use syscall;
use event::EventQueue;
use redox_netstack::error::{Error, Result};
use dns_parser::{Builder, Packet as DNSPacket, RRData, ResponseCode};
use dns_parser::{QueryClass, QueryType};
use crate::EventSource;
enum DnsFile {
Resolved { data: Rc<[u8]>, pos: usize },
Waiting { domain: String },
@@ -76,25 +80,26 @@ impl Domains {
}
}
fn request_domain(&mut self, domain: &str, queue_fd: RawFd) -> Option<RawFd> {
fn request_domain(&mut self, domain: &str, queue: &EventQueue<EventSource>) -> Option<RawFd> {
trace!("Requesting domain {}", domain);
let mut builder = Builder::new_query(1, true);
builder.add_question(domain, QueryType::A, QueryClass::IN);
let packet = builder.build().ok()?;
let udp_fd = syscall::open(
let udp_fd = libredox::call::open(
&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()) {
syscall::close(udp_fd as usize).ok()?;
libredox::flag::O_RDWR | libredox::flag::O_CREAT | libredox::flag::O_NONBLOCK,
0,
).ok()?;
if libredox::call::write(udp_fd, &packet) != Ok(packet.len()) {
libredox::call::close(udp_fd).ok()?;
return None;
}
subscribe_to_fd(queue_fd, udp_fd, 0xFFFFFFFF).ok()?;
self.requests.insert(udp_fd, domain.to_owned().into());
Some(udp_fd)
queue.subscribe(udp_fd, EventSource::Other, event::EventFlags::READ).ok()?;
self.requests.insert(udp_fd as RawFd, domain.to_owned().into());
Some(udp_fd as RawFd)
}
fn on_time_event(&mut self, cur_time: &TimeSpec, queue_fd: RawFd) -> BTreeSet<usize> {
fn on_time_event(&mut self, cur_time: &TimeSpec, queue: &EventQueue<EventSource>) -> Result<BTreeSet<usize>> {
while let Some((timeout, domain)) = self.resolved_timeouts.pop_front() {
if timeout.tv_sec > cur_time.tv_sec
|| (timeout.tv_sec == cur_time.tv_sec && timeout.tv_nsec > cur_time.tv_nsec)
@@ -133,18 +138,18 @@ impl Domains {
} = e.remove()
{
fds_to_wakeup.append(&mut waiting_fds);
let _ = unsubscribe_from_fd(queue_fd, socket_fd, 0xFFFFFFFF);
let _ = syscall::close(socket_fd as usize);
queue.unsubscribe(socket_fd as usize).map_err(|e| Error::from_syscall_error(e.into(), "unsubscribe failure"))?;
let _ = libredox::call::close(socket_fd as usize);
}
}
}
}
}
fds_to_wakeup
Ok(fds_to_wakeup)
}
fn on_fd_event(&mut self, fd: RawFd, cur_time: &TimeSpec, queue_fd: RawFd) -> Option<DnsParsingResult> {
fn on_fd_event(&mut self, fd: RawFd, cur_time: &TimeSpec, queue: &EventQueue<EventSource>) -> Option<DnsParsingResult> {
let e = match self.requests.entry(fd) {
Entry::Vacant(_) => {
return None;
@@ -152,7 +157,7 @@ impl Domains {
Entry::Occupied(e) => e,
};
let mut buf = [0u8; 0x1000];
let readed = syscall::read(fd as usize, &mut buf).ok()?;
let readed = libredox::call::read(fd as usize, &mut buf).ok()?;
if readed == 0 {
return None;
}
@@ -160,8 +165,8 @@ impl Domains {
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(queue_fd, fd, 0xFFFFFFFF).ok()?;
syscall::close(fd as usize).ok()?;
queue.unsubscribe(fd as usize).ok()?;
libredox::call::close(fd as usize).ok()?;
let domain = e.remove();
self.requested_timeouts
.retain(|&(_, ref d)| d.as_ref() != domain.as_ref());
@@ -190,8 +195,8 @@ impl Domains {
return None;
}
let data = Rc::from(result.into_bytes());
unsubscribe_from_fd(queue_fd, fd, 0xFFFFFFFF).ok()?;
syscall::close(fd as usize).ok()?;
queue.unsubscribe(fd as usize).ok()?;
libredox::call::close(fd as usize).ok()?;
let domain = e.remove();
let mut domain_data = Domain::Resolved { data };
trace!("On FD event {} {} resolved", fd, domain);
@@ -221,7 +226,7 @@ impl Domains {
}
}
fn file_from_domain(&mut self, domain: &str, fd: usize, cur_time: &TimeSpec, queue_fd: RawFd) -> DnsFile {
fn file_from_domain(&mut self, domain: &str, fd: usize, cur_time: &TimeSpec, queue: &EventQueue<EventSource>) -> DnsFile {
if let Some(domain_data) = self.domains.get_mut(domain) {
match *domain_data {
Domain::Resolved { ref data } => DnsFile::Resolved {
@@ -239,7 +244,7 @@ impl Domains {
}
}
} else {
if let Some(socket_fd) = self.request_domain(domain, queue_fd) {
if let Some(socket_fd) = self.request_domain(domain, queue) {
let mut waiting_fds = BTreeSet::new();
let domain = domain.to_owned().into();
waiting_fds.insert(fd);
@@ -273,26 +278,26 @@ impl Domains {
}
}
pub struct Dnsd {
pub struct Dnsd<'q> {
dns_file: File,
time_file: File,
queue_fd: RawFd,
queue: &'q EventQueue<EventSource>,
files: BTreeMap<usize, DnsFile>,
domains: Domains,
wait_map: BTreeMap<usize, SyscallPacket>,
next_fd: usize,
}
impl Dnsd {
impl<'q> Dnsd<'q> {
const RESOLVED_TIMEOUT_S: i64 = 5 * 60;
const REQUEST_TIMEOUT_S: i64 = 30;
const TIME_EVENT_TIMEOUT_S: i64 = 5;
pub fn new(dns_file: File, time_file: File, queue_fd: RawFd) -> Dnsd {
pub fn new(dns_file: File, time_file: File, queue: &'q EventQueue<EventSource>) -> Dnsd {
Dnsd {
dns_file,
time_file,
queue_fd,
queue,
files: BTreeMap::new(),
domains: Domains::new(),
wait_map: BTreeMap::new(),
@@ -300,7 +305,7 @@ impl Dnsd {
}
}
pub fn on_time_event(&mut self) -> Result<Option<()>> {
pub fn on_time_event(&mut self) -> Result<()> {
let mut time = TimeSpec::default();
if self.time_file.read(&mut time)? < mem::size_of::<TimeSpec>() {
return Err(Error::from_syscall_error(
@@ -309,7 +314,7 @@ impl Dnsd {
));
}
let fds_to_wakeup = self.domains.on_time_event(&time, self.queue_fd);
let fds_to_wakeup = self.domains.on_time_event(&time, self.queue)?;
if !fds_to_wakeup.is_empty() {
for fd in &fds_to_wakeup {
if let Some(file) = self.files.get_mut(fd) {
@@ -323,24 +328,25 @@ impl Dnsd {
self.time_file
.write_all(&time)
.map_err(|e| Error::from_io_error(e, "Failed to write to time file"))?;
Ok(None)
Ok(())
}
pub fn on_dns_file_event(&mut self) -> Result<Option<()>> {
let result = loop {
pub fn on_dns_file_event(&mut self) -> Result<bool> {
loop {
let mut packet = SyscallPacket::default();
match self.dns_file.read(&mut packet) {
Ok(0) => {
//TODO: Cleanup must occur
break Some(());
return Ok(false);
},
Ok(_) => (),
Err(err) => if err.kind() == ErrorKind::WouldBlock {
break None;
return Ok(true);
} else {
return Err(Error::from(err));
}
}
// TODO: implement cancellation
let a = packet.a;
self.handle(&mut packet);
if packet.a != (-syscall::EWOULDBLOCK) as usize {
@@ -349,17 +355,17 @@ impl Dnsd {
packet.a = a;
self.handle_block(packet)?;
}
};
Ok(result)
}
}
pub fn on_unknown_fd_event(&mut self, fd: RawFd) -> Result<Option<()>> {
pub fn on_unknown_fd_event(&mut self, fd: RawFd) -> Result<()> {
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"))?;
let cur_time = libredox::call::clock_gettime(libredox::flag::CLOCK_MONOTONIC)
.map_err(|e| Error::from_syscall_error(e.into(), "Can't get time"))?;
// TODO
let cur_time = TimeSpec { tv_sec: cur_time.tv_sec, tv_nsec: cur_time.tv_nsec as _ };
match self.domains.on_fd_event(fd, &cur_time, self.queue_fd) {
match self.domains.on_fd_event(fd, &cur_time, self.queue) {
Some(DnsParsingResult::FailFiles(fds_to_fail)) => {
for fd in &fds_to_fail {
if let Some(file) = self.files.get_mut(fd) {
@@ -373,12 +379,12 @@ impl Dnsd {
}
None => {}
}
Ok(None)
Ok(())
}
pub fn on_nameserver_event(&mut self) -> Result<Option<()>> {
pub fn on_nameserver_event(&mut self) -> Result<()> {
self.domains.update_nameserver();
Ok(None)
Ok(())
}
fn wakeup_fds(&mut self, fds_to_wakeup: &BTreeSet<usize>) {
@@ -416,7 +422,7 @@ impl Dnsd {
}
}
impl SchemeMut for Dnsd {
impl SchemeMut for Dnsd<'_> {
fn open(&mut self, url: &str, _flags: usize, _uid: u32, _gid: u32) -> SyscallResult<usize> {
let domain = url.to_lowercase();
if domain.is_empty() || !Dnsd::validate_domain(&domain) {
@@ -426,7 +432,7 @@ impl SchemeMut for Dnsd {
self.next_fd += 1;
let mut cur_time = TimeSpec::default();
syscall::clock_gettime(syscall::CLOCK_MONOTONIC, &mut cur_time)?;
let dns_file = self.domains.file_from_domain(&domain, fd, &cur_time, self.queue_fd);
let dns_file = self.domains.file_from_domain(&domain, fd, &cur_time, self.queue);
self.files.insert(fd, dns_file);
trace!("Open {} {}", &domain, fd);
Ok(fd)
@@ -460,7 +466,7 @@ impl SchemeMut for Dnsd {
syscall::clock_gettime(syscall::CLOCK_MONOTONIC, &mut cur_time)?;
if let DnsFile::Waiting { ref domain } = *file {
*file = self.domains.file_from_domain(domain, fd, &cur_time, self.queue_fd);
*file = self.domains.file_from_domain(domain, fd, &cur_time, self.queue);
}
match *file {
+3
View File
@@ -4,12 +4,14 @@ use std::result;
use std::io::Error as IOError;
use syscall::error::Error as SyscallError;
#[derive(Debug)]
enum ErrorType {
Syscall(SyscallError),
IOError(IOError),
Other,
}
#[derive(Debug)]
pub struct Error {
error_type: ErrorType,
descr: String,
@@ -53,6 +55,7 @@ impl fmt::Display for Error {
}
}
}
impl std::error::Error for Error {}
impl convert::From<IOError> for Error {
fn from(e: IOError) -> Self {
+76 -97
View File
@@ -13,12 +13,14 @@ use std::os::unix::io::{FromRawFd, RawFd};
use std::process;
use std::rc::Rc;
use event::EventQueue;
use redox_netstack::error::{Error, Result};
use event::{EventQueue, EventFlags};
use libredox::Fd;
use libredox::flag::{O_RDWR, O_NONBLOCK, O_CREAT};
use anyhow::{Result, anyhow, bail, Context};
use redox_netstack::logger;
use scheme::Smolnetd;
use smoltcp::wire::EthernetAddress;
use syscall::flag::*;
mod buffer_pool;
mod link;
@@ -48,7 +50,7 @@ fn get_network_adapter() -> Result<String> {
}
if adapters.is_empty() {
Err(Error::other_error("no network adapter found"))
bail!("no network adapter found");
} else {
let adapter = adapters.remove(0);
if !adapters.is_empty() {
@@ -62,129 +64,106 @@ fn get_network_adapter() -> Result<String> {
fn run(daemon: redox_daemon::Daemon) -> Result<()> {
let adapter = get_network_adapter()?;
trace!("opening {adapter}:");
let network_fd = syscall::open(format!("{adapter}:"), O_RDWR | O_NONBLOCK)
.map_err(|e| Error::from_syscall_error(e, format!("failed to open {adapter}:")))?
as RawFd;
let network_fd = Fd::open(&format!("{adapter}:"), O_RDWR | O_NONBLOCK, 0)
.map_err(|e| anyhow!("failed to open {adapter}: {e}"))?;
let hardware_addr = std::fs::read(format!("{adapter}:mac"))
.map(|mac_address| EthernetAddress::from_bytes(&mac_address))
.expect("failed to get mac address from network adapter");
.context("failed to get mac address from network adapter")?;
trace!("opening :ip");
let ip_fd = syscall::open(":ip", O_RDWR | O_CREAT | O_NONBLOCK)
.map_err(|e| Error::from_syscall_error(e, "failed to open :ip"))? as RawFd;
let ip_fd = Fd::open(":ip", O_RDWR | O_CREAT | O_NONBLOCK, 0)
.context("failed to open :ip")?;
trace!("opening :udp");
let udp_fd = syscall::open(":udp", O_RDWR | O_CREAT | O_NONBLOCK)
.map_err(|e| Error::from_syscall_error(e, "failed to open :udp"))?
as RawFd;
let udp_fd = Fd::open(":udp", O_RDWR | O_CREAT | O_NONBLOCK, 0)
.context("failed to open :udp")?;
trace!("opening :tcp");
let tcp_fd = syscall::open(":tcp", O_RDWR | O_CREAT | O_NONBLOCK)
.map_err(|e| Error::from_syscall_error(e, "failed to open :tcp"))?
as RawFd;
let tcp_fd = Fd::open(":tcp", O_RDWR | O_CREAT | O_NONBLOCK, 0)
.context("failed to open :tcp")?;
trace!("opening :icmp");
let icmp_fd = syscall::open(":icmp", O_RDWR | O_CREAT | O_NONBLOCK)
.map_err(|e| Error::from_syscall_error(e, "failed to open :icmp"))?
as RawFd;
let icmp_fd = Fd::open(":icmp", O_RDWR | O_CREAT | O_NONBLOCK, 0)
.context("failed to open :icmp")?;
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 netcfg_fd = Fd::open(":netcfg", O_RDWR | O_CREAT | O_NONBLOCK, 0)
.context("failed to open :netcfg")?;
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 time_fd = Fd::open(&time_path, O_RDWR, 0)
.context("failed to open time:")?;
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),
File::from_raw_fd(time_fd),
File::from_raw_fd(udp_fd),
File::from_raw_fd(tcp_fd),
File::from_raw_fd(icmp_fd),
File::from_raw_fd(netcfg_fd),
)
};
event::user_data! {
enum EventSource {
Network,
Time,
IpScheme,
UdpScheme,
TcpScheme,
IcmpScheme,
NetcfgScheme,
}
}
let smolnetd = Rc::new(RefCell::new(Smolnetd::new(
network_file,
hardware_addr,
ip_file,
udp_file,
tcp_file,
icmp_file,
time_file,
netcfg_file,
)));
let mut event_queue = EventQueue::<(), Error>::new()
.map_err(|e| Error::from_io_error(e, "failed to create event queue"))?;
syscall::setrens(0, 0).expect("smolnetd: failed to enter null namespace");
let event_queue = EventQueue::<EventSource>::new()
.context("failed to create event queue")?;
daemon.ready().expect("smolnetd: failed to notify parent");
let smolnetd_ = Rc::clone(&smolnetd);
event_queue.subscribe(network_fd.raw(), EventSource::Network, EventFlags::READ)
.context("failed to listen to network events")?;
event_queue
.add(network_fd, move |_| {
smolnetd_.borrow_mut().on_network_scheme_event()
})
.map_err(|e| Error::from_io_error(e, "failed to listen to network events"))?;
event_queue.subscribe(time_fd.raw(), EventSource::Time, EventFlags::READ)
.context("failed to listen to timer events")?;
let smolnetd_ = Rc::clone(&smolnetd);
event_queue.subscribe(ip_fd.raw(), EventSource::IpScheme, EventFlags::READ)
.context("failed to listen to ip scheme events")?;
event_queue
.add(ip_fd, move |_| smolnetd_.borrow_mut().on_ip_scheme_event())
.map_err(|e| Error::from_io_error(e, "failed to listen to ip events"))?;
event_queue.subscribe(udp_fd.raw(), EventSource::UdpScheme, EventFlags::READ)
.context("failed to listen to udp scheme events")?;
let smolnetd_ = Rc::clone(&smolnetd);
event_queue.subscribe(tcp_fd.raw(), EventSource::TcpScheme, EventFlags::READ)
.context("failed to listen to tcp scheme events")?;
event_queue
.add(udp_fd, move |_| {
smolnetd_.borrow_mut().on_udp_scheme_event()
})
.map_err(|e| Error::from_io_error(e, "failed to listen to udp events"))?;
event_queue.subscribe(icmp_fd.raw(), EventSource::IcmpScheme, EventFlags::READ)
.context("failed to listen to icmp scheme events")?;
let smolnetd_ = Rc::clone(&smolnetd);
event_queue.subscribe(netcfg_fd.raw(), EventSource::NetcfgScheme, EventFlags::READ)
.context("failed to listen to netcfg scheme events")?;
event_queue
.add(tcp_fd, move |_| {
smolnetd_.borrow_mut().on_tcp_scheme_event()
})
.map_err(|e| Error::from_io_error(e, "failed to listen to tcp events"))?;
let mut smolnetd = Smolnetd::new(
network_fd,
hardware_addr,
ip_fd,
udp_fd,
tcp_fd,
icmp_fd,
time_fd,
netcfg_fd,
);
let smolnetd_ = Rc::clone(&smolnetd);
libredox::call::setrens(0, 0)
.context("smolnetd: failed to enter null namespace")?;
event_queue
.add(icmp_fd, move |_| {
smolnetd_.borrow_mut().on_icmp_scheme_event()
})
.map_err(|e| Error::from_io_error(e, "failed to listen to icmp events"))?;
let all = {
use EventSource::*;
[Network, Time, IpScheme, UdpScheme, IcmpScheme, NetcfgScheme].map(Ok)
};
let smolnetd_ = Rc::clone(&smolnetd);
event_queue
.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(event::Event {
fd: 0,
flags: EventFlags::empty(),
})?;
event_queue.run()
for event_res in all.into_iter().chain(event_queue.map(|r| r.map(|e| e.user_data))) {
match event_res? {
EventSource::Network => smolnetd.on_network_scheme_event()?,
EventSource::Time => smolnetd.on_time_event()?,
EventSource::IpScheme => smolnetd.on_ip_scheme_event()?,
EventSource::UdpScheme => smolnetd.on_udp_scheme_event()?,
EventSource::TcpScheme => smolnetd.on_tcp_scheme_event()?,
EventSource::IcmpScheme => smolnetd.on_icmp_scheme_event()?,
EventSource::NetcfgScheme => smolnetd.on_netcfg_scheme_event()?,
}
}
Ok(())
}
fn main() {
+29 -27
View File
@@ -4,6 +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 libredox::Fd;
use netutils::getcfg;
use smoltcp;
use smoltcp::iface::{Config, Interface as SmoltcpInterface};
@@ -16,6 +17,7 @@ use std::cell::RefCell;
use std::fs::File;
use std::io::{Read, Write};
use std::mem::size_of;
use std::os::fd::{FromRawFd, RawFd};
use std::rc::Rc;
use std::str::FromStr;
use syscall;
@@ -63,14 +65,14 @@ impl Smolnetd {
pub const MAX_CHECK_TIMEOUT: Duration = Duration::from_millis(500);
pub fn new(
network_file: File,
network_file: Fd,
hardware_addr: EthernetAddress,
ip_file: File,
udp_file: File,
tcp_file: File,
icmp_file: File,
time_file: File,
netcfg_file: File,
ip_file: Fd,
udp_file: Fd,
tcp_file: Fd,
icmp_file: Fd,
time_file: Fd,
netcfg_file: Fd,
) -> Smolnetd {
let protocol_addrs = vec![
IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8),
@@ -108,7 +110,7 @@ impl Smolnetd {
let mut eth0 = EthernetLink::new(
"eth0",
network_file,
unsafe { File::from_raw_fd(network_file.into_raw() as RawFd) },
);
eth0.set_mac_address(hardware_addr);
@@ -120,79 +122,79 @@ impl Smolnetd {
router_device: network_device,
socket_set: Rc::clone(&socket_set),
timer: ::std::time::Instant::now(),
time_file,
time_file: unsafe { File::from_raw_fd(time_file.into_raw() as RawFd) },
ip_scheme: IpScheme::new(
Rc::clone(&iface),
Rc::clone(&route_table),
Rc::clone(&socket_set),
ip_file,
unsafe { File::from_raw_fd(ip_file.into_raw() as RawFd) },
),
udp_scheme: UdpScheme::new(
Rc::clone(&iface),
Rc::clone(&route_table),
Rc::clone(&socket_set),
udp_file,
unsafe { File::from_raw_fd(udp_file.into_raw() as RawFd) },
),
tcp_scheme: TcpScheme::new(
Rc::clone(&iface),
Rc::clone(&route_table),
Rc::clone(&socket_set),
tcp_file,
unsafe { File::from_raw_fd(tcp_file.into_raw() as RawFd) },
),
icmp_scheme: IcmpScheme::new(
Rc::clone(&iface),
Rc::clone(&route_table),
Rc::clone(&socket_set),
icmp_file,
unsafe { File::from_raw_fd(icmp_file.into_raw() as RawFd) },
),
netcfg_scheme: NetCfgScheme::new(
Rc::clone(&iface),
netcfg_file,
unsafe { File::from_raw_fd(netcfg_file.into_raw() as RawFd) },
Rc::clone(&route_table),
Rc::clone(&devices),
),
}
}
pub fn on_network_scheme_event(&mut self) -> Result<Option<()>> {
pub fn on_network_scheme_event(&mut self) -> Result<()> {
self.poll()?;
Ok(None)
Ok(())
}
pub fn on_ip_scheme_event(&mut self) -> Result<Option<()>> {
pub fn on_ip_scheme_event(&mut self) -> Result<()> {
self.ip_scheme.on_scheme_event()?;
let _ = self.poll()?;
Ok(None)
Ok(())
}
pub fn on_udp_scheme_event(&mut self) -> Result<Option<()>> {
pub fn on_udp_scheme_event(&mut self) -> Result<()> {
self.udp_scheme.on_scheme_event()?;
let _ = self.poll()?;
Ok(None)
Ok(())
}
pub fn on_tcp_scheme_event(&mut self) -> Result<Option<()>> {
pub fn on_tcp_scheme_event(&mut self) -> Result<()> {
self.tcp_scheme.on_scheme_event()?;
let _ = self.poll()?;
Ok(None)
Ok(())
}
pub fn on_icmp_scheme_event(&mut self) -> Result<Option<()>> {
pub fn on_icmp_scheme_event(&mut self) -> Result<()> {
self.icmp_scheme.on_scheme_event()?;
let _ = self.poll()?;
Ok(None)
Ok(())
}
pub fn on_time_event(&mut self) -> Result<Option<()>> {
pub fn on_time_event(&mut self) -> Result<()> {
let timeout = self.poll()?;
self.schedule_time_event(timeout)?;
//TODO: Fix network scheme to ensure events are not missed
self.on_network_scheme_event()
}
pub fn on_netcfg_scheme_event(&mut self) -> Result<Option<()>> {
pub fn on_netcfg_scheme_event(&mut self) -> Result<()> {
self.netcfg_scheme.on_scheme_event()?;
Ok(None)
Ok(())
}
fn schedule_time_event(&mut self, timeout: Duration) -> Result<()> {
+12 -8
View File
@@ -10,7 +10,8 @@ use std::ops::DerefMut;
use std::rc::Rc;
use std::str;
use syscall;
use libredox::flag::CLOCK_MONOTONIC;
use syscall::{self, KSMSG_CANCEL};
use syscall::data::TimeSpec;
use syscall::flag::{EVENT_READ, EVENT_WRITE};
use syscall::{
@@ -286,6 +287,10 @@ where
}
}
}
if packet.a == KSMSG_CANCEL {
println!("smolnetd: todo: handle cancellation");
continue;
}
if let Some(a) = self.handle(&mut packet) {
packet.a = a;
self.scheme_file.write_all(&packet)?;
@@ -372,15 +377,14 @@ where
}?;
let mut timeout = match packet.a {
syscall::SYS_WRITE => Ok(write_timeout),
syscall::SYS_READ => Ok(read_timeout),
_ => Ok(None),
}?;
syscall::SYS_WRITE => write_timeout,
syscall::SYS_READ => read_timeout,
_ => None,
};
if let Some(ref mut timeout) = timeout {
let mut cur_time = TimeSpec::default();
syscall::clock_gettime(syscall::CLOCK_MONOTONIC, &mut cur_time)?;
*timeout = add_time(timeout, &cur_time)
let cur_time = libredox::call::clock_gettime(CLOCK_MONOTONIC)?;
*timeout = add_time(timeout, &TimeSpec { tv_sec: cur_time.tv_sec, tv_nsec: cur_time.tv_nsec as i32 })
}
Ok(timeout)