From 9526ffa80fb1ffcfd242e09803ee87d31fdc1073 Mon Sep 17 00:00:00 2001 From: Tiago Lam Date: Wed, 5 Feb 2020 23:07:49 +0000 Subject: [PATCH 1/2] chan: Support opening "empty" ChanScheme. Similarly to how the "tcp:" in Redox's netstack supports opening a first empty scheme, only to later on being dup()'ed and set with an appropriate path, this follows the same approach - a map of NullFile structs is kept and initially associated with an id. Next time dup() is called, the true Handle is created, keeping the same definitions of the previously created NullFile. Not that it is important to add support for this in the ipcd to support AF_UNIX sockets, otherwise the socket() created in relibc won't be associated with a address / path. --- src/chan.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/chan.rs b/src/chan.rs index 38df91fca7..97d1f64987 100644 --- a/src/chan.rs +++ b/src/chan.rs @@ -40,6 +40,10 @@ impl Default for Connection { } } +pub struct NullFile { + pub flags: usize, +} + #[derive(Debug, Default)] pub struct Handle { id: usize, @@ -92,6 +96,7 @@ impl Handle { } pub struct ChanScheme { + nulls: HashMap, handles: HashMap, listeners: HashMap, next_id: usize, @@ -100,6 +105,7 @@ pub struct ChanScheme { impl ChanScheme { pub fn new() -> io::Result { Ok(Self { + nulls: HashMap::new(), handles: HashMap::new(), listeners: HashMap::new(), next_id: 0, @@ -124,6 +130,20 @@ impl SchemeBlockMut for ChanScheme { let path = ::std::str::from_utf8(path).or(Err(Error::new(EPERM)))?; let new_id = self.next_id; + + if path.is_empty() { + let null = NullFile { + flags: flags, + }; + + let id = new_id; + + self.nulls.insert(id, null); + self.next_id += 1; + + return Ok(Some(id)); + } + let mut new = Handle::default(); new.flags = flags; @@ -154,6 +174,13 @@ impl SchemeBlockMut for ChanScheme { Ok(Some(new_id)) } fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { + if let Some(flags) = self.nulls + .get(&id) + .map(|null| null.flags) + { + return self.open(buf, flags, 0, 0); + } + match buf { b"listen" => { loop { @@ -268,6 +295,10 @@ impl SchemeBlockMut for ChanScheme { } } fn close(&mut self, id: usize) -> Result> { + if let Some(_null) = self.nulls.remove(&id) { + return Ok(Some(0)); + } + let handle = self.handles.remove(&id).ok_or(Error::new(EBADF))?; match handle.extra { From fad13404d5583b42f7a65c985df5c066c4cfa8da Mon Sep 17 00:00:00 2001 From: Tiago Lam Date: Wed, 5 Feb 2020 23:17:30 +0000 Subject: [PATCH 2/2] chan: Keep path in for new Handle. While supporting AF_UNIX, once an accept() is called in relibc, in turn, a dup() is also called with "listen". While processing this ipcd effectively creates a new handler, losing track of the path of the previous handler. However, it is important to keep this path in the newly created Handler as well, so the socket can be queried later by relibc (when calling fpath()) and fill in appropriately its sockaddr_un struct. --- src/chan.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/chan.rs b/src/chan.rs index 97d1f64987..f9b3f1ccb8 100644 --- a/src/chan.rs +++ b/src/chan.rs @@ -48,7 +48,8 @@ pub struct NullFile { pub struct Handle { id: usize, flags: usize, - extra: Extra + extra: Extra, + path: Option, } impl Handle { /// Duplicate this listener handle into one that is linked to the @@ -186,10 +187,11 @@ impl SchemeBlockMut for ChanScheme { loop { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; let listener = handle.require_listener()?; + let listener_path = listener.path.clone(); break if let Some(remote_id) = listener.awaiting.pop_front() { let new_id = self.next_id; - let new = handle.accept(remote_id); + let mut new = handle.accept(remote_id); // Hook the remote side, assuming it's still // connected, up to this one so the connection is @@ -206,6 +208,8 @@ impl SchemeBlockMut for ChanScheme { } post_fevent(&mut self.socket, remote_id, EVENT_WRITE)?; + new.path = listener_path; + self.handles.insert(new_id, new); self.next_id += 1; Ok(Some(new_id)) @@ -271,6 +275,23 @@ impl SchemeBlockMut for ChanScheme { Ok(None) } } + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + // Write scheme name + const PREFIX: &[u8] = b"chan:"; + let len = cmp::min(PREFIX.len(), buf.len()); + buf[..len].copy_from_slice(&PREFIX[..len]); + if len < PREFIX.len() { + return Ok(Some(len)); + } + + // Write path + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + let path = handle.path.as_ref().ok_or(Error::new(EBADF))?; + let len = cmp::min(path.len(), buf.len() - PREFIX.len()); + buf[PREFIX.len()..][..len].copy_from_slice(&path.as_bytes()[..len]); + + Ok(Some(PREFIX.len() + len)) + } fn fsync(&mut self, id: usize) -> Result> { self.handles.get(&id) .ok_or(Error::new(EBADF))