Merge branch 'impl_recvmsg_handler' into 'main'

Impl recvmsg handler

See merge request redox-os/base!202
This commit is contained in:
Jeremy Soller
2026-03-25 07:02:28 -06:00
7 changed files with 135 additions and 8 deletions
Generated
+2 -2
View File
@@ -1186,9 +1186,9 @@ checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
[[package]]
name = "libredox"
version = "0.1.14"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a"
checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08"
dependencies = [
"bitflags 2.11.0",
"ioslice",
+1 -1
View File
@@ -82,7 +82,7 @@ edid = "0.3.0" #TODO: edid is abandoned, fork it and maintain?
fdt = "0.1.5"
libc = "0.2.181"
log = "0.4"
libredox = "0.1.14"
libredox = "0.1.15"
orbclient = "0.3.51"
parking_lot = "0.12"
pico-args = "0.5"
+6 -2
View File
@@ -252,7 +252,7 @@ impl<'a> SchemeSocket for IcmpSocket<'a> {
if let SchemeFile::Socket(ref socket_file) = *file {
match socket_file.data.socket_type {
IcmpSocketType::Echo => {
let path = format!("icmp:echo/{}", socket_file.data.ip);
let path = format!("/scheme/icmp/echo/{}", socket_file.data.ip);
let path = path.as_bytes();
let mut i = 0;
@@ -264,7 +264,7 @@ impl<'a> SchemeSocket for IcmpSocket<'a> {
Ok(i)
}
IcmpSocketType::Udp => {
let path = format!("icmp:udp/{}", socket_file.data.ip);
let path = format!("/scheme/icmp/udp/{}", socket_file.data.ip);
let path = path.as_bytes();
let mut i = 0;
@@ -281,6 +281,10 @@ impl<'a> SchemeSocket for IcmpSocket<'a> {
}
}
fn handle_recvmsg(&mut self, file: &mut SchemeFile<Self>, how:&mut [u8], flags:usize) -> SyscallResult<usize> {
return Err(SyscallError::new(syscall::EOPNOTSUPP));
}
fn handle_get_peer_name(
&self,
file: &SchemeFile<Self>,
+5 -1
View File
@@ -137,7 +137,7 @@ impl<'a> SchemeSocket for RawSocket<'a> {
}
fn fpath(&self, _file: &SchemeFile<Self>, buf: &mut [u8]) -> SyscallResult<usize> {
let path = format!("ip:{}", self.ip_protocol());
let path = format!("/scheme/ip/{}", self.ip_protocol());
let path = path.as_bytes();
let mut i = 0;
@@ -149,6 +149,10 @@ impl<'a> SchemeSocket for RawSocket<'a> {
Ok(i)
}
fn handle_recvmsg(&mut self, file: &mut SchemeFile<Self>, how:&mut [u8], flags:usize) -> SyscallResult<usize> {
return Err(SyscallError::new(syscall::EOPNOTSUPP));
}
fn handle_get_peer_name(
&self,
file: &SchemeFile<Self>,
+23 -1
View File
@@ -243,6 +243,13 @@ where
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize>;
fn handle_recvmsg(
&mut self,
file: &mut SchemeFile<Self>,
payload: &mut [u8],
flags: usize,
) -> SyscallResult<usize>;
fn get_sock_opt(
&self,
file: &SchemeFile<Self>,
@@ -496,7 +503,6 @@ where
}
}
// SocketCall::SendMsg => self.handle_sendmsg(id, payload, ctx),
// SocketCall::RecvMsg => self.handle_recvmsg(id, payload),
// SocketCall::Unbind => self.handle_unbind(id),
// SocketCall::GetToken => self.handle_get_token(id, payload),
SocketCall::GetPeerName => {
@@ -514,6 +520,22 @@ where
SocketT::handle_get_peer_name(socket, file, payload)
}
SocketCall::RecvMsg => {
let flags = metadata[1] as usize;
let handle = self.handles.get_mut(&fd).ok_or_else(||SyscallError::new(syscall::EBADF))?;
match *handle {
Handle::File(ref mut file) => {
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get_mut::<SocketT>(file.socket_handle());
SocketT::handle_recvmsg(socket, file, payload, flags)
}
Handle::Null(_) => Err(SyscallError::new(syscall::EINVAL)),
Handle::SchemeRoot => Err(SyscallError::new(syscall::EBADF)),
}
}
SocketCall::Shutdown => {
let how = metadata[1] as usize;
+44
View File
@@ -9,6 +9,7 @@ use syscall::{Error as SyscallError, Result as SyscallResult};
use super::socket::{Context, DupResult, SchemeFile, SchemeSocket, SocketFile};
use super::{parse_endpoint, SchemeWrapper, SocketSet};
use crate::port_set::PortSet;
use libredox::flag;
const SO_SNDBUF: usize = 7;
const SO_RCVBUF: usize = 8;
@@ -308,6 +309,49 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
Ok(i)
}
fn handle_recvmsg(&mut self, file: &mut SchemeFile<Self>, how:&mut [u8], flags:usize) -> SyscallResult<usize> {
let socket_file = match file {
SchemeFile::Socket(ref mut sock_f) => sock_f,
_ => return Err(SyscallError::new(syscall::EBADF))
};
if !socket_file.read_enabled {
Ok(0)
} else if self.can_recv(&socket_file.data) {
let usize_length = core::mem::size_of::<usize>();
let prepared_name_len = usize::from_le_bytes(
how[0..usize_length].try_into().map_err(|_| SyscallError::new(syscall::EINVAL))?,
);
let prepared_whole_iov_size = usize::from_le_bytes(
how[usize_length..2 * usize_length].try_into().map_err(|_| SyscallError::new(syscall::EINVAL))?,
);
let prepared_msg_controllen = usize::from_le_bytes(
how[2 * usize_length..3 * usize_length].try_into().map_err(|_| SyscallError::new(syscall::EINVAL))?,
);
if prepared_name_len + prepared_msg_controllen + prepared_whole_iov_size > how.len() {//expected returned buffer size is larger than provided -> return invalid
return Err(SyscallError::new(syscall::EINVAL));
}
let mut address = match self.remote_endpoint() {
Some(endpoint) => format!("/scheme/tcp/{}:{}", endpoint.addr, endpoint.port),
None => String::from("/scheme/tcp/0.0.0.0:0"),
};
how[..usize_length].copy_from_slice(&address.len().to_le_bytes());
how[usize_length..address.len() + usize_length].copy_from_slice(&address.as_bytes());
let payload_length = self.recv_slice(&mut how[address.len() + 2 * usize_length..address.len() + 2 * usize_length + prepared_whole_iov_size]).unwrap();
println!("\n\n{}\n", payload_length);
how[address.len() + usize_length..address.len() + 2 * usize_length].copy_from_slice(&payload_length.to_le_bytes());
//TODO should return the length of payload but relibc uses trim on the buffer incorrectly
Ok(how.len())
} else if socket_file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK || flags & flag::MSG_DONTWAIT as usize != 0 {
Err(SyscallError::new(syscall::EAGAIN))
} else {
Err(SyscallError::new(syscall::EWOULDBLOCK)) // internally scheduled to re-read
}
}
fn handle_get_peer_name(
&self,
file: &SchemeFile<Self>,
+54 -1
View File
@@ -12,6 +12,7 @@ use super::{parse_endpoint, SchemeWrapper, Smolnetd, SocketSet};
use crate::port_set::PortSet;
use crate::router::Router;
use std::fmt::Write;
use libredox::flag;
const SO_SNDBUF: usize = 7;
const SO_RCVBUF: usize = 8;
@@ -59,7 +60,7 @@ impl<'a> SchemeSocket for UdpSocket<'a> {
if !is_broadcast && !connected_addr.is_unspecified() {
if source.addr != connected_addr || source.port != data.port {
// Bad packet detetced
// Bad packet detected
// Remove it from the buffer immediately so poll() doesn't trigger
let _ = self.recv();
continue; // Loop again to check the next packet
@@ -296,6 +297,58 @@ impl<'a> SchemeSocket for UdpSocket<'a> {
Ok(i)
}
fn handle_recvmsg(&mut self, file: &mut SchemeFile<Self>, how:&mut [u8], flags:usize) -> SyscallResult<usize> {
//there is a separate flags argument for MSG_DONTWAIT which is call specific not socket-wide like socket_file.flags
let socket_file = match file{
SchemeFile::Socket(ref mut sock_f) => sock_f,
_ => return Err(SyscallError::new(syscall::EBADF))
};
if !socket_file.read_enabled {
Ok(0)
} else if self.can_recv(&socket_file.data) {
let usize_length = core::mem::size_of::<usize>();
let prepared_name_len = usize::from_le_bytes(
how[0..usize_length].try_into().map_err(|_| SyscallError::new(syscall::EINVAL))?,
);
let prepared_whole_iov_size = usize::from_le_bytes(
how[usize_length..2 * usize_length].try_into().map_err(|_| SyscallError::new(syscall::EINVAL))?,
);
let prepared_msg_controllen = usize::from_le_bytes(
how[2 * usize_length..3 * usize_length].try_into().map_err(|_| SyscallError::new(syscall::EINVAL))?,
);
if prepared_name_len + prepared_msg_controllen + prepared_whole_iov_size > how.len() {//expected returned buffer size is larger than provided -> return invalid
return Err(SyscallError::new(syscall::EINVAL));
}
//the relibc deserialization functions expect NO GAPS between the name and payload slices
//so the payload must be temporarily stored during recv_slice
let mut payload_tmp = vec![0u8; prepared_whole_iov_size - prepared_name_len];
let (length, address) = self.recv_slice(&mut payload_tmp).expect("Can't recieve slice");
//Address Handling
let address_formatted = if prepared_name_len > 0 {
format!("/scheme/udp/{}:{}", address.endpoint.addr, address.endpoint.port)
} else {
String::from("")
};
how[..usize_length].copy_from_slice(&address_formatted.len().to_le_bytes());
let payload_len_index = address_formatted.len() + usize_length;
how[usize_length..payload_len_index].copy_from_slice(&address_formatted.as_bytes());
//Payload Handling
how[payload_len_index..payload_len_index + usize_length].copy_from_slice(&(length as usize).to_le_bytes());
how[payload_len_index + usize_length..payload_len_index + usize_length + length].copy_from_slice(&payload_tmp[..length]);
//TODO should return the length of payload but relibc uses trim on the buffer incorrectly
Ok(how.len())
} else if socket_file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK || flags & flag::MSG_DONTWAIT as usize != 0 {
Err(SyscallError::new(syscall::EAGAIN))
} else {
Err(SyscallError::new(syscall::EWOULDBLOCK)) // internally scheduled to re-read
}
}
fn handle_get_peer_name(
&self,
file: &SchemeFile<Self>,