Initial commit

This commit is contained in:
jD91mZM2
2018-06-02 09:00:49 +02:00
commit 1624deadfa
5 changed files with 257 additions and 0 deletions
Generated
+14
View File
@@ -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"
+7
View File
@@ -0,0 +1,7 @@
[package]
name = "chand"
version = "0.1.0"
authors = ["jD91mZM2 <me@krake.one>"]
[dependencies]
redox_syscall = "0.1.40"
+46
View File
@@ -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(())
}
+57
View File
@@ -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));
}
}
}
+133
View File
@@ -0,0 +1,133 @@
use std::collections::BTreeMap;
use syscall::{flag::*, error::*, Error, SchemeBlockMut, Result};
pub struct Handle {
path: Option<String>,
remote: Option<usize>,
buffer: Vec<u8>
}
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<usize, Handle>,
listeners: BTreeMap<String, usize>,
next_id: usize
}
impl SchemeBlockMut for ChanScheme {
fn open(&mut self, path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result<Option<usize>> {
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<Option<usize>> {
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<Option<usize>> {
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<Option<usize>> {
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<Option<usize>> {
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<Option<usize>> {
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))
}
}