Initial commit
This commit is contained in:
Generated
+14
@@ -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"
|
||||
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "chand"
|
||||
version = "0.1.0"
|
||||
authors = ["jD91mZM2 <me@krake.one>"]
|
||||
|
||||
[dependencies]
|
||||
redox_syscall = "0.1.40"
|
||||
@@ -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
@@ -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
@@ -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))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user