//! uds scheme for handling Unix Domain Socket stream communication use super::{ get_uid_gid_from_pid, path_buf_to_str, read_msghdr_info, read_num, AncillaryData, Credential, DataPacket, MsgWriter, MIN_RECV_MSG_LEN, }; use libc::{ucred, AF_UNIX}; use rand::prelude::*; use redox_rt::protocol::SocketCall; use redox_scheme::{ scheme::SchemeSync, CallerCtx, OpenResult, RecvFdRequest, Response, SendFdRequest, SignalBehavior, Socket as SchemeSocket, }; use std::{ cell::RefCell, cmp, collections::{HashMap, HashSet, VecDeque}, mem, rc::Rc, slice, }; use syscall::{error::*, flag::*, schemev2::NewFdFlags, Error, Stat}; #[derive(Clone, Copy, Default)] struct MsgFlags(libc::c_int); impl MsgFlags { fn nonblock(&self) -> bool { self.0 & libc::MSG_DONTWAIT == libc::MSG_DONTWAIT } } #[derive(Debug, Default, Clone, PartialEq, Eq)] struct Connection { peer: usize, packets: VecDeque, fds: VecDeque, is_peer_shutdown: bool, } impl Connection { fn new(peer: usize) -> Self { Self { peer, ..Default::default() } } fn drop_fds(&mut self, num_fd: usize) -> Result<()> { for i in 0..num_fd { if self.fds.pop_front().is_none() { eprintln!("Connection::drop_fds: Attempted to drop FD #{} of {}, but fd queue is empty. State inconsistency.", i + 1, num_fd); return Err(Error::new(EPROTO)); } } Ok(()) } fn can_read(&self) -> bool { !self.packets.is_empty() || !self.fds.is_empty() || self.is_peer_shutdown } fn serialize_to_msgstream( &mut self, stream: &mut [u8], name_buf_size: usize, iov_size: usize, options: HashSet, ) -> Result { let mut name: Option = None; let mut payload_buffer: Vec = Vec::with_capacity(iov_size); let mut ancillary_data_buffer: VecDeque = VecDeque::new(); let mut total_copied_len = 0; let mut user_buf_offset = 0; while user_buf_offset < iov_size { let Some(packet) = self.packets.front_mut() else { // No more packets to read break; }; let packet_rem_payload = &packet.payload[packet.read_offset..]; let user_buf_rem_len = iov_size - user_buf_offset; let copied_len = cmp::min(packet_rem_payload.len(), user_buf_rem_len); if copied_len == 0 { // No more data to read from this packet break; } payload_buffer.extend_from_slice(&packet_rem_payload[..copied_len]); if !packet.ancillary_taken { name = name.or_else(|| packet.ancillary_data.name.take()); ancillary_data_buffer.push_back(packet.ancillary_data.clone()); packet.ancillary_taken = true; // Mark ancillary data as taken } packet.read_offset += copied_len; user_buf_offset += copied_len; total_copied_len += copied_len; if packet.read_offset >= packet.payload.len() { // If the packet is fully read, remove it from the queue self.packets.pop_front(); } } let mut msg_writer = MsgWriter::new(stream); msg_writer.write_name(name, name_buf_size, UdsStreamScheme::fpath_inner)?; let full_len = cmp::min(total_copied_len, iov_size); msg_writer.write_payload(&payload_buffer, full_len, iov_size)?; let mut num_fds = 0; for ancillary_data in ancillary_data_buffer.iter() { num_fds += ancillary_data.num_fds; } if !msg_writer.write_rights(num_fds) { eprintln!( "serialize_to_msgstream: Buffer too small for SCM_RIGHTS, dropping {} FDs.", num_fds ); self.drop_fds(num_fds)?; } for option in options { let result = match option { libc::SO_PASSCRED => { let mut success = true; for data in &ancillary_data_buffer { if !msg_writer.write_credentials(&data.cred) { success = false; break; } } success } _ => { eprintln!( "serialize_to_msgstream: Unsupported socket option for serialization: {}", option ); return Err(Error::new(EOPNOTSUPP)); } }; if !result { eprintln!("serialize_to_msgstream: Buffer too small for ancillary data, stopping further serialization."); break; } } Ok(msg_writer.len()) } } #[derive(Debug, Clone, PartialEq, Eq, Copy)] pub enum State { Unbound, Bound, Listening, Connecting, Accepted, Established, Closed, } impl Default for State { fn default() -> Self { Self::Unbound } } #[derive(Debug)] pub struct Socket { primary_id: usize, path: Option, options: HashSet, flags: usize, state: State, awaiting: VecDeque, connection: Option, issued_token: Option, ucred: ucred, } impl Socket { fn new( id: usize, path: Option, state: State, options: HashSet, flags: usize, connection: Option, ctx: &CallerCtx, ) -> Self { Self { primary_id: id, path, state, options, flags, awaiting: VecDeque::new(), connection, issued_token: None, //TODO: when should ucred be updated? man 7 unix for SO_PEERCRED says on connect, listen, or socketpair ucred: ucred { pid: ctx.pid as _, uid: ctx.uid as _, gid: ctx.gid as _, }, } } fn events(&self) -> EventFlags { let mut ready = EventFlags::empty(); if let Some(connection) = &self.connection { if connection.can_read() { ready |= EVENT_READ; } //TODO: block on write buffer ready |= EVENT_WRITE; } match self.state { State::Listening => { if !self.awaiting.is_empty() { ready |= EVENT_READ; } } State::Closed => { ready |= EVENT_READ; } _ => {} } ready } fn accept( &mut self, primary_id: usize, awaiting_client_id: usize, ctx: &CallerCtx, ) -> Result { if !self.is_listening() { eprintln!( "accept(id: {}): Accept called on a non-listening socket.", self.primary_id ); return Err(Error::new(EINVAL)); } Ok(Self::new( primary_id, self.path.clone(), State::Established, self.options.clone(), self.flags, Some(Connection::new(awaiting_client_id)), ctx, )) } fn establish(&mut self, peer: usize) -> Result<()> { if self.state != State::Connecting { eprintln!( "establish(id: {}): Cannot establish connection in state: {:?}", self.primary_id, self.state ); return Err(Error::new(EINVAL)); } self.state = State::Accepted; if let Some(conn) = &self.connection { if conn.peer != peer { // client is expecting other connection return Err(Error::new(EAGAIN)); } } else { // client is dead return Err(Error::new(EAGAIN)); } Ok(()) } fn connect(&mut self, other: usize, flags: usize) -> Result<()> { match self.state { State::Unbound | State::Bound => { // If the socket is unbound or bound, wait for the listener to start listening. if flags & O_NONBLOCK == O_NONBLOCK { self.awaiting.push_back(other); Ok(()) } else { // If the connecting target is not a listening, // the connecting socket will block until the socket // is ready to accept. Err(Error::new(EWOULDBLOCK)) } } State::Listening => { // If the socket is already listening, it can accept connections. self.awaiting.push_back(other); Ok(()) } _ => Err(Error::new(ECONNREFUSED)), } } // For socketpair, add the peer's id to the base socket's awaiting queue. fn connect_socketpair(&mut self, peer: usize) { self.awaiting.push_back(peer); } fn is_listening(&self) -> bool { self.state == State::Listening } fn require_connection(&mut self) -> Result<&mut Connection> { if let Some(connection) = &mut self.connection { Ok(connection) } else { eprintln!( "Socket (id: {}): connection is None in require_connection", self.primary_id ); Err(Error::new(EPROTO)) } } fn require_connected_connection(&mut self, msg_flags: MsgFlags) -> Result<&mut Connection> { match self.state { State::Established | State::Accepted => self.require_connection(), State::Connecting => { if self.flags & O_NONBLOCK == O_NONBLOCK || msg_flags.nonblock() { Err(Error::new(EAGAIN)) } else { Err(Error::new(EWOULDBLOCK)) } } State::Closed => Err(Error::new(EPIPE)), _ => Err(Error::new(ENOTCONN)), } } fn start_listening(&mut self) -> Result<()> { if !matches!(self.state, State::Unbound | State::Bound) { eprintln!( "start_listening(id: {}): Socket cannot listen in state {:?}.", self.primary_id, self.state ); return Err(Error::new(EINVAL)); } self.state = State::Listening; Ok(()) } fn serialize_to_msgstream( &mut self, msg_flags: MsgFlags, stream: &mut [u8], name_buf_size: usize, iov_size: usize, ) -> Result { let options = self.options.clone(); let connection = self.require_connected_connection(msg_flags)?; connection.serialize_to_msgstream(stream, name_buf_size, iov_size, options) } } pub struct UdsStreamScheme<'sock> { sockets: HashMap>>, next_id: usize, socket_paths: HashMap>>, socket_tokens: HashMap>>, socket: &'sock SchemeSocket, proc_creds_capability: usize, rng: SmallRng, } impl<'sock> UdsStreamScheme<'sock> { pub fn new(socket: &'sock SchemeSocket) -> Result { Ok(Self { sockets: HashMap::new(), next_id: 0, socket_paths: HashMap::new(), socket_tokens: HashMap::new(), socket, proc_creds_capability: syscall::open( "/scheme/proc/proc-creds-capability", syscall::O_RDONLY, )?, rng: SmallRng::from_entropy(), }) } fn post_fevent(&self, id: usize, flags: EventFlags) -> Result<()> { /*TODO: filter out unnecessary flags? if let Ok(socket_rc) = self.get_socket(id) { let socket = socket_rc.borrow(); let socket_flags = socket.events(); } */ let fevent_response = Response::post_fevent(id, flags.bits()); match self .socket .write_response(fevent_response, SignalBehavior::Restart) { Ok(true) => Ok(()), // Write response success Ok(false) => Err(Error::new(EAGAIN)), // Write response failed, retry. Err(err) => Err(err), // Error writing response } } fn get_socket(&self, id: usize) -> Result<&Rc>, Error> { self.sockets.get(&id).ok_or(Error::new(EBADF)) } fn get_connected_peer(&self, id: usize) -> Result<(usize, Rc>), Error> { let mut socket = self.get_socket(id)?.borrow_mut(); let remote_id = socket.require_connection()?.peer; let remote_rc = self.get_socket(remote_id).map_err(|e| { eprintln!("get_connected_peer(id: {}): Peer socket (id: {}) has vanished. Original error: {:?}", id, remote_id, e); Error::new(EPIPE) })?; if remote_rc.borrow().state == State::Closed { eprintln!( "get_connected_peer(id: {}): Attempted to interact with a closed peer (id: {}).", id, remote_id ); return Err(Error::new(ECONNREFUSED)); } Ok((remote_id, remote_rc.clone())) } fn handle_unnamed_socket(&mut self, flags: usize, ctx: &CallerCtx) -> usize { let new_id = self.next_id; let new = Socket::new( new_id, None, State::Unbound, HashSet::new(), flags, None, ctx, ); self.sockets.insert(new_id, Rc::new(RefCell::new(new))); self.next_id += 1; new_id } fn call_inner( &mut self, id: usize, payload: &mut [u8], metadata: &[u64], ctx: &CallerCtx, ) -> Result { let Some(verb) = SocketCall::try_from_raw(*metadata.get(0).ok_or(Error::new(EINVAL))? as usize) else { eprintln!("call_inner: Invalid verb in metadata: {:?}", metadata); return Err(Error::new(EINVAL)); }; match verb { SocketCall::Bind => self.handle_bind(id, &payload), SocketCall::Connect => self.handle_connect(id, &payload), SocketCall::SetSockOpt => self.handle_setsockopt( id, *metadata.get(1).ok_or(Error::new(EINVAL))? as i32, &payload, ), SocketCall::GetSockOpt => self.handle_getsockopt( id, *metadata.get(1).ok_or(Error::new(EINVAL))? as i32, payload, ), SocketCall::SendMsg => self.handle_sendmsg( id, metadata .get(1) .map(|x| MsgFlags(*x as _)) .unwrap_or_default(), payload, ctx, ), SocketCall::RecvMsg => self.handle_recvmsg( id, metadata .get(1) .map(|x| MsgFlags(*x as _)) .unwrap_or_default(), payload, ), SocketCall::Unbind => self.handle_unbind(id), SocketCall::GetToken => self.handle_get_token(id, payload), SocketCall::GetPeerName => self.handle_get_peer_name(id, payload), _ => Err(Error::new(EOPNOTSUPP)), } } fn handle_bind(&mut self, id: usize, path_buf: &[u8]) -> Result { let path = path_buf_to_str(path_buf)?; if self.socket_paths.contains_key(path) { eprintln!("handle_bind: Path '{}' is already in use.", path); return Err(Error::new(EADDRINUSE)); } let socket_rc = self.get_socket(id)?.clone(); let path_owned: String; let token: u64; { let mut socket = socket_rc.borrow_mut(); if socket.state != State::Unbound { eprintln!( "handle_bind(id: {}): Socket is already bound or connected (state: {:?})", id, socket.state ); return Err(Error::new(EINVAL)); } path_owned = path.to_string(); socket.path = Some(path_owned.clone()); socket.state = State::Bound; token = self.rng.next_u64(); socket.issued_token = Some(token); //TODO: Hack since relibc does not listen() socket.start_listening()?; } self.socket_paths.insert(path_owned, socket_rc.clone()); self.socket_tokens.insert(token, socket_rc); Ok(0) } // There are three phases of connecting a socket: // // Phase 1: The listener is bound but not yet listening. // The client is trying to connect. // If the listener is not listening, the listener will // refuse to connect until the listener starts listening. // // Phase 2: The listener is now listening. // The client is still trying to connect. // The client pushes its ID to the listener's awaiting queue // and sets its state to `Connecting`. // The client will be blocked from sending/receiving messages, // waiting for the listener to accept it. // // Phase 3: The listener accepts the client, changes its state to `Established`, // and then changes the client's state to `Accepted`. // The client detects that its state has changed to `Accepted` // and changes its own state to `Established`. // // After these three phases, the socket connection is considered established. fn handle_connect(&mut self, id: usize, token_buf: &[u8]) -> Result { let token = read_num::(token_buf)?; let (listener_id, flags) = { let listener_rc = self .socket_tokens .get(&token) .ok_or_else(|| Error::new(ECONNREFUSED))? .clone(); let client_rc = self.get_socket(id)?.clone(); let mut client = client_rc.borrow_mut(); // Phase 1: listener is bound but not yet listening let mut listener = listener_rc.borrow_mut(); let listener_id = listener.primary_id; match client.state { State::Connecting => { if client .connection .as_ref() .is_some_and(|c| c.peer == listener_id) { // No op return Ok(0); } } State::Established => { return Err(Error::new(EISCONN)); } State::Accepted => { // Phase 3: Socket is already connected client.state = State::Established; return Ok(0); } _ => {} } listener.connect(id, client.flags)?; // Phase 2: listener is now listening client.state = State::Connecting; client.connection = Some(Connection::new(listener_id)); (listener_id, client.flags) }; // smoltcp sends writeable whenever a listener gets a // client, we'll do the same too (but also readable, why // not) self.post_fevent(listener_id, EVENT_READ | EVENT_WRITE)?; Ok(0) } fn handle_setsockopt(&mut self, id: usize, option: i32, value_slice: &[u8]) -> Result { let socket_rc = self.get_socket(id)?; let mut socket = socket_rc.borrow_mut(); match option { libc::SO_PASSCRED => { let value = read_num::(value_slice)?; if value != 0 { socket.options.insert(libc::SO_PASSCRED); } else { socket.options.remove(&libc::SO_PASSCRED); } Ok(value_slice.len()) } libc::SO_SNDBUF => { // FIXME: implement Ok(0) } _ => { eprintln!( "socket_setsockopt(id: {}): Unsupported option: {}", id, option ); Err(Error::new(ENOPROTOOPT)) } } } fn handle_getsockopt(&mut self, id: usize, option: i32, payload: &mut [u8]) -> Result { let mut write_value = |value: &[u8]| -> Result { if payload.len() < value.len() { eprintln!( "socket_getsockopt(id: {}, option: {}): payload buffer is too small. len: {} < {}", id, option, payload.len(), value.len() ); return Err(Error::new(ENOBUFS)); } payload.fill(0); payload[..value.len()].copy_from_slice(&value); Ok(value.len()) }; match option { libc::SO_DOMAIN => write_value(&AF_UNIX.to_le_bytes()), libc::SO_PEERCRED => { let (_, remote_rc) = self.get_connected_peer(id)?; let remote = remote_rc.borrow(); write_value(unsafe { slice::from_raw_parts( &remote.ucred as *const ucred as *const u8, mem::size_of::(), ) }) } libc::SO_SNDBUF => { //TODO: default value on Linux, should we use something else? let value: libc::c_int = 212992; write_value(&value.to_le_bytes()) } _ => { eprintln!( "socket_getsockopt(id: {}): Unsupported option: {}", id, option ); Err(Error::new(ENOPROTOOPT)) } } } fn handle_sendmsg( &mut self, id: usize, msg_flags: MsgFlags, msg_stream: &[u8], ctx: &CallerCtx, ) -> Result { if msg_stream.is_empty() { eprintln!("msg_stream is empty, returning EINVAL."); return Err(Error::new(EINVAL)); } let (bytes_written, remote_id) = { let name = self.get_socket(id)?.borrow().path.clone(); let (remote_id, remote_rc) = self.get_connected_peer(id)?; let mut socket = remote_rc.borrow_mut(); let connection = socket.require_connected_connection(msg_flags)?; let (pid, uid, gid) = get_uid_gid_from_pid(self.proc_creds_capability, ctx.pid)?; let packet = DataPacket::from_stream( msg_stream, name, Credential::new(pid as i32, uid as i32, gid as i32), )?; let payload_len = packet.len(); // sendmsg(2) on `SOCK_STREAM` with zero-byte payload is a no-op // even if ancillary data is present. Note that this does not apply // to `SOCK_DGRAM`. if payload_len == 0 { return Ok(0); } connection.packets.push_back(packet); (payload_len, remote_id) }; self.post_fevent(remote_id, EVENT_READ)?; Ok(bytes_written) } fn handle_recvmsg( &mut self, id: usize, msg_flags: MsgFlags, msg_stream: &mut [u8], ) -> Result { let socket_rc = self.get_socket(id)?; let mut socket = socket_rc.borrow_mut(); let flags = socket.flags; let connection = match &mut socket.state { State::Established | State::Accepted => socket.require_connection()?, State::Closed => { // Remote dropped, send EOF return Self::write_eof(msg_stream); } State::Listening => { eprintln!("socket_recvmsg: Called on a listening socket, returning EOPNOTSUPP."); return Err(Error::new(EOPNOTSUPP)); } _ => return Err(Error::new(ENOTCONN)), }; if connection.packets.is_empty() { return if connection.is_peer_shutdown { // EOF, no data to read return Self::write_eof(msg_stream); } else if (flags as usize) & O_NONBLOCK == O_NONBLOCK || msg_flags.nonblock() { Err(Error::new(EAGAIN)) } else { Err(Error::new(EWOULDBLOCK)) }; } Self::recvmsg_inner(&mut socket, msg_flags, msg_stream) } fn write_eof(buffer: &mut [u8]) -> Result { // Write EOF to the buffer let target = buffer.get_mut(..MIN_RECV_MSG_LEN).ok_or_else(|| { eprintln!("write_eof: Buffer is too small to write EOF, returning EINVAL."); Error::new(EINVAL) })?; target.fill(0); // Fill the buffer with zeros to indicate EOF Ok(MIN_RECV_MSG_LEN) } fn recvmsg_inner( socket: &mut Socket, msg_flags: MsgFlags, msg_stream: &mut [u8], ) -> Result { let (prepared_name_len, prepared_whole_iov_size, _) = read_msghdr_info(msg_stream)?; let written_len = socket.serialize_to_msgstream( msg_flags, msg_stream, prepared_name_len, prepared_whole_iov_size, )?; Ok(written_len) } fn handle_unbind(&mut self, id: usize) -> Result { let path_opt = { let socket_rc = self.get_socket(id)?; let mut socket = socket_rc.borrow_mut(); if socket.state != State::Bound { return Err(Error::new(EINVAL)); } socket.state = State::Unbound; socket.path.take() }; if let Some(path) = path_opt { self.socket_paths.remove(&path); } Ok(0) } fn handle_get_token(&self, id: usize, payload: &mut [u8]) -> Result { let socket_rc = self.get_socket(id)?; let Some(token) = socket_rc.borrow().issued_token else { return Err(Error::new(EINVAL)); }; let token_bytes = token.to_le_bytes(); let token_bytes_len = token_bytes.len(); if payload.len() < token_bytes_len { eprintln!( "handle_get_token(id: {}): Payload buffer is too small for token.", id ); return Err(Error::new(ENOBUFS)); } payload[..token_bytes_len].copy_from_slice(&token_bytes); return Ok(token_bytes_len); } fn handle_get_peer_name(&self, id: usize, payload: &mut [u8]) -> Result { let (_, socket_rc) = self.get_connected_peer(id)?; let socket_borrow = socket_rc.borrow(); match socket_borrow.path.as_ref() { Some(path_string) => Self::fpath_inner(path_string, payload), None => { let empty_path = "".to_string(); Self::fpath_inner(&empty_path, payload) } } } fn accept_connection( &mut self, listener_socket: &mut Socket, client_id: usize, ctx: &CallerCtx, ) -> Result> { let (new_id, new) = { let Ok(client_rc) = self.get_socket(client_id) else { return Ok(None); // Client socket has been closed, nothing to accept }; let new_id = self.next_id; let new = listener_socket.accept(new_id, client_id, ctx)?; let mut client_socket = client_rc.borrow_mut(); client_socket.establish(new_id)?; (new_id, new) }; self.next_id += 1; self.sockets.insert(new_id, Rc::new(RefCell::new(new))); self.post_fevent(client_id, EVENT_READ | EVENT_WRITE)?; Ok(Some(OpenResult::ThisScheme { number: new_id, flags: NewFdFlags::empty(), })) } fn handle_accept( &mut self, id: usize, socket: &mut Socket, ctx: &CallerCtx, ) -> Result> { let flags = socket.flags; if !socket.is_listening() { eprintln!( "socket_accept: Socket state is not Listening for id: {}", id ); return Err(Error::new(EINVAL)); } loop { // Try to accept a waiting connection let Some(client_id) = socket.awaiting.pop_front() else { if flags & O_NONBLOCK == O_NONBLOCK { return Err(Error::new(EAGAIN)); } else { return Ok(Some(OpenResult::WouldBlock)); } }; return match self.accept_connection(socket, client_id, ctx) { Ok(conn) => Ok(conn), Err(Error { errno: EAGAIN }) => continue, Err(e) => Err(e), }; } } // Transition a Bound or Unbound socket to the Listening state. fn handle_start_listening(&mut self, socket_rc: &Rc>) -> Result<()> { let path = { let mut socket = socket_rc.borrow_mut(); socket.start_listening()?; socket.path.clone() }; if let Some(path) = path { if let Some(existing_socket_rc) = self.socket_paths.get(&path) { if !Rc::ptr_eq(socket_rc, existing_socket_rc) { eprintln!("handle_start_listening: Path '{}' is already in use.", path); return Err(Error::new(EADDRINUSE)); } } self.socket_paths.insert(path, socket_rc.clone()); } Ok(()) } // Handle a `dup` call for `b"listen"`. // If the socket is not yet listening, it transitions it to the Listening state. // If it is already listening, it tries to accept a pending connection. fn handle_listen(&mut self, id: usize, ctx: &CallerCtx) -> Result { loop { let socket_rc = self.get_socket(id)?.clone(); let is_listening = socket_rc.borrow().is_listening(); if is_listening { let mut socket = socket_rc.borrow_mut(); match self.handle_accept(id, &mut socket, ctx)? { Some(result) => return Ok(result), None => continue, } } else { self.handle_start_listening(&socket_rc)?; continue; } } } fn handle_connect_socketpair(&mut self, id: usize, ctx: &CallerCtx) -> Result { let new_id = self.next_id; let flags = self.get_socket(id)?.borrow().flags; let new = Socket::new( new_id, None, State::Connecting, HashSet::new(), flags, None, ctx, ); { let socket_rc = self.get_socket(id)?; let mut socket = socket_rc.borrow_mut(); if socket.state == State::Closed { eprintln!( "socket_connect_socketpair: Base socket {} is already closed.", id ); return Err(Error::new(EPIPE)); } socket.connect_socketpair(new_id); } // smoltcp sends writeable whenever a listener gets a // client, we'll do the same too (but also readable, // why not) self.post_fevent(id, EVENT_READ | EVENT_WRITE)?; self.sockets.insert(new_id, Rc::new(RefCell::new(new))); self.next_id += 1; Ok(OpenResult::ThisScheme { number: new_id, flags: NewFdFlags::empty(), }) } fn handle_recvfd(&mut self, id: usize) -> Result { let socket_rc = self.get_socket(id)?; let mut socket = socket_rc.borrow_mut(); match socket.state { State::Established | State::Accepted => { let connection = socket.require_connected_connection(MsgFlags::default())?; let fd = connection.fds.pop_front().ok_or(Error::new(EWOULDBLOCK))?; Ok(OpenResult::OtherScheme { fd }) } State::Closed => Err(Error::new(EPIPE)), State::Listening => Err(Error::new(EOPNOTSUPP)), _ => Err(Error::new(ENOTCONN)), } } fn write_inner(&mut self, receiver_id: usize, buf: &[u8], ctx: &CallerCtx) -> Result { { let receiver_rc = self.get_socket(receiver_id)?; let mut receiver = receiver_rc.borrow_mut(); let name = receiver.path.clone(); let connection = receiver.require_connected_connection(MsgFlags::default())?; if !buf.is_empty() { // Send readable only if it wasn't readable before let ancillary_data = AncillaryData::new( Credential::new(ctx.pid as i32, ctx.uid as i32, ctx.gid as i32), name, ); let packet = DataPacket::new(buf.to_vec(), ancillary_data); connection.packets.push_back(packet); } } self.post_fevent(receiver_id, EVENT_READ)?; Ok(buf.len()) } fn sendfd_inner( &mut self, receiver_id: usize, sendfd_request: &SendFdRequest, ) -> Result { 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::UPPER_TBL, &mut new_fds) { eprintln!("sendfd_inner: obtain_fd failed with error: {:?}", e); return Err(e); } { let receiver_rc = self.get_socket(receiver_id)?; let mut receiver = receiver_rc.borrow_mut(); let connection = receiver.require_connected_connection(MsgFlags::default())?; for new_fd in &new_fds { connection.fds.push_back(*new_fd); } } self.post_fevent(receiver_id, EVENT_READ)?; 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(MsgFlags::default())?; 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 { Err(Error::new(EAGAIN)) } else { Ok(OpenResult::WouldBlock) }; } 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 { let mut total_copied_len = 0; let mut user_buf_offset = 0; while user_buf_offset < buf.len() { let Some(packet) = connection.packets.front_mut() else { // No more packets to read break; }; let packet_rem_payload = &packet.payload[packet.read_offset..]; let user_buf_rem_len = buf.len() - user_buf_offset; let copied_len = cmp::min(packet_rem_payload.len(), user_buf_rem_len); if copied_len == 0 { // No more data to read from this packet break; } buf[user_buf_offset..user_buf_offset + copied_len] .copy_from_slice(&packet_rem_payload[..copied_len]); if packet.read_offset == 0 { packet.ancillary_taken = true; // Mark ancillary data as taken } packet.read_offset += copied_len; user_buf_offset += copied_len; total_copied_len += copied_len; if packet.read_offset >= packet.payload.len() { // If the packet is fully read, remove it from the queue connection.packets.pop_front(); } } if total_copied_len > 0 { Ok(total_copied_len) } else if connection.is_peer_shutdown { Ok(0) // EOF, no data to read } else if (flags as usize) & O_NONBLOCK == O_NONBLOCK { Err(Error::new(EAGAIN)) } else { Err(Error::new(EWOULDBLOCK)) } } fn handle_listening_closure(&mut self, socket_rc: Rc>) { let socket = socket_rc.borrow(); if let Some(path) = &socket.path { self.socket_paths.remove(path); } if let Some(token) = &socket.issued_token { self.socket_tokens.remove(&token); } // Notify all waiting clients about listener closure for client_id in &socket.awaiting { if let Ok(client_rc) = self.get_socket(*client_id) { { let mut client = client_rc.borrow_mut(); client.state = State::Closed; } let _ = self.post_fevent(*client_id, EVENT_READ); } } } fn handle_other_closure(&mut self, socket_rc: Rc>) { // If this is the last reference to the socket, it's safe to remove the socket path. let mut socket = socket_rc.borrow_mut(); if matches!(socket.state, State::Established | State::Accepted) { let Ok(connection) = socket.require_connection() else { return; }; let Ok(remote_rc) = self.get_socket(connection.peer) else { return; }; let remote_id = { let mut remote = remote_rc.borrow_mut(); let Ok(connection) = remote.require_connection() else { return; }; connection.is_peer_shutdown = true; remote.primary_id }; let _ = self.post_fevent(remote_id, EVENT_READ); } if let Some(path) = socket.path.take() { // If this is the last reference to the socket, remove the path from the registry self.socket_paths.remove(&path); } if let Some(token) = socket.issued_token { self.socket_tokens.remove(&token); } socket.state = State::Closed; } fn fpath_inner(path: &String, buf: &mut [u8]) -> Result { // Write scheme name const PREFIX: &[u8] = b"/scheme/uds_stream/"; let len = cmp::min(PREFIX.len(), buf.len()); buf[..len].copy_from_slice(&PREFIX[..len]); if len < PREFIX.len() { return Ok(len); } // Write path let len = cmp::min(path.len(), buf.len() - PREFIX.len()); buf[PREFIX.len()..][..len].copy_from_slice(&path.as_bytes()[..len]); Ok(PREFIX.len() + len) } } impl<'sock> SchemeSync for UdsStreamScheme<'sock> { fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result { let new_id = if path.is_empty() { self.handle_unnamed_socket(flags, ctx) } else { eprintln!( "open(path: '{}'): Attempting to open a named socket, which is not supported.", path ); return Err(Error::new(EINVAL)); }; Ok(OpenResult::ThisScheme { number: new_id, flags: NewFdFlags::empty(), }) } fn call( &mut self, id: usize, payload: &mut [u8], metadata: &[u64], ctx: &CallerCtx, ) -> Result { self.call_inner(id, payload, metadata, ctx) } fn dup(&mut self, id: usize, buf: &[u8], ctx: &CallerCtx) -> Result { match buf { b"listen" => self.handle_listen(id, ctx), b"connect" => self.handle_connect_socketpair(id, ctx), b"recvfd" => self.handle_recvfd(id), _ => Err(Error::new(EINVAL)), } } fn write( &mut self, id: usize, buf: &[u8], _offset: u64, _flags: u32, ctx: &CallerCtx, ) -> Result { let (receiver_id, _) = self.get_connected_peer(id)?; self.write_inner(receiver_id, buf, ctx) } fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { let socket_rc = self.get_socket(id)?; let socket = socket_rc.borrow(); let empty = String::new(); let path = socket.path.as_ref().unwrap_or(&empty); Ok(Self::fpath_inner(path, buf)?) } fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> { self.get_socket(id).and(Ok(())) } fn read( &mut self, id: usize, buf: &mut [u8], _offset: u64, flags: u32, _ctx: &CallerCtx, ) -> Result { let socket_rc = self.get_socket(id)?; let mut socket = socket_rc.borrow_mut(); match socket.state { State::Established | State::Accepted => { let connection = socket.require_connected_connection(MsgFlags::default())?; Self::read_inner(connection, buf, flags) } State::Closed => Ok(0), State::Listening => Err(Error::new(EOPNOTSUPP)), _ => Err(Error::new(ENOTCONN)), } } fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result { let id = sendfd_request.id(); let (receiver_id, _) = self.get_connected_peer(id)?; 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; }; let state = socket_rc.borrow().state; match state { State::Listening => { self.handle_listening_closure(socket_rc); } _ => { self.handle_other_closure(socket_rc); } } } fn fcntl(&mut self, id: usize, cmd: usize, arg: usize, _ctx: &CallerCtx) -> Result { let socket_rc = self.get_socket(id)?; let mut socket = socket_rc.borrow_mut(); match cmd { F_GETFL => Ok(socket.flags), F_SETFL => { socket.flags = arg; Ok(0) } _ => Err(Error::new(EINVAL)), } } fn fevent(&mut self, id: usize, flags: EventFlags, _ctx: &CallerCtx) -> Result { let socket_rc = self.get_socket(id)?; let socket = socket_rc.borrow(); Ok(socket.events() & flags) } fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> { self.get_socket(id)?; *stat = Stat { st_mode: MODE_SOCK, ..Default::default() }; Ok(()) } }