commit 1624deadfa8aba4f9ab6cffe3c2adb72de55cdaa Author: jD91mZM2 Date: Sat Jun 2 09:00:49 2018 +0200 Initial commit diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000..5cc1fc1a2a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,14 @@ +[[package]] +name = "chand" +version = "0.1.0" +dependencies = [ + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000..841036c99e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "chand" +version = "0.1.0" +authors = ["jD91mZM2 "] + +[dependencies] +redox_syscall = "0.1.40" diff --git a/examples/chan.rs b/examples/chan.rs new file mode 100644 index 0000000000..06954e18f5 --- /dev/null +++ b/examples/chan.rs @@ -0,0 +1,46 @@ +extern crate syscall; + +use std::{ + fs::File, + io::{self, prelude::*}, + os::unix::io::{AsRawFd, FromRawFd}, + thread, + time::Duration +}; + +fn from_syscall_error(error: syscall::Error) -> io::Error { + io::Error::from_raw_os_error(error.errno as i32) +} + +fn main() -> io::Result<()> { + let server = File::create("chan:hello_world")?; + let mut client = File::open("chan:hello_world")?; + + let dup = syscall::dup(server.as_raw_fd(), b"listen").map_err(from_syscall_error)?; + let mut dup = unsafe { File::from_raw_fd(dup) }; + + dup.write(b"abc")?; + dup.flush()?; + + let mut buf = [0; 5]; + assert_eq!(client.read(&mut buf)?, 3); + assert_eq!(&buf[..3], b"abc"); + + // Tada, you can clone handles properly! + let mut client_clone = client.try_clone()?; + + let thread = thread::spawn(move || -> io::Result<()> { + thread::sleep(Duration::from_secs(1)); + client_clone.write(b"def")?; + client_clone.flush()?; + Ok(()) + }); + + let mut buf = [0; 5]; + assert_eq!(dup.read(&mut buf)?, 3); + assert_eq!(&buf[..3], b"def"); + + thread.join().unwrap().unwrap(); + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000000..2288894a9f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,57 @@ +extern crate syscall; + +use std::{ + collections::VecDeque, + fs::File, + io::{self, prelude::*} +}; +use syscall::SchemeBlockMut; + +mod scheme; + +use scheme::ChanScheme; + +fn from_syscall_error(error: syscall::Error) -> io::Error { + io::Error::from_raw_os_error(error.errno as i32) +} + +fn main() -> Result<(), Box<::std::error::Error>> { + if unsafe { syscall::clone(0) }.map_err(from_syscall_error)? != 0 { + return Ok(()); + } + + let mut scheme_file = File::create(":chan")?; + let mut scheme = ChanScheme::default(); + + let mut todo = VecDeque::with_capacity(16); + + syscall::setrens(0, 0).map_err(from_syscall_error)?; + + loop { + let mut event = syscall::Packet::default(); + scheme_file.read(&mut event)?; + + // New event has to be handled first so any previous event + // that is now updated gets processed after. + todo.push_front(event); + + let mut error = None; + + todo.retain(|event| { + if let Some(a) = scheme.handle(&event) { + // Send event back with new ID + let mut event = *event; + event.a = a; + if let Err(err) = scheme_file.write(&event) { + error = Some(err); + } + return false; + } + + true + }); + if let Some(err) = error { + return Err(Box::new(err)); + } + } +} diff --git a/src/scheme.rs b/src/scheme.rs new file mode 100644 index 0000000000..d104e221cc --- /dev/null +++ b/src/scheme.rs @@ -0,0 +1,133 @@ +use std::collections::BTreeMap; +use syscall::{flag::*, error::*, Error, SchemeBlockMut, Result}; + +pub struct Handle { + path: Option, + remote: Option, + buffer: Vec +} +impl Handle { + pub fn dup(&mut self) -> Self { + Self { + path: None, + remote: self.remote.take(), + buffer: Vec::new() + } + } +} + +#[derive(Default)] +pub struct ChanScheme { + handles: BTreeMap, + listeners: BTreeMap, + next_id: usize +} +impl SchemeBlockMut for ChanScheme { + fn open(&mut self, path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result> { + let path = ::std::str::from_utf8(path).unwrap_or(""); + if path.is_empty() { + return Err(Error::new(EPERM)); + } + if flags & O_CREAT == O_CREAT && self.listeners.contains_key(path) { + return Err(Error::new(EADDRINUSE)); + } else if flags & O_CREAT != O_CREAT && !self.listeners.contains_key(path) { + return Err(Error::new(ENOENT)); + } + + let mut handle = Handle { + path: None, + remote: None, + buffer: Vec::new() + }; + + let id = self.next_id; + if flags & O_CREAT == O_CREAT { + self.listeners.insert(String::from(path), id); + handle.path = Some(String::from(path)); + } else { + let listener = self.listeners[path]; + let handle = self.handles.get_mut(&listener).expect("orphan listener left over"); + handle.remote = Some(id); + } + self.handles.insert(id, handle); + self.next_id += 1; + Ok(Some(id)) + } + fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { + match buf { + b"listen" => { + let mut remote = match self.handles.get(&id) { + Some(ref handle) if handle.path.is_some() => handle.remote, + _ => return Err(Error::new(EBADF)) + }; + if let Some(remote) = remote { + let new_id = self.next_id; + let mut clone = self.handles.get_mut(&id).map(Handle::dup).unwrap(); + + self.handles.insert(new_id, clone); + self.next_id += 1; + + let mut remote = self.handles.get_mut(&remote).unwrap(); + remote.remote = Some(new_id); + Ok(Some(new_id)) + } else { + Ok(None) + } + }, + _ => { + return Err(Error::new(EBADF)); + } + } + } + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + let remote = match self.handles.get(&id) { + Some(handle) if handle.path.is_none() => handle.remote, + _ => return Err(Error::new(EBADF)) + }; + if let Some(remote) = remote { + let mut remote = self.handles.get_mut(&remote).unwrap(); + remote.buffer.extend(buf); + Ok(Some(buf.len())) + } else { + Err(Error::new(ENOTCONN)) + } + } + fn fsync(&mut self, id: usize) -> Result> { + match self.handles.get(&id) { + Some(handle) if handle.path.is_none() => Ok(Some(id)), + _ => Err(Error::new(EBADF)) + } + } + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let handle = match self.handles.get_mut(&id) { + Some(handle) => handle, + None => return Err(Error::new(EBADF)) + }; + if handle.path.is_some() { + // This is a listener, not a stream. + Err(Error::new(EBADF)) + } else if handle.buffer.is_empty() { + Ok(None) + } else { + let len = buf.len().min(handle.buffer.len()); + buf[..len].copy_from_slice(&handle.buffer[..len]); + handle.buffer.drain(..len); + Ok(Some(len)) + } + } + fn close(&mut self, id: usize) -> Result> { + let handle = match self.handles.remove(&id) { + Some(handle) => handle, + None => return Err(Error::new(EBADF)) + }; + + if let Some(remote) = handle.remote { + let mut remote = self.handles.get_mut(&remote).unwrap(); + remote.remote = None; + } + if let Some(path) = handle.path { + self.listeners.remove(&path); + } + Ok(Some(0)) + } +}