From eae2252c5f27e6534726b3dbd7ca5a2ebf293c24 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Sat, 2 Jun 2018 11:56:51 +0200 Subject: [PATCH] Announce when ready to dup --- examples/chan.rs | 61 +++++++++++++++++++++++++++++++++++++++--------- src/scheme.rs | 43 ++++++++++++++++++++++------------ 2 files changed, 78 insertions(+), 26 deletions(-) diff --git a/examples/chan.rs b/examples/chan.rs index 0006437fd5..281b99eb65 100644 --- a/examples/chan.rs +++ b/examples/chan.rs @@ -17,6 +17,8 @@ fn main() -> io::Result<()> { let server = File::create("chan:hello_world")?; { let mut client = File::open("chan:hello_world")?; + // First client not accepted yet + assert_eq!(File::open("chan:hello_world").unwrap_err().kind(), io::ErrorKind::ConnectionRefused); let dup = syscall::dup(server.as_raw_fd(), b"listen").map_err(from_syscall_error)?; let mut dup = unsafe { File::from_raw_fd(dup) }; @@ -65,7 +67,21 @@ fn main() -> io::Result<()> { syscall::fcntl(client.as_raw_fd(), syscall::F_SETFL, syscall::O_NONBLOCK) .map_err(from_syscall_error)?; + syscall::fcntl(server.as_raw_fd(), syscall::F_SETFL, syscall::O_NONBLOCK) + .map_err(from_syscall_error)?; assert_eq!(client.read(&mut buf).unwrap_err().kind(), io::ErrorKind::WouldBlock); + println!("-> Read would block"); + match syscall::dup(server.as_raw_fd(), b"listen") { + Ok(dup) => { + unsafe { File::from_raw_fd(dup); } + panic!("this is supposed to fail"); + }, + Err(err) => { + let err = from_syscall_error(err); + assert_eq!(err.kind(), io::ErrorKind::WouldBlock); + } + } + println!("-> Accept would block"); println!("Testing events..."); @@ -73,12 +89,19 @@ fn main() -> io::Result<()> { println!("--> Thread: Sleeping for 1 second..."); thread::sleep(Duration::from_secs(1)); println!("--> Thread: Writing..."); - dup.write(b"hello")?; - dup.flush()?; + client.write(b"hello")?; + client.flush()?; println!("--> Thread: Sleeping for 1 second..."); thread::sleep(Duration::from_secs(1)); println!("--> Thread: Dropping..."); - drop(dup); + drop(client); + println!("--> Thread: Sleeping for 3 seconds..."); + thread::sleep(Duration::from_secs(3)); + println!("--> Thread: Opening new..."); + let mut client = File::open("chan:hello_world")?; + let mut buf = [0; 5]; + assert_eq!(client.read(&mut buf)?, 0); + println!("--> Thread: Closing..."); Ok(()) }); @@ -87,45 +110,61 @@ fn main() -> io::Result<()> { let mut time = syscall::TimeSpec::default(); time_file.read(&mut time)?; - time.tv_sec += 5; + time.tv_sec += 3; time_file.write(&time)?; event_file.write(&syscall::Event { - id: client.as_raw_fd(), + id: dup.as_raw_fd(), flags: syscall::EVENT_READ | syscall::EVENT_WRITE, data: 0 })?; + event_file.write(&syscall::Event { + id: server.as_raw_fd(), + flags: syscall::EVENT_WRITE | syscall::EVENT_READ, + data: 1 + })?; event_file.write(&syscall::Event { id: time_file.as_raw_fd(), flags: syscall::EVENT_READ, - data: 1 + data: 2 })?; let mut event = syscall::Event::default(); event_file.read(&mut event)?; - assert_eq!(event.id, client.as_raw_fd()); + assert_eq!(event.id, dup.as_raw_fd()); assert_eq!(event.flags, syscall::EVENT_WRITE); assert_eq!(event.data, 0); println!("-> Read event"); for _ in 0..2 { event_file.read(&mut event)?; - assert_eq!(event.id, client.as_raw_fd()); + assert_eq!(event.id, dup.as_raw_fd()); assert_eq!(event.flags, syscall::EVENT_READ); assert_eq!(event.data, 0); println!("-> Read event"); - client.read(&mut buf)?; + dup.read(&mut buf)?; } event_file.read(&mut event)?; assert_eq!(event.id, time_file.as_raw_fd()); assert_eq!(event.flags, syscall::EVENT_READ); - assert_eq!(event.data, 1); + assert_eq!(event.data, 2); println!("-> Timed out"); - thread.join().unwrap().unwrap(); + event_file.read(&mut event)?; + assert_eq!(event.id, server.as_raw_fd()); + assert_eq!(event.flags, syscall::EVENT_WRITE); + assert_eq!(event.data, 1); + println!("-> Read accept event"); + + let dup = syscall::dup(server.as_raw_fd(), b"listen").map_err(from_syscall_error)?; + let dup = unsafe { File::from_raw_fd(dup) }; + + drop(dup); + + thread.join().unwrap()?; println!("Everything tested!"); diff --git a/src/scheme.rs b/src/scheme.rs index 4b88fa14c4..04bd345aa5 100644 --- a/src/scheme.rs +++ b/src/scheme.rs @@ -39,17 +39,29 @@ pub struct ChanScheme { impl ChanScheme { pub fn post_fevents(&mut self, file: &mut File) -> io::Result<()> { for (id, handle) in &mut self.handles { - if !handle.notified_write { - handle.notified_write = true; - post_fevent(file, *id, EVENT_WRITE)?; - } - if !handle.buffer.is_empty() || (!handle.is_listener() && handle.remote.is_none()) { - if !handle.notified_read { - handle.notified_read = true; - post_fevent(file, *id, EVENT_READ)?; + if handle.is_listener() { + if handle.remote.is_some() { + // Send writable because that's what smolnetd does for TcpListener + if !handle.notified_write { + handle.notified_write = true; + post_fevent(file, *id, EVENT_WRITE)?; + } + } else { + handle.notified_write = false; } } else { - handle.notified_read = false; + if !handle.notified_write { + handle.notified_write = true; + post_fevent(file, *id, EVENT_WRITE)?; + } + if !handle.buffer.is_empty() || handle.remote.is_none() { + if !handle.notified_read { + handle.notified_read = true; + post_fevent(file, *id, EVENT_READ)?; + } + } else { + handle.notified_read = false; + } } } Ok(()) @@ -61,22 +73,23 @@ impl SchemeBlockMut for ChanScheme { 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::default(); handle.flags = flags; let id = self.next_id; if flags & O_CREAT == O_CREAT { + if self.listeners.contains_key(path) { + return Err(Error::new(EADDRINUSE)); + } self.listeners.insert(String::from(path), id); handle.path = Some(String::from(path)); } else { - let listener = self.listeners[path]; + let listener = self.listeners.get(path).ok_or(Error::new(ENOENT))?; let handle = self.handles.get_mut(&listener).expect("orphan listener left over"); + if handle.remote.is_some() { + return Err(Error::new(ECONNREFUSED)); + } handle.remote = Some(id); } self.handles.insert(id, handle);