diff --git a/Cargo.lock b/Cargo.lock index 657622ddb9..31330c563b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index 3b2f5247db..9bf3ac5f00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/netstack/src/scheme/icmp.rs b/netstack/src/scheme/icmp.rs index c2b1b5d0c6..f1005e6452 100644 --- a/netstack/src/scheme/icmp.rs +++ b/netstack/src/scheme/icmp.rs @@ -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, how:&mut [u8], flags:usize) -> SyscallResult { + return Err(SyscallError::new(syscall::EOPNOTSUPP)); + } + fn handle_get_peer_name( &self, file: &SchemeFile, diff --git a/netstack/src/scheme/ip.rs b/netstack/src/scheme/ip.rs index f39d00a638..6108cea7a4 100644 --- a/netstack/src/scheme/ip.rs +++ b/netstack/src/scheme/ip.rs @@ -137,7 +137,7 @@ impl<'a> SchemeSocket for RawSocket<'a> { } fn fpath(&self, _file: &SchemeFile, buf: &mut [u8]) -> SyscallResult { - 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, how:&mut [u8], flags:usize) -> SyscallResult { + return Err(SyscallError::new(syscall::EOPNOTSUPP)); + } + fn handle_get_peer_name( &self, file: &SchemeFile, diff --git a/netstack/src/scheme/socket.rs b/netstack/src/scheme/socket.rs index a99a696a79..9f832a6660 100644 --- a/netstack/src/scheme/socket.rs +++ b/netstack/src/scheme/socket.rs @@ -243,6 +243,13 @@ where fn handle_shutdown(&mut self, file: &mut SchemeFile, how: usize) -> SyscallResult; + fn handle_recvmsg( + &mut self, + file: &mut SchemeFile, + payload: &mut [u8], + flags: usize, + ) -> SyscallResult; + fn get_sock_opt( &self, file: &SchemeFile, @@ -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::(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; diff --git a/netstack/src/scheme/tcp.rs b/netstack/src/scheme/tcp.rs index 8c46eec49c..583011197e 100644 --- a/netstack/src/scheme/tcp.rs +++ b/netstack/src/scheme/tcp.rs @@ -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, how:&mut [u8], flags:usize) -> SyscallResult { + 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::(); + 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, diff --git a/netstack/src/scheme/udp.rs b/netstack/src/scheme/udp.rs index b0ad69bbf5..8cb1292c1b 100644 --- a/netstack/src/scheme/udp.rs +++ b/netstack/src/scheme/udp.rs @@ -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, how:&mut [u8], flags:usize) -> SyscallResult { + //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::(); + 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,