From 3cad0e8a330d64b20b026966d1923d8f715274e0 Mon Sep 17 00:00:00 2001 From: Ibuki Omatsu Date: Thu, 31 Jul 2025 00:49:37 +0000 Subject: [PATCH] feat: Implement bulk fd passing --- Cargo.lock | 14 +++++----- ipcd/Cargo.toml | 6 ++--- ipcd/src/uds/dgram.rs | 53 ++++++++++++++++++++++++++++++++----- ipcd/src/uds/stream.rs | 60 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 110 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1906e5fca5..5bfc9a6977 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -454,7 +454,7 @@ dependencies = [ "rand", "redox-daemon", "redox-rt", - "redox-scheme 0.7.0", + "redox-scheme 0.8.0", "redox_event", "redox_syscall", ] @@ -483,9 +483,9 @@ checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libredox" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4488594b9328dee448adb906d8b126d9b7deb7cf5c22161ee591610bb1be83c0" +checksum = "360e552c93fa0e8152ab463bc4c4837fce76a225df11dfaeea66c313de5e61f7" dependencies = [ "bitflags 2.9.0", "ioslice", @@ -802,9 +802,9 @@ dependencies = [ [[package]] name = "redox-scheme" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4da6a0251965958189cdfd5ebb66f99754db4aa165394300aa2b958525d94b64" +checksum = "2ad682dfdadbfcf79ee861ba3cebcb78f4615276c1a3434fb510403916cbaba4" dependencies = [ "libredox", "redox_syscall", @@ -837,9 +837,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.14" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3a5d9f0aba1dbcec1cc47f0ff94a4b778fe55bca98a6dfa92e4e094e57b1c4" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ "bitflags 2.9.0", ] diff --git a/ipcd/Cargo.toml b/ipcd/Cargo.toml index 02116159c1..02781424b4 100644 --- a/ipcd/Cargo.toml +++ b/ipcd/Cargo.toml @@ -4,10 +4,10 @@ name = "ipcd" version = "0.1.0" [dependencies] -libredox = { version = "0.1.6", features = ["call"]} +libredox = { version = "0.1.8", features = ["call"]} redox-daemon = "0.1.2" -redox_syscall = "0.5" -redox-scheme = "0.7.0" +redox_syscall = "0.5.17" +redox-scheme = "0.8.0" redox-rt = { git = "https://gitlab.redox-os.org/redox-os/relibc.git", default-features = false } redox_event = "0.4.0" anyhow = "1.0.97" diff --git a/ipcd/src/uds/dgram.rs b/ipcd/src/uds/dgram.rs index e314e932c3..98bff30e82 100644 --- a/ipcd/src/uds/dgram.rs +++ b/ipcd/src/uds/dgram.rs @@ -10,8 +10,8 @@ use rand::rngs::SmallRng; use rand::{RngCore, SeedableRng}; use redox_rt::protocol::SocketCall; use redox_scheme::{ - scheme::SchemeSync, CallerCtx, OpenResult, Response, SendFdRequest, SignalBehavior, - Socket as SchemeSocket, + scheme::SchemeSync, CallerCtx, OpenResult, RecvFdRequest, Response, SendFdRequest, + SignalBehavior, Socket as SchemeSocket, }; use std::{ cell::RefCell, @@ -558,19 +558,56 @@ impl<'sock> UdsDgramScheme<'sock> { } fn sendfd_inner(&mut self, sendfd_request: &SendFdRequest) -> Result { - let mut new_fd = usize::MAX; + if sendfd_request.num_fds() == 0 { + return Ok(0); + } + let mut new_fds = Vec::new(); + new_fds.resize(sendfd_request.num_fds(), usize::MAX); if let Err(e) = - sendfd_request.obtain_fd(&self.socket, FobtainFdFlags::empty(), Err(&mut new_fd)) + sendfd_request.obtain_fd(&self.socket, FobtainFdFlags::UPPER_TBL, &mut new_fds) { eprintln!("sendfd_inner: obtain_fd failed with error: {:?}", e); return Err(e); } let socket_id = sendfd_request.id(); let (remote_id, remote_rc) = self.get_connected_peer(socket_id)?; - remote_rc.borrow_mut().fds.push_back(new_fd); + { + let mut remote = remote_rc.borrow_mut(); + for new_fd in &new_fds { + remote.fds.push_back(*new_fd); + } + } self.post_fevent(remote_id, EVENT_READ.bits())?; - Ok(new_fd) + Ok(new_fds.len()) + } + + fn recvfd_inner(&mut self, recvfd_request: &RecvFdRequest) -> Result { + if recvfd_request.num_fds() == 0 { + return Ok(OpenResult::OtherSchemeMultiple { num_fds: 0 }); + } + + let socket_id = recvfd_request.id(); + let socket_rc = self.get_socket(socket_id)?; + let mut socket = socket_rc.borrow_mut(); + + if socket.fds.len() < recvfd_request.num_fds() { + return if (socket.flags as usize) & O_NONBLOCK == O_NONBLOCK { + Ok(OpenResult::WouldBlock) + } else { + Err(Error::new(EWOULDBLOCK)) + }; + } + + let fds: Vec = socket.fds.drain(..recvfd_request.num_fds()).collect(); + if let Err(e) = recvfd_request.move_fd(&self.socket, FmoveFdFlags::empty(), &fds) { + eprintln!("recvfd_inner: move_fd failed with error: {:?}", e); + return Err(Error::new(EPROTO)); + } + + Ok(OpenResult::OtherSchemeMultiple { + num_fds: recvfd_request.num_fds(), + }) } } @@ -673,6 +710,10 @@ impl<'sock> SchemeSync for UdsDgramScheme<'sock> { self.sendfd_inner(sendfd_request) } + fn on_recvfd(&mut self, recvfd_request: &RecvFdRequest) -> Result { + self.recvfd_inner(recvfd_request) + } + fn fcntl(&mut self, id: usize, cmd: usize, arg: usize, _ctx: &CallerCtx) -> Result { let socket = self.get_socket(id)?; match cmd { diff --git a/ipcd/src/uds/stream.rs b/ipcd/src/uds/stream.rs index c071b3df5f..c285936ab9 100644 --- a/ipcd/src/uds/stream.rs +++ b/ipcd/src/uds/stream.rs @@ -9,8 +9,8 @@ use libc::{AF_UNIX, SO_DOMAIN, SO_PASSCRED}; use rand::prelude::*; use redox_rt::protocol::SocketCall; use redox_scheme::{ - scheme::SchemeSync, CallerCtx, OpenResult, Response, SendFdRequest, SignalBehavior, - Socket as SchemeSocket, + scheme::SchemeSync, CallerCtx, OpenResult, RecvFdRequest, Response, SendFdRequest, + SignalBehavior, Socket as SchemeSocket, }; use std::{ cell::RefCell, @@ -417,7 +417,7 @@ impl<'sock> UdsStreamScheme<'sock> { socket.path = Some(path_owned.clone()); socket.state = State::Bound; token = self.rng.next_u64(); - socket.issued_token.insert(token); + socket.issued_token = Some(token); } self.socket_paths.insert(path_owned, socket_rc.clone()); @@ -852,9 +852,10 @@ impl<'sock> UdsStreamScheme<'sock> { receiver_id: usize, sendfd_request: &SendFdRequest, ) -> Result { - let mut new_fd = usize::MAX; + let mut new_fds = Vec::new(); + new_fds.resize(sendfd_request.num_fds(), usize::MAX); if let Err(e) = - sendfd_request.obtain_fd(&self.socket, FobtainFdFlags::empty(), Err(&mut new_fd)) + sendfd_request.obtain_fd(&self.socket, FobtainFdFlags::UPPER_TBL, &mut new_fds) { eprintln!("sendfd_inner: obtain_fd failed with error: {:?}", e); return Err(e); @@ -863,11 +864,52 @@ impl<'sock> UdsStreamScheme<'sock> { let mut receiver = receiver_rc.borrow_mut(); let connection = receiver.require_connected_connection()?; - connection.fds.push_back(new_fd); + for new_fd in &new_fds { + connection.fds.push_back(*new_fd); + } self.post_fevent(receiver_id, EVENT_READ.bits())?; - Ok(new_fd) + Ok(new_fds.len()) + } + + fn recvfd_inner(&mut self, recvfd_request: &RecvFdRequest) -> Result { + let socket_id = recvfd_request.id(); + let socket_rc = self.get_socket(socket_id)?; + let mut socket = socket_rc.borrow_mut(); + + if recvfd_request.num_fds() == 0 { + return Ok(OpenResult::OtherSchemeMultiple { num_fds: 0 }); + } + + match socket.state { + State::Established | State::Accepted => { + let connection = socket.require_connected_connection()?; + + if connection.fds.len() < recvfd_request.num_fds() { + return if connection.is_peer_shutdown { + Ok(OpenResult::OtherSchemeMultiple { num_fds: 0 }) // EOF, no data to read + } else if (socket.flags as usize) & O_NONBLOCK == O_NONBLOCK { + Ok(OpenResult::WouldBlock) + } else { + Err(Error::new(EWOULDBLOCK)) + }; + } + + let fds: Vec = connection.fds.drain(..recvfd_request.num_fds()).collect(); + if let Err(e) = recvfd_request.move_fd(&self.socket, FmoveFdFlags::empty(), &fds) { + eprintln!("recvfd_inner: move_fd failed with error: {:?}", e); + return Err(Error::new(EPROTO)); + } + + Ok(OpenResult::OtherSchemeMultiple { + num_fds: recvfd_request.num_fds(), + }) + } + State::Closed => Err(Error::new(EPIPE)), + State::Listening => Err(Error::new(EOPNOTSUPP)), + _ => Err(Error::new(ENOTCONN)), + } } fn read_inner(connection: &mut Connection, buf: &mut [u8], flags: u32) -> Result { @@ -1072,6 +1114,10 @@ impl<'sock> SchemeSync for UdsStreamScheme<'sock> { self.sendfd_inner(receiver_id, sendfd_request) } + fn on_recvfd(&mut self, recvfd_request: &RecvFdRequest) -> Result { + self.recvfd_inner(recvfd_request) + } + fn on_close(&mut self, id: usize) { let Some(socket_rc) = self.sockets.remove(&id) else { return;