From f8eca84a993b969ab7b6b5fe0bb7143f5f5a377e Mon Sep 17 00:00:00 2001 From: Jianfeng Jiang Date: Thu, 28 Dec 2023 09:24:23 +0000 Subject: [PATCH] Refactor sock option implementations --- Makefile | 6 +- services/libs/aster-std/src/fs/file_handle.rs | 2 +- services/libs/aster-std/src/fs/file_table.rs | 5 +- .../src/net/socket/ip/datagram/mod.rs | 24 +- .../libs/aster-std/src/net/socket/ip/mod.rs | 3 +- .../aster-std/src/net/socket/ip/stream/mod.rs | 122 +++++----- .../src/net/socket/ip/stream/options.rs | 71 +----- .../src/net/socket/ip/stream/util.rs | 59 +++++ services/libs/aster-std/src/net/socket/mod.rs | 20 +- .../src/net/socket/options/macros.rs | 83 +++++++ .../aster-std/src/net/socket/options/mod.rs | 120 ++-------- .../src/net/socket/options/socket.rs | 86 ------- .../aster-std/src/net/socket/unix/addr.rs | 2 +- .../src/net/socket/unix/stream/socket.rs | 12 +- .../libs/aster-std/src/net/socket/util/mod.rs | 3 +- .../aster-std/src/net/socket/util/options.rs | 53 +++++ .../util/{sockaddr.rs => socket_addr.rs} | 0 services/libs/aster-std/src/syscall/accept.rs | 21 +- services/libs/aster-std/src/syscall/bind.rs | 13 +- .../libs/aster-std/src/syscall/connect.rs | 10 +- .../libs/aster-std/src/syscall/getpeername.rs | 18 +- .../libs/aster-std/src/syscall/getsockname.rs | 11 +- .../libs/aster-std/src/syscall/getsockopt.rs | 15 +- services/libs/aster-std/src/syscall/listen.rs | 14 +- .../libs/aster-std/src/syscall/recvfrom.rs | 16 +- services/libs/aster-std/src/syscall/sendto.rs | 12 +- .../libs/aster-std/src/syscall/setsockopt.rs | 15 +- .../libs/aster-std/src/syscall/shutdown.rs | 19 +- services/libs/aster-std/src/syscall/socket.rs | 16 +- .../libs/aster-std/src/syscall/socketpair.rs | 8 +- services/libs/aster-std/src/util/net/addr.rs | 104 ++++----- services/libs/aster-std/src/util/net/mod.rs | 27 +-- .../aster-std/src/util/net/options/mod.rs | 189 ++++++++-------- .../aster-std/src/util/net/options/socket.rs | 39 ++-- .../aster-std/src/util/net/options/tcp.rs | 32 ++- .../aster-std/src/util/net/options/utils.rs | 211 ++++++++++++------ 36 files changed, 733 insertions(+), 728 deletions(-) create mode 100644 services/libs/aster-std/src/net/socket/ip/stream/util.rs create mode 100644 services/libs/aster-std/src/net/socket/options/macros.rs delete mode 100644 services/libs/aster-std/src/net/socket/options/socket.rs create mode 100644 services/libs/aster-std/src/net/socket/util/options.rs rename services/libs/aster-std/src/net/socket/util/{sockaddr.rs => socket_addr.rs} (100%) diff --git a/Makefile b/Makefile index 5ab2d5811..ec7f5b34c 100644 --- a/Makefile +++ b/Makefile @@ -98,7 +98,7 @@ USERMODE_TESTABLE := \ services/libs/typeflags \ services/libs/typeflags-util -.PHONY: all setup build tools run test docs check clean +.PHONY: all setup build tools run test docs check clean update_initramfs all: build @@ -136,3 +136,7 @@ clean: @cargo clean @cd docs && mdbook clean @make --no-print-directory -C regression clean + +update_initramfs: + @make --no-print-directory -C regression clean + @make --no-print-directory -C regression \ No newline at end of file diff --git a/services/libs/aster-std/src/fs/file_handle.rs b/services/libs/aster-std/src/fs/file_handle.rs index 05dbe218b..8bc4c71bd 100644 --- a/services/libs/aster-std/src/fs/file_handle.rs +++ b/services/libs/aster-std/src/fs/file_handle.rs @@ -71,7 +71,7 @@ pub trait FileLike: Send + Sync + Any { return_errno_with_message!(Errno::EINVAL, "unregister_observer is not supported") } - fn as_socket(&self) -> Option<&dyn Socket> { + fn as_socket(self: Arc) -> Option> { None } diff --git a/services/libs/aster-std/src/fs/file_table.rs b/services/libs/aster-std/src/fs/file_table.rs index b3b910ed4..a3eeb0a0c 100644 --- a/services/libs/aster-std/src/fs/file_table.rs +++ b/services/libs/aster-std/src/fs/file_table.rs @@ -132,8 +132,9 @@ impl FileTable { .ok_or(Error::with_message(Errno::EBADF, "fd not exits")) } - pub fn get_socket(&self, sockfd: FileDescripter) -> Result<&dyn Socket> { - self.get_file(sockfd)? + pub fn get_socket(&self, sockfd: FileDescripter) -> Result> { + let file_like = self.get_file(sockfd)?.clone(); + file_like .as_socket() .ok_or_else(|| Error::with_message(Errno::ENOTSOCK, "the fd is not a socket")) } diff --git a/services/libs/aster-std/src/net/socket/ip/datagram/mod.rs b/services/libs/aster-std/src/net/socket/ip/datagram/mod.rs index 1b376f8c5..261035cf8 100644 --- a/services/libs/aster-std/src/net/socket/ip/datagram/mod.rs +++ b/services/libs/aster-std/src/net/socket/ip/datagram/mod.rs @@ -1,18 +1,14 @@ use core::sync::atomic::{AtomicBool, Ordering}; use crate::events::IoEvents; +use crate::fs::file_handle::FileLike; use crate::fs::utils::StatusFlags; use crate::net::iface::IpEndpoint; - +use crate::net::socket::util::send_recv_flags::SendRecvFlags; +use crate::net::socket::util::socket_addr::SocketAddr; +use crate::net::socket::Socket; +use crate::prelude::*; use crate::process::signal::Poller; -use crate::{ - fs::file_handle::FileLike, - net::socket::{ - util::{send_recv_flags::SendRecvFlags, sockaddr::SocketAddr}, - Socket, - }, - prelude::*, -}; use self::bound::BoundDatagram; use self::unbound::UnboundDatagram; @@ -129,7 +125,7 @@ impl FileLike for DatagramSocket { self.inner.read().poll(mask, poller) } - fn as_socket(&self) -> Option<&dyn Socket> { + fn as_socket(self: Arc) -> Option> { Some(self) } @@ -152,14 +148,14 @@ impl FileLike for DatagramSocket { } impl Socket for DatagramSocket { - fn bind(&self, sockaddr: SocketAddr) -> Result<()> { - let endpoint = sockaddr.try_into()?; + fn bind(&self, socket_addr: SocketAddr) -> Result<()> { + let endpoint = socket_addr.try_into()?; self.inner.write().bind(endpoint)?; Ok(()) } - fn connect(&self, sockaddr: SocketAddr) -> Result<()> { - let endpoint = sockaddr.try_into()?; + fn connect(&self, socket_addr: SocketAddr) -> Result<()> { + let endpoint = socket_addr.try_into()?; let bound = self.try_bind_empheral(&endpoint)?; bound.set_remote_endpoint(endpoint); Ok(()) diff --git a/services/libs/aster-std/src/net/socket/ip/mod.rs b/services/libs/aster-std/src/net/socket/ip/mod.rs index cff0a289a..1f66a3f50 100644 --- a/services/libs/aster-std/src/net/socket/ip/mod.rs +++ b/services/libs/aster-std/src/net/socket/ip/mod.rs @@ -1,8 +1,7 @@ mod always_some; mod common; mod datagram; -mod stream; +pub mod stream; pub use datagram::DatagramSocket; -pub use stream::options as tcp_options; pub use stream::StreamSocket; diff --git a/services/libs/aster-std/src/net/socket/ip/stream/mod.rs b/services/libs/aster-std/src/net/socket/ip/stream/mod.rs index ef03d53d2..01b6b7ff2 100644 --- a/services/libs/aster-std/src/net/socket/ip/stream/mod.rs +++ b/services/libs/aster-std/src/net/socket/ip/stream/mod.rs @@ -1,26 +1,25 @@ use crate::events::IoEvents; use crate::fs::file_handle::FileLike; use crate::fs::utils::StatusFlags; -use crate::net::socket::ip::tcp_options::{ - TcpCongestion, TcpMaxseg, TcpWindowClamp, DEFAULT_MAXSEG, -}; use crate::net::socket::options::{ - SockOption, SocketError, SocketLinger, SocketOptions, SocketRecvBuf, SocketReuseAddr, - SocketReusePort, SocketSendBuf, MIN_RECVBUF, MIN_SENDBUF, + Error, Linger, RecvBuf, ReuseAddr, ReusePort, SendBuf, SocketOption, }; +use crate::net::socket::util::options::{SocketOptionSet, MIN_RECVBUF, MIN_SENDBUF}; use crate::net::socket::util::{ - send_recv_flags::SendRecvFlags, shutdown_cmd::SockShutdownCmd, sockaddr::SocketAddr, + send_recv_flags::SendRecvFlags, shutdown_cmd::SockShutdownCmd, socket_addr::SocketAddr, }; use crate::net::socket::Socket; use crate::prelude::*; use crate::process::signal::Poller; use crate::{match_sock_option_mut, match_sock_option_ref}; +use options::{Congestion, MaxSegment, WindowClamp}; +use util::{TcpOptionSet, DEFAULT_MAXSEG}; use connected::ConnectedStream; use connecting::ConnectingStream; use init::InitStream; use listen::ListenStream; -use options::{TcpNoDelay, TcpOptions}; +use options::NoDelay; use smoltcp::wire::IpEndpoint; mod connected; @@ -28,9 +27,12 @@ mod connecting; mod init; mod listen; pub mod options; +mod util; + +pub use self::util::CongestionControl; pub struct StreamSocket { - options: RwLock, + options: RwLock, state: RwLock, } @@ -46,22 +48,22 @@ enum State { } #[derive(Debug, Clone)] -struct Options { - socket: SocketOptions, - tcp: TcpOptions, +struct OptionSet { + socket: SocketOptionSet, + tcp: TcpOptionSet, } -impl Options { +impl OptionSet { fn new() -> Self { - let socket = SocketOptions::new_tcp(); - let tcp = TcpOptions::new(); - Options { socket, tcp } + let socket = SocketOptionSet::new_tcp(); + let tcp = TcpOptionSet::new(); + OptionSet { socket, tcp } } } impl StreamSocket { pub fn new(nonblocking: bool) -> Self { - let options = Options::new(); + let options = OptionSet::new(); let state = State::Init(InitStream::new(nonblocking)); Self { options: RwLock::new(options), @@ -143,14 +145,14 @@ impl FileLike for StreamSocket { Ok(()) } - fn as_socket(&self) -> Option<&dyn Socket> { + fn as_socket(self: Arc) -> Option> { Some(self) } } impl Socket for StreamSocket { - fn bind(&self, sockaddr: SocketAddr) -> Result<()> { - let endpoint = sockaddr.try_into()?; + fn bind(&self, socket_addr: SocketAddr) -> Result<()> { + let endpoint = socket_addr.try_into()?; let state = self.state.read(); match &*state { State::Init(init_stream) => init_stream.bind(endpoint), @@ -158,8 +160,8 @@ impl Socket for StreamSocket { } } - fn connect(&self, sockaddr: SocketAddr) -> Result<()> { - let remote_endpoint = sockaddr.try_into()?; + fn connect(&self, socket_addr: SocketAddr) -> Result<()> { + let remote_endpoint = socket_addr.try_into()?; let connecting_stream = self.do_connect(&remote_endpoint)?; match connecting_stream.wait_conn() { @@ -206,7 +208,7 @@ impl Socket for StreamSocket { let accepted_socket = { let state = RwLock::new(State::Connected(connected_stream)); Arc::new(StreamSocket { - options: RwLock::new(Options::new()), + options: RwLock::new(OptionSet::new()), state, }) }; @@ -279,40 +281,40 @@ impl Socket for StreamSocket { connected_stream.sendto(buf, flags) } - fn option(&self, option: &mut dyn SockOption) -> Result<()> { + fn get_option(&self, option: &mut dyn SocketOption) -> Result<()> { let options = self.options.read(); match_sock_option_mut!(option, { // Socket Options - socket_errors: SocketError => { + socket_errors: Error => { let sock_errors = options.socket.sock_errors(); - socket_errors.set_output(sock_errors); + socket_errors.set(sock_errors); }, - socket_reuse_addr: SocketReuseAddr => { + socket_reuse_addr: ReuseAddr => { let reuse_addr = options.socket.reuse_addr(); - socket_reuse_addr.set_output(reuse_addr); + socket_reuse_addr.set(reuse_addr); }, - socket_send_buf: SocketSendBuf => { + socket_send_buf: SendBuf => { let send_buf = options.socket.send_buf(); - socket_send_buf.set_output(send_buf); + socket_send_buf.set(send_buf); }, - socket_recv_buf: SocketRecvBuf => { + socket_recv_buf: RecvBuf => { let recv_buf = options.socket.recv_buf(); - socket_recv_buf.set_output(recv_buf); + socket_recv_buf.set(recv_buf); }, - socket_reuse_port: SocketReusePort => { + socket_reuse_port: ReusePort => { let reuse_port = options.socket.reuse_port(); - socket_reuse_port.set_output(reuse_port); + socket_reuse_port.set(reuse_port); }, // Tcp Options - tcp_no_delay: TcpNoDelay => { + tcp_no_delay: NoDelay => { let no_delay = options.tcp.no_delay(); - tcp_no_delay.set_output(no_delay); + tcp_no_delay.set(no_delay); }, - tcp_congestion: TcpCongestion => { + tcp_congestion: Congestion => { let congestion = options.tcp.congestion(); - tcp_congestion.set_output(congestion); + tcp_congestion.set(congestion); }, - tcp_maxseg: TcpMaxseg => { + tcp_maxseg: MaxSegment => { // It will always return the default MSS value defined above for an unconnected socket // and always return the actual current MSS for a connected one. @@ -321,64 +323,64 @@ impl Socket for StreamSocket { State::Init(_) | State::Listen(_) | State::Connecting(_) => DEFAULT_MAXSEG, State::Connected(_) => options.tcp.maxseg(), }; - tcp_maxseg.set_output(maxseg); + tcp_maxseg.set(maxseg); }, - tcp_window_clamp: TcpWindowClamp => { + tcp_window_clamp: WindowClamp => { let window_clamp = options.tcp.window_clamp(); - tcp_window_clamp.set_output(window_clamp); + tcp_window_clamp.set(window_clamp); }, _ => return_errno_with_message!(Errno::ENOPROTOOPT, "get unknown option") }); Ok(()) } - fn set_option(&self, option: &dyn SockOption) -> Result<()> { + fn set_option(&self, option: &dyn SocketOption) -> Result<()> { let mut options = self.options.write(); // FIXME: here we have only set the value of the option, without actually // making any real modifications. match_sock_option_ref!(option, { // Socket options - socket_recv_buf: SocketRecvBuf => { - let recv_buf = socket_recv_buf.input().unwrap(); + socket_recv_buf: RecvBuf => { + let recv_buf = socket_recv_buf.get().unwrap(); if *recv_buf <= MIN_RECVBUF { options.socket.set_recv_buf(MIN_RECVBUF); } else{ options.socket.set_recv_buf(*recv_buf); } }, - socket_send_buf: SocketSendBuf => { - let send_buf = socket_send_buf.input().unwrap(); + socket_send_buf: SendBuf => { + let send_buf = socket_send_buf.get().unwrap(); if *send_buf <= MIN_SENDBUF { options.socket.set_send_buf(MIN_SENDBUF); } else { options.socket.set_send_buf(*send_buf); } }, - socket_reuse_addr: SocketReuseAddr => { - let reuse_addr = socket_reuse_addr.input().unwrap(); + socket_reuse_addr: ReuseAddr => { + let reuse_addr = socket_reuse_addr.get().unwrap(); options.socket.set_reuse_addr(*reuse_addr); }, - socket_reuse_port: SocketReusePort => { - let reuse_port = socket_reuse_port.input().unwrap(); + socket_reuse_port: ReusePort => { + let reuse_port = socket_reuse_port.get().unwrap(); options.socket.set_reuse_port(*reuse_port); }, - socket_linger: SocketLinger => { - let linger = socket_linger.input().unwrap(); + socket_linger: Linger => { + let linger = socket_linger.get().unwrap(); options.socket.set_linger(*linger); }, // Tcp options - tcp_no_delay: TcpNoDelay => { - let no_delay = tcp_no_delay.input().unwrap(); + tcp_no_delay: NoDelay => { + let no_delay = tcp_no_delay.get().unwrap(); options.tcp.set_no_delay(*no_delay); }, - tcp_congestion: TcpCongestion => { - let congestion = tcp_congestion.input().unwrap(); + tcp_congestion: Congestion => { + let congestion = tcp_congestion.get().unwrap(); options.tcp.set_congestion(*congestion); }, - tcp_maxseg: TcpMaxseg => { + tcp_maxseg: MaxSegment => { const MIN_MAXSEG: u32 = 536; const MAX_MAXSEG: u32 = 65535; - let maxseg = tcp_maxseg.input().unwrap(); + let maxseg = tcp_maxseg.get().unwrap(); if *maxseg < MIN_MAXSEG || *maxseg > MAX_MAXSEG { return_errno_with_message!(Errno::EINVAL, "New maxseg should be in allowed range."); @@ -386,8 +388,8 @@ impl Socket for StreamSocket { options.tcp.set_maxseg(*maxseg); }, - tcp_window_clamp: TcpWindowClamp => { - let window_clamp = tcp_window_clamp.input().unwrap(); + tcp_window_clamp: WindowClamp => { + let window_clamp = tcp_window_clamp.get().unwrap(); let half_recv_buf = (options.socket.recv_buf()) / 2; if *window_clamp <= half_recv_buf { options.tcp.set_window_clamp(half_recv_buf); diff --git a/services/libs/aster-std/src/net/socket/ip/stream/options.rs b/services/libs/aster-std/src/net/socket/ip/stream/options.rs index 7b98c69a4..e99a9c1e3 100644 --- a/services/libs/aster-std/src/net/socket/ip/stream/options.rs +++ b/services/libs/aster-std/src/net/socket/ip/stream/options.rs @@ -1,67 +1,10 @@ -use crate::impl_sock_options; -use crate::prelude::*; +use crate::impl_socket_options; -#[derive(Debug, Clone, Copy, CopyGetters, Setters)] -#[get_copy = "pub"] -#[set = "pub"] -pub struct TcpOptions { - no_delay: bool, - congestion: Congestion, - maxseg: u32, - window_clamp: u32, -} +use super::CongestionControl; -pub const DEFAULT_MAXSEG: u32 = 536; -pub const DEFAULT_WINDOW_CLAMP: u32 = 0x8000_0000; - -impl TcpOptions { - pub fn new() -> Self { - Self { - no_delay: false, - congestion: Congestion::Reno, - maxseg: DEFAULT_MAXSEG, - window_clamp: DEFAULT_WINDOW_CLAMP, - } - } -} - -impl Default for TcpOptions { - fn default() -> Self { - Self::new() - } -} - -#[derive(Debug, Clone, Copy)] -pub enum Congestion { - Reno, - Cubic, -} - -impl Congestion { - const RENO: &'static str = "reno"; - const CUBIC: &'static str = "cubic"; - - pub fn new(name: &str) -> Result { - let congestion = match name { - Self::RENO => Self::Reno, - Self::CUBIC => Self::Cubic, - _ => return_errno_with_message!(Errno::EINVAL, "unsupported congestion name"), - }; - - Ok(congestion) - } - - pub fn name(&self) -> &'static str { - match self { - Self::Reno => Self::RENO, - Self::Cubic => Self::CUBIC, - } - } -} - -impl_sock_options!( - pub struct TcpNoDelay {} - pub struct TcpCongestion {} - pub struct TcpMaxseg {} - pub struct TcpWindowClamp {} +impl_socket_options!( + pub struct NoDelay(bool); + pub struct Congestion(CongestionControl); + pub struct MaxSegment(u32); + pub struct WindowClamp(u32); ); diff --git a/services/libs/aster-std/src/net/socket/ip/stream/util.rs b/services/libs/aster-std/src/net/socket/ip/stream/util.rs new file mode 100644 index 000000000..c37b1c0f3 --- /dev/null +++ b/services/libs/aster-std/src/net/socket/ip/stream/util.rs @@ -0,0 +1,59 @@ +use crate::prelude::*; + +#[derive(Debug, Clone, Copy, CopyGetters, Setters)] +#[get_copy = "pub"] +#[set = "pub"] +pub struct TcpOptionSet { + no_delay: bool, + congestion: CongestionControl, + maxseg: u32, + window_clamp: u32, +} + +pub const DEFAULT_MAXSEG: u32 = 536; +pub const DEFAULT_WINDOW_CLAMP: u32 = 0x8000_0000; + +impl TcpOptionSet { + pub fn new() -> Self { + Self { + no_delay: false, + congestion: CongestionControl::Reno, + maxseg: DEFAULT_MAXSEG, + window_clamp: DEFAULT_WINDOW_CLAMP, + } + } +} + +impl Default for TcpOptionSet { + fn default() -> Self { + Self::new() + } +} + +#[derive(Debug, Clone, Copy)] +pub enum CongestionControl { + Reno, + Cubic, +} + +impl CongestionControl { + const RENO: &'static str = "reno"; + const CUBIC: &'static str = "cubic"; + + pub fn new(name: &str) -> Result { + let congestion = match name { + Self::RENO => Self::Reno, + Self::CUBIC => Self::Cubic, + _ => return_errno_with_message!(Errno::EINVAL, "unsupported congestion name"), + }; + + Ok(congestion) + } + + pub fn name(&self) -> &'static str { + match self { + Self::Reno => Self::RENO, + Self::Cubic => Self::CUBIC, + } + } +} diff --git a/services/libs/aster-std/src/net/socket/mod.rs b/services/libs/aster-std/src/net/socket/mod.rs index c9f796824..2d92a02fd 100644 --- a/services/libs/aster-std/src/net/socket/mod.rs +++ b/services/libs/aster-std/src/net/socket/mod.rs @@ -1,9 +1,10 @@ use crate::{fs::file_handle::FileLike, prelude::*}; -use self::options::SockOption; +use self::options::SocketOption; +pub use self::util::options::LingerOption; pub use self::util::send_recv_flags::SendRecvFlags; pub use self::util::shutdown_cmd::SockShutdownCmd; -pub use self::util::sockaddr::SocketAddr; +pub use self::util::socket_addr::SocketAddr; pub mod ip; pub mod options; @@ -12,13 +13,13 @@ mod util; /// Operations defined on a socket. pub trait Socket: FileLike + Send + Sync { - /// Assign the address specified by sockaddr to the socket - fn bind(&self, sockaddr: SocketAddr) -> Result<()> { + /// Assign the address specified by socket_addr to the socket + fn bind(&self, socket_addr: SocketAddr) -> Result<()> { return_errno_with_message!(Errno::EINVAL, "bind not implemented"); } /// Build connection for a given address - fn connect(&self, sockaddr: SocketAddr) -> Result<()> { + fn connect(&self, socket_addr: SocketAddr) -> Result<()> { return_errno_with_message!(Errno::EINVAL, "connect not implemented"); } @@ -47,13 +48,14 @@ pub trait Socket: FileLike + Send + Sync { return_errno_with_message!(Errno::EINVAL, "getpeername not implemented"); } - /// Get options on the socket - fn option(&self, option: &mut dyn SockOption) -> Result<()> { + /// Get options on the socket. The resulted option will put in the `option` parameter, if + /// this method returns success. + fn get_option(&self, option: &mut dyn SocketOption) -> Result<()> { return_errno_with_message!(Errno::EINVAL, "getsockopt not implemented"); } - /// Set options on the socket - fn set_option(&self, option: &dyn SockOption) -> Result<()> { + /// Set options on the socket. + fn set_option(&self, option: &dyn SocketOption) -> Result<()> { return_errno_with_message!(Errno::EINVAL, "setsockopt not implemented"); } diff --git a/services/libs/aster-std/src/net/socket/options/macros.rs b/services/libs/aster-std/src/net/socket/options/macros.rs new file mode 100644 index 000000000..c1f73a907 --- /dev/null +++ b/services/libs/aster-std/src/net/socket/options/macros.rs @@ -0,0 +1,83 @@ +#[macro_export] +macro_rules! impl_socket_options { + ($( + $(#[$outer:meta])* + pub struct $name: ident ( $value_ty:ty ); + )*) => { + $( + $(#[$outer])* + #[derive(Debug)] + pub struct $name (Option<$value_ty>); + + impl $name { + pub fn new() -> Self { + Self (None) + } + + pub fn get(&self) -> Option<&$value_ty> { + self.0.as_ref() + } + + pub fn set(&mut self, value: $value_ty) { + self.0 = Some(value); + } + } + + impl $crate::net::socket::SocketOption for $name { + fn as_any(&self) -> &dyn core::any::Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn core::any::Any { + self + } + } + + impl Default for $name { + fn default() -> Self { + Self::new() + } + } + )* + }; +} + +#[macro_export] +macro_rules! match_sock_option_ref { + ( + $option:expr, { + $( $bind: ident : $ty:ty => $arm:expr ),*, + _ => $default:expr + } + ) => {{ + let __option : &dyn SocketOption = $option; + $( + if let Some($bind) = __option.as_any().downcast_ref::<$ty>() { + $arm + } else + )* + { + $default + } + }}; +} + +#[macro_export] +macro_rules! match_sock_option_mut { + ( + $option:expr, { + $( $bind: ident : $ty:ty => $arm:expr ),*, + _ => $default:expr + } + ) => {{ + let __option : &mut dyn SocketOption = $option; + $( + if let Some($bind) = __option.as_any_mut().downcast_mut::<$ty>() { + $arm + } else + )* + { + $default + } + }}; +} diff --git a/services/libs/aster-std/src/net/socket/options/mod.rs b/services/libs/aster-std/src/net/socket/options/mod.rs index 8019a0203..3cbb68245 100644 --- a/services/libs/aster-std/src/net/socket/options/mod.rs +++ b/services/libs/aster-std/src/net/socket/options/mod.rs @@ -1,113 +1,21 @@ +use crate::impl_socket_options; use crate::prelude::*; +mod macros; -mod socket; +use super::LingerOption; -pub use socket::{ - LingerOption, SockErrors, SocketError, SocketLinger, SocketOptions, SocketRecvBuf, - SocketReuseAddr, SocketReusePort, SocketSendBuf, MIN_RECVBUF, MIN_SENDBUF, -}; - -pub trait SockOption: Any + Send + Sync + Debug { +/// Socket options. This trait represents all options that can be set or got for a socket, including +/// socket level options and options for specific socket type like tcp socket. +pub trait SocketOption: Any + Send + Sync + Debug { fn as_any(&self) -> &dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any; } -// The following macros are mainly from occlum/ngo. - -#[macro_export] -macro_rules! impl_sock_options { - ($( - $(#[$outer:meta])* - pub struct $name: ident {} - )*) => { - $( - $(#[$outer])* - #[derive(Debug)] - pub struct $name { - input: Option<$input>, - output: Option<$output>, - } - - impl $name { - pub fn new() -> Self { - Self { - input: None, - output: None, - } - } - - pub fn input(&self) -> Option<&$input> { - self.input.as_ref() - } - - pub fn set_input(&mut self, input: $input) { - self.input = Some(input); - } - - pub fn output(&self) -> Option<&$output> { - self.output.as_ref() - } - - pub fn set_output(&mut self, output: $output) { - self.output = Some(output); - } - } - - impl $crate::net::socket::SockOption for $name { - fn as_any(&self) -> &dyn Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } - } - - impl Default for $name { - fn default() -> Self { - Self::new() - } - } - )* - }; -} - -#[macro_export] -macro_rules! match_sock_option_ref { - ( - $option:expr, { - $( $bind: ident : $ty:ty => $arm:expr ),*, - _ => $default:expr - } - ) => {{ - let __option : &dyn SockOption = $option; - $( - if let Some($bind) = __option.as_any().downcast_ref::<$ty>() { - $arm - } else - )* - { - $default - } - }}; -} - -#[macro_export] -macro_rules! match_sock_option_mut { - ( - $option:expr, { - $( $bind: ident : $ty:ty => $arm:expr ),*, - _ => $default:expr - } - ) => {{ - let __option : &mut dyn SockOption = $option; - $( - if let Some($bind) = __option.as_any_mut().downcast_mut::<$ty>() { - $arm - } else - )* - { - $default - } - }}; -} +impl_socket_options!( + pub struct ReuseAddr(bool); + pub struct ReusePort(bool); + pub struct SendBuf(u32); + pub struct RecvBuf(u32); + pub struct Error(Option); + pub struct Linger(LingerOption); +); diff --git a/services/libs/aster-std/src/net/socket/options/socket.rs b/services/libs/aster-std/src/net/socket/options/socket.rs deleted file mode 100644 index d7a65533b..000000000 --- a/services/libs/aster-std/src/net/socket/options/socket.rs +++ /dev/null @@ -1,86 +0,0 @@ -use core::time::Duration; - -use crate::impl_sock_options; -use crate::net::iface::{RECV_BUF_LEN, SEND_BUF_LEN}; -use crate::prelude::*; - -#[derive(Debug, Clone, CopyGetters, Setters)] -#[get_copy = "pub"] -#[set = "pub"] -pub struct SocketOptions { - sock_errors: SockErrors, - reuse_addr: bool, - reuse_port: bool, - send_buf: u32, - recv_buf: u32, - linger: LingerOption, -} - -impl SocketOptions { - pub fn new_tcp() -> Self { - Self { - sock_errors: SockErrors::no_error(), - reuse_addr: false, - reuse_port: false, - send_buf: SEND_BUF_LEN as u32, - recv_buf: RECV_BUF_LEN as u32, - linger: LingerOption::default(), - } - } -} - -pub const MIN_SENDBUF: u32 = 2304; -pub const MIN_RECVBUF: u32 = 2304; - -impl_sock_options!( - pub struct SocketReuseAddr {} - pub struct SocketReusePort {} - pub struct SocketSendBuf {} - pub struct SocketRecvBuf {} - pub struct SocketError {} - pub struct SocketLinger {} -); - -#[derive(Debug, Clone, Copy)] -pub struct SockErrors(Option); - -impl SockErrors { - pub const fn no_error() -> Self { - Self(None) - } - - pub const fn with_error(error: Error) -> Self { - Self(Some(error)) - } - - pub const fn error(&self) -> Option<&Error> { - self.0.as_ref() - } - - pub const fn as_i32(&self) -> i32 { - match &self.0 { - None => 0, - Some(err) => err.error() as i32, - } - } -} - -#[derive(Debug, Default, Clone, Copy)] -pub struct LingerOption { - is_on: bool, - timeout: Duration, -} - -impl LingerOption { - pub fn new(is_on: bool, timeout: Duration) -> Self { - Self { is_on, timeout } - } - - pub fn is_on(&self) -> bool { - self.is_on - } - - pub fn timeout(&self) -> Duration { - self.timeout - } -} diff --git a/services/libs/aster-std/src/net/socket/unix/addr.rs b/services/libs/aster-std/src/net/socket/unix/addr.rs index 825e5d021..d4f4b5e50 100644 --- a/services/libs/aster-std/src/net/socket/unix/addr.rs +++ b/services/libs/aster-std/src/net/socket/unix/addr.rs @@ -1,5 +1,5 @@ use crate::fs::utils::Dentry; -use crate::net::socket::util::sockaddr::SocketAddr; +use crate::net::socket::util::socket_addr::SocketAddr; use crate::prelude::*; #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/services/libs/aster-std/src/net/socket/unix/stream/socket.rs b/services/libs/aster-std/src/net/socket/unix/stream/socket.rs index 5112904fc..5eb6390b0 100644 --- a/services/libs/aster-std/src/net/socket/unix/stream/socket.rs +++ b/services/libs/aster-std/src/net/socket/unix/stream/socket.rs @@ -5,7 +5,7 @@ use crate::fs::utils::{Dentry, InodeType, StatusFlags}; use crate::net::socket::unix::addr::UnixSocketAddrBound; use crate::net::socket::unix::UnixSocketAddr; use crate::net::socket::util::send_recv_flags::SendRecvFlags; -use crate::net::socket::util::sockaddr::SocketAddr; +use crate::net::socket::util::socket_addr::SocketAddr; use crate::net::socket::{SockShutdownCmd, Socket}; use crate::prelude::*; use crate::process::signal::Poller; @@ -78,7 +78,7 @@ impl UnixStreamSocket { } impl FileLike for UnixStreamSocket { - fn as_socket(&self) -> Option<&dyn Socket> { + fn as_socket(self: Arc) -> Option> { Some(self) } @@ -132,8 +132,8 @@ impl FileLike for UnixStreamSocket { } impl Socket for UnixStreamSocket { - fn bind(&self, sockaddr: SocketAddr) -> Result<()> { - let addr = UnixSocketAddr::try_from(sockaddr)?; + fn bind(&self, socket_addr: SocketAddr) -> Result<()> { + let addr = UnixSocketAddr::try_from(socket_addr)?; let init = match &*self.0.read() { State::Init(init) => init.clone(), @@ -147,9 +147,9 @@ impl Socket for UnixStreamSocket { init.bind(&addr) } - fn connect(&self, sockaddr: SocketAddr) -> Result<()> { + fn connect(&self, socket_addr: SocketAddr) -> Result<()> { let remote_addr = { - let unix_socket_addr = UnixSocketAddr::try_from(sockaddr)?; + let unix_socket_addr = UnixSocketAddr::try_from(socket_addr)?; match unix_socket_addr { UnixSocketAddr::Abstract(abstract_name) => { UnixSocketAddrBound::Abstract(abstract_name) diff --git a/services/libs/aster-std/src/net/socket/util/mod.rs b/services/libs/aster-std/src/net/socket/util/mod.rs index d187727f3..cf76c1473 100644 --- a/services/libs/aster-std/src/net/socket/util/mod.rs +++ b/services/libs/aster-std/src/net/socket/util/mod.rs @@ -1,3 +1,4 @@ +pub mod options; pub mod send_recv_flags; pub mod shutdown_cmd; -pub mod sockaddr; +pub mod socket_addr; diff --git a/services/libs/aster-std/src/net/socket/util/options.rs b/services/libs/aster-std/src/net/socket/util/options.rs new file mode 100644 index 000000000..68afa5318 --- /dev/null +++ b/services/libs/aster-std/src/net/socket/util/options.rs @@ -0,0 +1,53 @@ +use core::time::Duration; + +use crate::net::iface::{RECV_BUF_LEN, SEND_BUF_LEN}; +use crate::prelude::*; + +#[derive(Debug, Clone, CopyGetters, Setters)] +#[get_copy = "pub"] +#[set = "pub"] +pub struct SocketOptionSet { + sock_errors: Option, + reuse_addr: bool, + reuse_port: bool, + send_buf: u32, + recv_buf: u32, + linger: LingerOption, +} + +impl SocketOptionSet { + /// Return the default socket level options for tcp socket. + pub fn new_tcp() -> Self { + Self { + sock_errors: None, + reuse_addr: false, + reuse_port: false, + send_buf: SEND_BUF_LEN as u32, + recv_buf: RECV_BUF_LEN as u32, + linger: LingerOption::default(), + } + } +} + +pub const MIN_SENDBUF: u32 = 2304; +pub const MIN_RECVBUF: u32 = 2304; + +#[derive(Debug, Default, Clone, Copy)] +pub struct LingerOption { + is_on: bool, + timeout: Duration, +} + +impl LingerOption { + pub fn new(is_on: bool, timeout: Duration) -> Self { + Self { is_on, timeout } + } + + pub fn is_on(&self) -> bool { + self.is_on + } + + pub fn timeout(&self) -> Duration { + self.timeout + } +} diff --git a/services/libs/aster-std/src/net/socket/util/sockaddr.rs b/services/libs/aster-std/src/net/socket/util/socket_addr.rs similarity index 100% rename from services/libs/aster-std/src/net/socket/util/sockaddr.rs rename to services/libs/aster-std/src/net/socket/util/socket_addr.rs diff --git a/services/libs/aster-std/src/syscall/accept.rs b/services/libs/aster-std/src/syscall/accept.rs index 76ed1ae89..5977afcf9 100644 --- a/services/libs/aster-std/src/syscall/accept.rs +++ b/services/libs/aster-std/src/syscall/accept.rs @@ -1,9 +1,9 @@ -use crate::util::net::write_socket_addr_to_user; -use crate::{fs::file_table::FileDescripter, prelude::*}; -use crate::{get_socket_without_holding_filetable_lock, log_syscall_entry}; +use crate::fs::file_table::FileDescripter; +use crate::log_syscall_entry; +use crate::prelude::*; +use crate::util::net::{get_socket_from_fd, write_socket_addr_to_user}; -use super::SyscallReturn; -use super::SYS_ACCEPT; +use super::{SyscallReturn, SYS_ACCEPT}; pub fn sys_accept( sockfd: FileDescripter, @@ -12,13 +12,16 @@ pub fn sys_accept( ) -> Result { log_syscall_entry!(SYS_ACCEPT); debug!("sockfd = {sockfd}, sockaddr_ptr = 0x{sockaddr_ptr:x}, addrlen_ptr = 0x{addrlen_ptr:x}"); - let current = current!(); - get_socket_without_holding_filetable_lock!(socket, current, sockfd); + + let socket = get_socket_from_fd(sockfd)?; + let (connected_socket, socket_addr) = socket.accept()?; write_socket_addr_to_user(&socket_addr, sockaddr_ptr, addrlen_ptr)?; - let fd = { + + let connected_fd = { + let current = current!(); let mut file_table = current.file_table().lock(); file_table.insert(connected_socket) }; - Ok(SyscallReturn::Return(fd as _)) + Ok(SyscallReturn::Return(connected_fd as _)) } diff --git a/services/libs/aster-std/src/syscall/bind.rs b/services/libs/aster-std/src/syscall/bind.rs index 7e9d001c5..ec49a746d 100644 --- a/services/libs/aster-std/src/syscall/bind.rs +++ b/services/libs/aster-std/src/syscall/bind.rs @@ -1,9 +1,9 @@ +use crate::fs::file_table::FileDescripter; use crate::log_syscall_entry; -use crate::util::net::read_socket_addr_from_user; -use crate::{fs::file_table::FileDescripter, prelude::*}; +use crate::prelude::*; +use crate::util::net::{get_socket_from_fd, read_socket_addr_from_user}; -use super::SyscallReturn; -use super::SYS_BIND; +use super::{SyscallReturn, SYS_BIND}; pub fn sys_bind( sockfd: FileDescripter, @@ -13,9 +13,8 @@ pub fn sys_bind( log_syscall_entry!(SYS_BIND); let socket_addr = read_socket_addr_from_user(sockaddr_ptr, addrlen as usize)?; debug!("sockfd = {sockfd}, socket_addr = {socket_addr:?}"); - let current = current!(); - let file_table = current.file_table().lock(); - let socket = file_table.get_socket(sockfd)?; + + let socket = get_socket_from_fd(sockfd)?; socket.bind(socket_addr)?; Ok(SyscallReturn::Return(0)) } diff --git a/services/libs/aster-std/src/syscall/connect.rs b/services/libs/aster-std/src/syscall/connect.rs index a305e1edc..5523af8eb 100644 --- a/services/libs/aster-std/src/syscall/connect.rs +++ b/services/libs/aster-std/src/syscall/connect.rs @@ -1,11 +1,9 @@ use crate::fs::file_table::FileDescripter; -use crate::get_socket_without_holding_filetable_lock; use crate::log_syscall_entry; use crate::prelude::*; -use crate::util::net::read_socket_addr_from_user; +use crate::util::net::{get_socket_from_fd, read_socket_addr_from_user}; -use super::SyscallReturn; -use super::SYS_CONNECT; +use super::{SyscallReturn, SYS_CONNECT}; pub fn sys_connect( sockfd: FileDescripter, @@ -15,8 +13,8 @@ pub fn sys_connect( log_syscall_entry!(SYS_CONNECT); let socket_addr = read_socket_addr_from_user(sockaddr_ptr, addr_len as _)?; debug!("fd = {sockfd}, socket_addr = {socket_addr:?}"); - let current = current!(); - get_socket_without_holding_filetable_lock!(socket, current, sockfd); + + let socket = get_socket_from_fd(sockfd)?; socket.connect(socket_addr)?; Ok(SyscallReturn::Return(0)) } diff --git a/services/libs/aster-std/src/syscall/getpeername.rs b/services/libs/aster-std/src/syscall/getpeername.rs index fa1e945b5..3ee51eeb6 100644 --- a/services/libs/aster-std/src/syscall/getpeername.rs +++ b/services/libs/aster-std/src/syscall/getpeername.rs @@ -1,8 +1,9 @@ -use crate::util::net::write_socket_addr_to_user; -use crate::{fs::file_table::FileDescripter, log_syscall_entry, prelude::*}; +use crate::fs::file_table::FileDescripter; +use crate::log_syscall_entry; +use crate::prelude::*; +use crate::util::net::{get_socket_from_fd, write_socket_addr_to_user}; -use super::SyscallReturn; -use super::SYS_GETPEERNAME; +use super::{SyscallReturn, SYS_GETPEERNAME}; pub fn sys_getpeername( sockfd: FileDescripter, @@ -11,13 +12,12 @@ pub fn sys_getpeername( ) -> Result { log_syscall_entry!(SYS_GETPEERNAME); debug!("sockfd = {sockfd}, addr = 0x{addr:x}, addrlen_ptr = 0x{addrlen_ptr:x}"); - let socket_addr = { - let current = current!(); - let file_table = current.file_table().lock(); - let socket = file_table.get_socket(sockfd)?; + + let peer_addr = { + let socket = get_socket_from_fd(sockfd)?; socket.peer_addr()? }; // FIXME: trunscate write len if addrlen is not big enough - write_socket_addr_to_user(&socket_addr, addr, addrlen_ptr)?; + write_socket_addr_to_user(&peer_addr, addr, addrlen_ptr)?; Ok(SyscallReturn::Return(0)) } diff --git a/services/libs/aster-std/src/syscall/getsockname.rs b/services/libs/aster-std/src/syscall/getsockname.rs index efea64187..13990c609 100644 --- a/services/libs/aster-std/src/syscall/getsockname.rs +++ b/services/libs/aster-std/src/syscall/getsockname.rs @@ -1,10 +1,9 @@ use crate::fs::file_table::FileDescripter; use crate::log_syscall_entry; use crate::prelude::*; -use crate::util::net::write_socket_addr_to_user; +use crate::util::net::{get_socket_from_fd, write_socket_addr_to_user}; -use super::SyscallReturn; -use super::SYS_GETSOCKNAME; +use super::{SyscallReturn, SYS_GETSOCKNAME}; pub fn sys_getsockname( sockfd: FileDescripter, @@ -13,12 +12,12 @@ pub fn sys_getsockname( ) -> Result { log_syscall_entry!(SYS_GETSOCKNAME); debug!("sockfd = {sockfd}, addr = 0x{addr:x}, addrlen_ptr = 0x{addrlen_ptr:x}"); + let socket_addr = { - let current = current!(); - let file_table = current.file_table().lock(); - let socket = file_table.get_socket(sockfd)?; + let socket = get_socket_from_fd(sockfd)?; socket.addr()? }; + // FIXME: trunscate write len if addrlen is not big enough write_socket_addr_to_user(&socket_addr, addr, addrlen_ptr)?; Ok(SyscallReturn::Return(0)) diff --git a/services/libs/aster-std/src/syscall/getsockopt.rs b/services/libs/aster-std/src/syscall/getsockopt.rs index 150878dc6..f0689af7e 100644 --- a/services/libs/aster-std/src/syscall/getsockopt.rs +++ b/services/libs/aster-std/src/syscall/getsockopt.rs @@ -1,8 +1,8 @@ use crate::fs::file_table::FileDescripter; +use crate::log_syscall_entry; use crate::prelude::*; -use crate::util::net::{new_raw_socket_option, SockOptionLevel}; +use crate::util::net::{get_socket_from_fd, new_raw_socket_option, CSocketOptionLevel}; use crate::util::{read_val_from_user, write_val_to_user}; -use crate::{get_socket_without_holding_filetable_lock, log_syscall_entry}; use super::{SyscallReturn, SYS_SETSOCKOPT}; @@ -14,24 +14,25 @@ pub fn sys_getsockopt( optlen_addr: Vaddr, ) -> Result { log_syscall_entry!(SYS_SETSOCKOPT); - let level = SockOptionLevel::try_from(level)?; + let level = CSocketOptionLevel::try_from(level)?; if optval == 0 || optlen_addr == 0 { return_errno_with_message!(Errno::EINVAL, "optval or optlen_addr is null pointer"); } let optlen: u32 = read_val_from_user(optlen_addr)?; debug!("level = {level:?}, sockfd = {sockfd}, optname = {optname:?}, optlen = {optlen}"); - let current = current!(); - get_socket_without_holding_filetable_lock!(socket, current, sockfd); + + let socket = get_socket_from_fd(sockfd)?; let mut raw_option = new_raw_socket_option(level, optname)?; debug!("raw option: {:?}", raw_option); - socket.option(raw_option.as_sock_option_mut())?; + socket.get_option(raw_option.as_sock_option_mut())?; let write_len = { + let current = current!(); let vmar = current.root_vmar(); - raw_option.write_output(vmar, optval, optlen)? + raw_option.write_to_user(vmar, optval, optlen)? }; write_val_to_user(optlen_addr, &(write_len as u32))?; diff --git a/services/libs/aster-std/src/syscall/listen.rs b/services/libs/aster-std/src/syscall/listen.rs index 5222ae475..954b473d7 100644 --- a/services/libs/aster-std/src/syscall/listen.rs +++ b/services/libs/aster-std/src/syscall/listen.rs @@ -1,14 +1,16 @@ -use crate::{fs::file_table::FileDescripter, log_syscall_entry, prelude::*}; +use crate::fs::file_table::FileDescripter; +use crate::log_syscall_entry; +use crate::prelude::*; +use crate::util::net::get_socket_from_fd; -use super::SyscallReturn; -use super::SYS_LISTEN; +use super::{SyscallReturn, SYS_LISTEN}; pub fn sys_listen(sockfd: FileDescripter, backlog: i32) -> Result { log_syscall_entry!(SYS_LISTEN); debug!("sockfd = {sockfd}, backlog = {backlog}"); - let current = current!(); - let file_table = current.file_table().lock(); - let socket = file_table.get_socket(sockfd)?; + + let socket = get_socket_from_fd(sockfd)?; + socket.listen(backlog as usize)?; Ok(SyscallReturn::Return(0)) } diff --git a/services/libs/aster-std/src/syscall/recvfrom.rs b/services/libs/aster-std/src/syscall/recvfrom.rs index 4b4781937..2dd766d14 100644 --- a/services/libs/aster-std/src/syscall/recvfrom.rs +++ b/services/libs/aster-std/src/syscall/recvfrom.rs @@ -1,11 +1,11 @@ +use crate::fs::file_table::FileDescripter; +use crate::log_syscall_entry; use crate::net::socket::SendRecvFlags; -use crate::util::net::write_socket_addr_to_user; +use crate::prelude::*; +use crate::util::net::{get_socket_from_fd, write_socket_addr_to_user}; use crate::util::write_bytes_to_user; -use crate::{fs::file_table::FileDescripter, prelude::*}; -use crate::{get_socket_without_holding_filetable_lock, log_syscall_entry}; -use super::SyscallReturn; -use super::SYS_RECVFROM; +use super::{SyscallReturn, SYS_RECVFROM}; pub fn sys_recvfrom( sockfd: FileDescripter, @@ -18,9 +18,11 @@ pub fn sys_recvfrom( log_syscall_entry!(SYS_RECVFROM); let flags = SendRecvFlags::from_bits_truncate(flags); debug!("sockfd = {sockfd}, buf = 0x{buf:x}, len = {len}, flags = {flags:?}, src_addr = 0x{src_addr:x}, addrlen_ptr = 0x{addrlen_ptr:x}"); - let current = current!(); - get_socket_without_holding_filetable_lock!(socket, current, sockfd); + + let socket = get_socket_from_fd(sockfd)?; + let mut buffer = vec![0u8; len]; + let (recv_size, socket_addr) = socket.recvfrom(&mut buffer, flags)?; if buf != 0 { write_bytes_to_user(buf, &buffer[..recv_size])?; diff --git a/services/libs/aster-std/src/syscall/sendto.rs b/services/libs/aster-std/src/syscall/sendto.rs index e1f56a8fc..3bae9a713 100644 --- a/services/libs/aster-std/src/syscall/sendto.rs +++ b/services/libs/aster-std/src/syscall/sendto.rs @@ -1,13 +1,11 @@ use crate::fs::file_table::FileDescripter; -use crate::get_socket_without_holding_filetable_lock; use crate::log_syscall_entry; use crate::net::socket::SendRecvFlags; use crate::prelude::*; -use crate::util::net::read_socket_addr_from_user; +use crate::util::net::{get_socket_from_fd, read_socket_addr_from_user}; use crate::util::read_bytes_from_user; -use super::SyscallReturn; -use super::SYS_SENDTO; +use super::{SyscallReturn, SYS_SENDTO}; pub fn sys_sendto( sockfd: FileDescripter, @@ -28,8 +26,10 @@ pub fn sys_sendto( debug!("sockfd = {sockfd}, buf = 0x{buf:x}, len = 0x{len:x}, flags = {flags:?}, socket_addr = {socket_addr:?}"); let mut buffer = vec![0u8; len]; read_bytes_from_user(buf, &mut buffer)?; - let current = current!(); - get_socket_without_holding_filetable_lock!(socket, current, sockfd); + + let socket = get_socket_from_fd(sockfd)?; + let send_size = socket.sendto(&buffer, socket_addr, flags)?; + Ok(SyscallReturn::Return(send_size as _)) } diff --git a/services/libs/aster-std/src/syscall/setsockopt.rs b/services/libs/aster-std/src/syscall/setsockopt.rs index ecc8766e5..bf7b23f45 100644 --- a/services/libs/aster-std/src/syscall/setsockopt.rs +++ b/services/libs/aster-std/src/syscall/setsockopt.rs @@ -1,6 +1,7 @@ -use crate::util::net::{new_raw_socket_option, SockOptionLevel}; -use crate::{fs::file_table::FileDescripter, prelude::*}; -use crate::{get_socket_without_holding_filetable_lock, log_syscall_entry}; +use crate::fs::file_table::FileDescripter; +use crate::log_syscall_entry; +use crate::prelude::*; +use crate::util::net::{get_socket_from_fd, new_raw_socket_option, CSocketOptionLevel}; use super::{SyscallReturn, SYS_SETSOCKOPT}; @@ -12,7 +13,7 @@ pub fn sys_setsockopt( optlen: u32, ) -> Result { log_syscall_entry!(SYS_SETSOCKOPT); - let level = SockOptionLevel::try_from(level)?; + let level = CSocketOptionLevel::try_from(level)?; if optval == 0 { return_errno_with_message!(Errno::EINVAL, "optval is null pointer"); } @@ -22,14 +23,14 @@ pub fn sys_setsockopt( level, sockfd, optname, optlen ); - let current = current!(); - get_socket_without_holding_filetable_lock!(socket, current, sockfd); + let socket = get_socket_from_fd(sockfd)?; let raw_option = { let mut option = new_raw_socket_option(level, optname)?; + let current = current!(); let vmar = current.root_vmar(); - option.read_input(vmar, optval, optlen)?; + option.read_from_user(vmar, optval, optlen)?; option }; diff --git a/services/libs/aster-std/src/syscall/shutdown.rs b/services/libs/aster-std/src/syscall/shutdown.rs index 02c0fe1a9..aa300819f 100644 --- a/services/libs/aster-std/src/syscall/shutdown.rs +++ b/services/libs/aster-std/src/syscall/shutdown.rs @@ -1,22 +1,17 @@ +use crate::fs::file_table::FileDescripter; +use crate::log_syscall_entry; use crate::net::socket::SockShutdownCmd; -use crate::{fs::file_table::FileDescripter, log_syscall_entry, prelude::*}; +use crate::prelude::*; +use crate::util::net::get_socket_from_fd; -use super::SyscallReturn; -use super::SYS_SHUTDOWN; +use super::{SyscallReturn, SYS_SHUTDOWN}; pub fn sys_shutdown(sockfd: FileDescripter, how: i32) -> Result { log_syscall_entry!(SYS_SHUTDOWN); let shutdown_cmd = SockShutdownCmd::try_from(how)?; debug!("sockfd = {sockfd}, cmd = {shutdown_cmd:?}"); - let current = current!(); - let file_table = current.file_table().lock(); - let socket = file_table - .get_file(sockfd)? - .as_socket() - .ok_or(Error::with_message( - Errno::ENOTSOCK, - "the file is not socket", - ))?; + + let socket = get_socket_from_fd(sockfd)?; socket.shutdown(shutdown_cmd)?; Ok(SyscallReturn::Return(0)) } diff --git a/services/libs/aster-std/src/syscall/socket.rs b/services/libs/aster-std/src/syscall/socket.rs index 9f91c257f..c9bfd09e7 100644 --- a/services/libs/aster-std/src/syscall/socket.rs +++ b/services/libs/aster-std/src/syscall/socket.rs @@ -1,7 +1,7 @@ use crate::fs::file_handle::FileLike; use crate::net::socket::ip::{DatagramSocket, StreamSocket}; use crate::net::socket::unix::UnixStreamSocket; -use crate::util::net::{Protocol, SaFamily, SockFlags, SockType, SOCK_TYPE_MASK}; +use crate::util::net::{CSocketAddrFamily, Protocol, SockFlags, SockType, SOCK_TYPE_MASK}; use crate::{log_syscall_entry, prelude::*}; use super::SyscallReturn; @@ -9,7 +9,7 @@ use super::SYS_SOCKET; pub fn sys_socket(domain: i32, type_: i32, protocol: i32) -> Result { log_syscall_entry!(SYS_SOCKET); - let domain = SaFamily::try_from(domain)?; + let domain = CSocketAddrFamily::try_from(domain)?; let sock_type = SockType::try_from(type_ & SOCK_TYPE_MASK)?; let sock_flags = SockFlags::from_bits_truncate(type_ & !SOCK_TYPE_MASK); let protocol = Protocol::try_from(protocol)?; @@ -19,17 +19,19 @@ pub fn sys_socket(domain: i32, type_: i32, protocol: i32) -> Result Arc::new(UnixStreamSocket::new( + (CSocketAddrFamily::AF_UNIX, SockType::SOCK_STREAM, _) => Arc::new(UnixStreamSocket::new( sock_flags.contains(SockFlags::SOCK_NONBLOCK), )) as Arc, ( - SaFamily::AF_INET, + CSocketAddrFamily::AF_INET, SockType::SOCK_STREAM, Protocol::IPPROTO_IP | Protocol::IPPROTO_TCP, ) => Arc::new(StreamSocket::new(nonblocking)) as Arc, - (SaFamily::AF_INET, SockType::SOCK_DGRAM, Protocol::IPPROTO_IP | Protocol::IPPROTO_UDP) => { - Arc::new(DatagramSocket::new(nonblocking)) as Arc - } + ( + CSocketAddrFamily::AF_INET, + SockType::SOCK_DGRAM, + Protocol::IPPROTO_IP | Protocol::IPPROTO_UDP, + ) => Arc::new(DatagramSocket::new(nonblocking)) as Arc, _ => return_errno_with_message!(Errno::EAFNOSUPPORT, "unsupported domain"), }; let fd = { diff --git a/services/libs/aster-std/src/syscall/socketpair.rs b/services/libs/aster-std/src/syscall/socketpair.rs index 2a483db09..f00929433 100644 --- a/services/libs/aster-std/src/syscall/socketpair.rs +++ b/services/libs/aster-std/src/syscall/socketpair.rs @@ -1,6 +1,6 @@ use crate::fs::file_table::FileDescripter; use crate::net::socket::unix::UnixStreamSocket; -use crate::util::net::{Protocol, SaFamily, SockFlags, SockType, SOCK_TYPE_MASK}; +use crate::util::net::{CSocketAddrFamily, Protocol, SockFlags, SockType, SOCK_TYPE_MASK}; use crate::util::write_val_to_user; use crate::{log_syscall_entry, prelude::*}; @@ -9,7 +9,7 @@ use super::SYS_SOCKETPAIR; pub fn sys_socketpair(domain: i32, type_: i32, protocol: i32, sv: Vaddr) -> Result { log_syscall_entry!(SYS_SOCKETPAIR); - let domain = SaFamily::try_from(domain)?; + let domain = CSocketAddrFamily::try_from(domain)?; let sock_type = SockType::try_from(type_ & SOCK_TYPE_MASK)?; let sock_flags = SockFlags::from_bits_truncate(type_ & !SOCK_TYPE_MASK); let protocol = Protocol::try_from(protocol)?; @@ -21,7 +21,9 @@ pub fn sys_socketpair(domain: i32, type_: i32, protocol: i32, sv: Vaddr) -> Resu // TODO: deal with all sock_flags and protocol let nonblocking = sock_flags.contains(SockFlags::SOCK_NONBLOCK); let (socket_a, socket_b) = match (domain, sock_type) { - (SaFamily::AF_UNIX, SockType::SOCK_STREAM) => UnixStreamSocket::new_pair(nonblocking)?, + (CSocketAddrFamily::AF_UNIX, SockType::SOCK_STREAM) => { + UnixStreamSocket::new_pair(nonblocking)? + } _ => return_errno_with_message!( Errno::EAFNOSUPPORT, "cannot create socket pair for this family" diff --git a/services/libs/aster-std/src/util/net/addr.rs b/services/libs/aster-std/src/util/net/addr.rs index bb1a0ac0a..db88aa74e 100644 --- a/services/libs/aster-std/src/util/net/addr.rs +++ b/services/libs/aster-std/src/util/net/addr.rs @@ -5,16 +5,16 @@ use crate::prelude::*; use crate::util::{read_bytes_from_user, read_val_from_user, write_val_to_user}; pub fn read_socket_addr_from_user(addr: Vaddr, addr_len: usize) -> Result { - debug_assert!(addr_len >= core::mem::size_of::()); - let sockaddr: SockAddr = read_val_from_user(addr)?; + debug_assert!(addr_len >= core::mem::size_of::()); + let sockaddr: CSocketAddr = read_val_from_user(addr)?; let socket_addr = match sockaddr.sa_family()? { - SaFamily::AF_UNSPEC => { + CSocketAddrFamily::AF_UNSPEC => { return_errno_with_message!(Errno::EINVAL, "the socket addr family is unspecified") } - SaFamily::AF_UNIX => { - debug_assert!(addr_len >= core::mem::size_of::()); + CSocketAddrFamily::AF_UNIX => { + debug_assert!(addr_len >= core::mem::size_of::()); let sa_family: u16 = read_val_from_user(addr)?; - debug_assert!(sa_family == SaFamily::AF_UNIX as u16); + debug_assert!(sa_family == CSocketAddrFamily::AF_UNIX as u16); let bytes = { let bytes_len = addr_len - core::mem::size_of::(); @@ -37,14 +37,14 @@ pub fn read_socket_addr_from_user(addr: Vaddr, addr_len: usize) -> Result { - debug_assert!(addr_len >= core::mem::size_of::()); - let sock_addr_in: SockAddrInet = read_val_from_user(addr)?; + CSocketAddrFamily::AF_INET => { + debug_assert!(addr_len >= core::mem::size_of::()); + let sock_addr_in: CSocketAddrInet = read_val_from_user(addr)?; SocketAddr::from(sock_addr_in) } - SaFamily::AF_INET6 => { - debug_assert!(addr_len >= core::mem::size_of::()); - let sock_addr_in6: SockAddrInet6 = read_val_from_user(addr)?; + CSocketAddrFamily::AF_INET6 => { + debug_assert!(addr_len >= core::mem::size_of::()); + let sock_addr_in6: CSocketAddrInet6 = read_val_from_user(addr)?; todo!() } _ => { @@ -66,16 +66,16 @@ pub fn write_socket_addr_to_user( let max_len = read_val_from_user::(addrlen_ptr)? as usize; let write_size = match socket_addr { SocketAddr::Unix(path) => { - let sock_addr_unix = SockAddrUnix::try_from(path)?; - let write_size = core::mem::size_of::(); + let sock_addr_unix = CSocketAddrUnix::try_from(path)?; + let write_size = core::mem::size_of::(); debug_assert!(max_len >= write_size); write_val_to_user(dest, &sock_addr_unix)?; write_size as i32 } SocketAddr::IPv4(addr, port) => { - let in_addr = InetAddr::from(*addr); - let sock_addr_in = SockAddrInet::new(*port, in_addr); - let write_size = core::mem::size_of::(); + let in_addr = CInetAddr::from(*addr); + let sock_addr_in = CSocketAddrInet::new(*port, in_addr); + let write_size = core::mem::size_of::(); debug_assert!(max_len >= write_size); write_val_to_user(dest, &sock_addr_in)?; write_size as i32 @@ -91,34 +91,34 @@ pub fn write_socket_addr_to_user( /// PlaceHolder #[derive(Debug, Clone, Copy, Pod)] #[repr(C)] -pub struct SockAddr { +pub struct CSocketAddr { sa_family: u16, // SaFamily sa_data: [u8; 14], } -impl SockAddr { - pub fn sa_family(&self) -> Result { - Ok(SaFamily::try_from(self.sa_family as i32)?) +impl CSocketAddr { + pub fn sa_family(&self) -> Result { + Ok(CSocketAddrFamily::try_from(self.sa_family as i32)?) } } -const SOCK_ADDR_UNIX_LEN: usize = 108; +const SOCKET_ADDR_UNIX_LEN: usize = 108; #[repr(C)] #[derive(Debug, Clone, Copy, Pod)] -pub struct SockAddrUnix { +pub struct CSocketAddrUnix { sun_family: u16, // Always SaFamily::AF_UNIX - sun_path: [u8; SOCK_ADDR_UNIX_LEN], + sun_path: [u8; SOCKET_ADDR_UNIX_LEN], } /// IPv4 4-byte address #[repr(C)] #[derive(Debug, Clone, Copy, Pod)] -pub struct InetAddr { +pub struct CInetAddr { s_addr: [u8; 4], } -impl InetAddr { +impl CInetAddr { pub fn as_bytes(&self) -> &[u8] { &self.s_addr } @@ -133,11 +133,11 @@ impl InetAddr { #[derive(Debug, Clone, Copy, Pod)] #[repr(C)] -pub struct PortNum { +pub struct CPortNum { port: [u8; 2], } -impl PortNum { +impl CPortNum { pub fn as_u16(&self) -> u16 { u16::from_be_bytes(self.port) } @@ -151,22 +151,22 @@ impl PortNum { /// IPv4 socket address #[repr(C)] #[derive(Debug, Clone, Copy, Pod)] -pub struct SockAddrInet { +pub struct CSocketAddrInet { /// always SaFamily::AF_INET sin_family: u16, /// Port number - sin_port_t: PortNum, + sin_port_t: CPortNum, /// IPv4 address - sin_addr: InetAddr, + sin_addr: CInetAddr, /// Pad to size of 'SockAddr' structure (16 bytes) _pad: [u8; 8], } -impl SockAddrInet { - pub fn new(port: u16, addr: InetAddr) -> Self { - let port = PortNum::from_u16(port); +impl CSocketAddrInet { + pub fn new(port: u16, addr: CInetAddr) -> Self { + let port = CPortNum::from_u16(port); Self { - sin_family: SaFamily::AF_INET as _, + sin_family: CSocketAddrFamily::AF_INET as _, sin_port_t: port, sin_addr: addr, _pad: [0u8; 8], @@ -176,11 +176,11 @@ impl SockAddrInet { #[repr(C)] #[derive(Debug, Clone, Copy, Pod)] -pub struct Inet6Addr { +pub struct CInet6Addr { s6_addr: [u8; 16], } -impl Inet6Addr { +impl CInet6Addr { pub fn as_bytes(&self) -> &[u8] { &self.s6_addr } @@ -189,15 +189,15 @@ impl Inet6Addr { /// IPv6 socket address #[repr(C)] #[derive(Debug, Clone, Copy, Pod)] -pub struct SockAddrInet6 { +pub struct CSocketAddrInet6 { /// always SaFamily::AF_INET6 sin6_family: u16, /// Port number - sin6_port: PortNum, + sin6_port: CPortNum, /// IPv6 flow information sin6_flowinfo: u32, /// IPv6 address - sin6_addr: Inet6Addr, + sin6_addr: CInet6Addr, // Scope ID sin6_scope_id: u32, } @@ -206,7 +206,7 @@ pub struct SockAddrInet6 { #[repr(i32)] #[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq)] #[allow(non_camel_case_types)] -pub enum SaFamily { +pub enum CSocketAddrFamily { AF_UNSPEC = 0, AF_UNIX = 1, /* Unix domain sockets */ //AF_LOCAL 1 /* POSIX name for AF_UNIX */ @@ -263,40 +263,40 @@ pub enum SaFamily { AF_MAX = 46, /* For now.. */ } -impl From for Ipv4Address { - fn from(value: InetAddr) -> Self { +impl From for Ipv4Address { + fn from(value: CInetAddr) -> Self { let addr = value.as_bytes(); Ipv4Address::from_bytes(addr) } } -impl From for InetAddr { +impl From for CInetAddr { fn from(value: Ipv4Address) -> Self { let bytes = value.as_bytes(); - InetAddr::from_bytes(bytes) + CInetAddr::from_bytes(bytes) } } -impl From for SocketAddr { - fn from(value: SockAddrInet) -> Self { +impl From for SocketAddr { + fn from(value: CSocketAddrInet) -> Self { let port = value.sin_port_t.as_u16(); let addr = Ipv4Address::from(value.sin_addr); SocketAddr::IPv4(addr, port) } } -impl TryFrom<&UnixSocketAddr> for SockAddrUnix { +impl TryFrom<&UnixSocketAddr> for CSocketAddrUnix { type Error = Error; fn try_from(value: &UnixSocketAddr) -> Result { - let mut sun_path = [0u8; SOCK_ADDR_UNIX_LEN]; + let mut sun_path = [0u8; SOCKET_ADDR_UNIX_LEN]; match value { UnixSocketAddr::Path(path) => { let bytes = path.as_bytes(); - let copy_len = bytes.len().min(SOCK_ADDR_UNIX_LEN - 1); + let copy_len = bytes.len().min(SOCKET_ADDR_UNIX_LEN - 1); sun_path[..copy_len].copy_from_slice(&bytes[..copy_len]); - Ok(SockAddrUnix { - sun_family: SaFamily::AF_UNIX as u16, + Ok(CSocketAddrUnix { + sun_family: CSocketAddrFamily::AF_UNIX as u16, sun_path, }) } diff --git a/services/libs/aster-std/src/util/net/mod.rs b/services/libs/aster-std/src/util/net/mod.rs index 2d6320664..15a6078c8 100644 --- a/services/libs/aster-std/src/util/net/mod.rs +++ b/services/libs/aster-std/src/util/net/mod.rs @@ -2,23 +2,16 @@ mod addr; mod options; mod socket; -pub use addr::{ - read_socket_addr_from_user, write_socket_addr_to_user, InetAddr, SaFamily, SockAddr, - SockAddrInet, SockAddrInet6, SockAddrUnix, -}; -pub use options::{new_raw_socket_option, RawSockOption, SockOptionLevel}; +pub use addr::{read_socket_addr_from_user, write_socket_addr_to_user, CSocketAddrFamily}; +pub use options::{new_raw_socket_option, CSocketOptionLevel}; pub use socket::{Protocol, SockFlags, SockType, SOCK_TYPE_MASK}; -#[macro_export] -macro_rules! get_socket_without_holding_filetable_lock { - ($name:tt, $current: expr, $sockfd: expr) => { - let file_like = { - let file_table = $current.file_table().lock(); - file_table.get_file($sockfd)?.clone() - // Drop filetable here to avoid locking - }; - let $name = file_like - .as_socket() - .ok_or_else(|| Error::with_message(Errno::ENOTSOCK, "the file is not socket"))?; - }; +use crate::fs::file_table::FileDescripter; +use crate::net::socket::Socket; +use crate::prelude::*; + +pub fn get_socket_from_fd(sockfd: FileDescripter) -> Result> { + let current = current!(); + let file_table = current.file_table().lock(); + file_table.get_socket(sockfd) } diff --git a/services/libs/aster-std/src/util/net/options/mod.rs b/services/libs/aster-std/src/util/net/options/mod.rs index 2160b9c5c..cf66b4a63 100644 --- a/services/libs/aster-std/src/util/net/options/mod.rs +++ b/services/libs/aster-std/src/util/net/options/mod.rs @@ -1,8 +1,54 @@ -use aster_rights::Full; +//! This module introduces utilities to support Linux get/setsockopt syscalls. +//! +//! These two syscalls are used to get/set options for a socket. These options can be at different +//! socket levels and of different types. To provide a unified interface, the `Socket` trait accepts +//! a `dyn SocketOption` as a parameter. For each socket option, We define a struct that implements +//! the `SocketOption` trait in net module. +//! +//! However, different socket options may have values of different types. For example, the values can +//! be u32, C structs, or byte arrays. Furthermore, some values may have different formats in kernel +//! space and user space. For example, for the option `ReusePort`, the user space may use an i32 while +//! the kernel space may use a bool. +//! +//! We introduce the `RawSocketOption` trait for reading/writing socket options from/to user space. It +//! can read/write values of different types and can convert the user type to the kernel type when +//! reading from the user space and vice versa when writing to the user space. The `RawSocketOption` +//! should not be implemented for a type by hand, and we provide macros to automatically implement the +//! trait. +//! +//! # Example +//! +//! Suppose we want to add a new option `TcpNodelay`. +//! +//! First, the option should be added in the net module for the TCP socket. +//! +//! ```rust norun +//! impl_socket_option!(TcpNodelay(bool)); +//! ``` +//! +//! Then, we need to implement the `ReadFromUser` and `WriteFromUser` traits for the bool type +//! in the utils module. These util functions can be shared if multiple options have the value +//! of same type. +//! +//! ```rust norun +//! impl ReadFromUser for bool { // content omitted here } +//! impl WriteFromUser for bool { // content omitted here } +//! ``` +//! +//! At last, we can implement `RawSocketOption` for `TcpNodelay` so that it can be read/from +//! user space. +//! +//! ```rust norun +//! impl_raw_socket_option!(TcpNodeley); +//! ``` +//! +//! At the syscall level, the interface is unified for all options and does not need to be modified. +//! -use crate::net::socket::options::SockOption; +use crate::net::socket::options::SocketOption; use crate::prelude::*; use crate::vm::vmar::Vmar; +use aster_rights::Full; mod socket; mod tcp; @@ -11,89 +57,58 @@ mod utils; use self::socket::new_socket_option; use self::tcp::new_tcp_option; -pub trait RawSockOption: SockOption { - fn read_input(&mut self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result<()>; +pub trait RawSocketOption: SocketOption { + fn read_from_user(&mut self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result<()>; - fn write_output(&self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result; + fn write_to_user(&self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result; - fn as_sock_option_mut(&mut self) -> &mut dyn SockOption; + fn as_sock_option_mut(&mut self) -> &mut dyn SocketOption; - fn as_sock_option(&self) -> &dyn SockOption; + fn as_sock_option(&self) -> &dyn SocketOption; } -/// Impl `RawSockOption` for a struct which implements `SockOption`. +/// Impl `RawSocketOption` for a struct which implements `SocketOption`. #[macro_export] -macro_rules! impl_raw_sock_option { +macro_rules! impl_raw_socket_option { ($option:ty) => { - impl RawSockOption for $option { - fn read_input(&mut self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result<()> { - use aster_frame::vm::VmIo; - - let input = vmar.read_val(addr)?; - - if (max_len as usize) < core::mem::size_of_val(&input) { - return_errno_with_message!(Errno::EINVAL, "max_len is too small"); - } - - self.set_input(input); + impl RawSocketOption for $option { + fn read_from_user( + &mut self, + vmar: &Vmar, + addr: Vaddr, + max_len: u32, + ) -> Result<()> { + use $crate::util::net::options::utils::ReadFromUser; + let input = ReadFromUser::read_from_user(vmar, addr, max_len)?; + self.set(input); Ok(()) } - fn write_output(&self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { - use aster_frame::vm::VmIo; + fn write_to_user(&self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { + use $crate::util::net::options::utils::WriteToUser; - let output = self.output().unwrap(); - - let write_len = core::mem::size_of_val(output); - - if (max_len as usize) < write_len { - return_errno_with_message!(Errno::EINVAL, "max_len is too small"); - } - - vmar.write_val(addr, output)?; - Ok(write_len) + let output = self.get().unwrap(); + output.write_to_user(vmar, addr, max_len) } - fn as_sock_option_mut(&mut self) -> &mut dyn SockOption { + fn as_sock_option_mut(&mut self) -> &mut dyn SocketOption { self } - fn as_sock_option(&self) -> &dyn SockOption { - self - } - } - }; - ($option: ty, $reader: ident, $writer: ident) => { - impl RawSockOption for $option { - fn read_input(&mut self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result<()> { - let input = $reader(vmar, addr, max_len)?; - self.set_input(input); - Ok(()) - } - - fn write_output(&self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { - let output = self.output().unwrap(); - $writer(output, vmar, addr, max_len) - } - - fn as_sock_option_mut(&mut self) -> &mut dyn SockOption { - self - } - - fn as_sock_option(&self) -> &dyn SockOption { + fn as_sock_option(&self) -> &dyn SocketOption { self } } }; } -/// Impl `RawSockOption` for a struct which is for only `getsockopt` and implements `SockOption`. +/// Impl `RawSocketOption` for a struct which is for only `getsockopt` and implements `SocketOption`. #[macro_export] macro_rules! impl_raw_sock_option_get_only { ($option:ty) => { - impl RawSockOption for $option { - fn read_input( + impl RawSocketOption for $option { + fn read_from_user( &mut self, _vmar: &Vmar, _addr: Vaddr, @@ -102,61 +117,31 @@ macro_rules! impl_raw_sock_option_get_only { return_errno_with_message!(Errno::ENOPROTOOPT, "the option is getter-only"); } - fn write_output(&self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { - use jinux_frame::vm::VmIo; + fn write_to_user(&self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { + use $crate::util::net::options::utils::WriteToUser; - let output = self.output().unwrap(); - - let write_len = core::mem::size_of_val(output); - - if (max_len as usize) < write_len { - return_errno_with_message!(Errno::EINVAL, "max_len is too small"); - } - - vmar.write_val(addr, output)?; - Ok(write_len) + let output = self.get().unwrap(); + output.write_to_user(vmar, addr, max_len) } - fn as_sock_option_mut(&mut self) -> &mut dyn SockOption { + fn as_sock_option_mut(&mut self) -> &mut dyn SocketOption { self } - fn as_sock_option(&self) -> &dyn SockOption { - self - } - } - }; - ($option: ty, $writer: ident) => { - impl RawSockOption for $option { - fn read_input( - &mut self, - _vmar: &Vmar, - _addr: Vaddr, - _max_len: u32, - ) -> Result<()> { - return_errno_with_message!(Errno::ENOPROTOOPT, "the option is getter-only"); - } - - fn write_output(&self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { - let output = self.output().unwrap(); - $writer(output, vmar, addr, max_len) - } - - fn as_sock_option_mut(&mut self) -> &mut dyn SockOption { - self - } - - fn as_sock_option(&self) -> &dyn SockOption { + fn as_sock_option(&self) -> &dyn SocketOption { self } } }; } -pub fn new_raw_socket_option(level: SockOptionLevel, name: i32) -> Result> { +pub fn new_raw_socket_option( + level: CSocketOptionLevel, + name: i32, +) -> Result> { match level { - SockOptionLevel::SOL_SOCKET => new_socket_option(name), - SockOptionLevel::SOL_TCP => new_tcp_option(name), + CSocketOptionLevel::SOL_SOCKET => new_socket_option(name), + CSocketOptionLevel::SOL_TCP => new_tcp_option(name), _ => todo!(), } } @@ -165,7 +150,7 @@ pub fn new_raw_socket_option(level: SockOptionLevel, name: i32) -> Result Result> { - let name = SocketOptionName::try_from(name)?; +pub fn new_socket_option(name: i32) -> Result> { + let name = CSocketOptionName::try_from(name)?; match name { - SocketOptionName::SNDBUF => Ok(Box::new(SocketSendBuf::new())), - SocketOptionName::RCVBUF => Ok(Box::new(SocketRecvBuf::new())), - SocketOptionName::REUSEADDR => Ok(Box::new(SocketReuseAddr::new())), - SocketOptionName::ERROR => Ok(Box::new(SocketError::new())), - SocketOptionName::REUSEPORT => Ok(Box::new(SocketReusePort::new())), - SocketOptionName::LINGER => Ok(Box::new(SocketLinger::new())), + CSocketOptionName::SNDBUF => Ok(Box::new(SendBuf::new())), + CSocketOptionName::RCVBUF => Ok(Box::new(RecvBuf::new())), + CSocketOptionName::REUSEADDR => Ok(Box::new(ReuseAddr::new())), + CSocketOptionName::ERROR => Ok(Box::new(Error::new())), + CSocketOptionName::REUSEPORT => Ok(Box::new(ReusePort::new())), + CSocketOptionName::LINGER => Ok(Box::new(Linger::new())), _ => todo!(), } } -impl_raw_sock_option!(SocketSendBuf); -impl_raw_sock_option!(SocketRecvBuf); -impl_raw_sock_option!(SocketReuseAddr, read_bool, write_bool); -impl_raw_sock_option_get_only!(SocketError, write_errors); -impl_raw_sock_option!(SocketReusePort, read_bool, write_bool); -impl_raw_sock_option!(SocketLinger, read_linger, write_linger); +impl_raw_socket_option!(SendBuf); +impl_raw_socket_option!(RecvBuf); +impl_raw_socket_option!(ReuseAddr); +impl_raw_sock_option_get_only!(Error); +impl_raw_socket_option!(ReusePort); +impl_raw_socket_option!(Linger); diff --git a/services/libs/aster-std/src/util/net/options/tcp.rs b/services/libs/aster-std/src/util/net/options/tcp.rs index 08657b457..426e5c123 100644 --- a/services/libs/aster-std/src/util/net/options/tcp.rs +++ b/services/libs/aster-std/src/util/net/options/tcp.rs @@ -1,13 +1,11 @@ -use crate::impl_raw_sock_option; -use crate::net::socket::ip::tcp_options::{TcpCongestion, TcpMaxseg, TcpNoDelay, TcpWindowClamp}; +use super::RawSocketOption; +use crate::impl_raw_socket_option; +use crate::net::socket::ip::stream::options::{Congestion, MaxSegment, NoDelay, WindowClamp}; use crate::prelude::*; -use crate::util::net::options::SockOption; +use crate::util::net::options::SocketOption; use crate::vm::vmar::Vmar; use aster_rights::Full; -use super::utils::{read_bool, read_congestion, write_bool, write_congestion}; -use super::RawSockOption; - /// Sock options for tcp socket. /// /// The raw definition is from https://elixir.bootlin.com/linux/v6.0.9/source/include/uapi/linux/tcp.h#L92 @@ -15,7 +13,7 @@ use super::RawSockOption; #[derive(Debug, Clone, Copy, TryFromInt)] #[allow(non_camel_case_types)] #[allow(clippy::upper_case_acronyms)] -pub enum TcpOptionName { +pub enum CTcpOptionName { NODELAY = 1, /* Turn off Nagle's algorithm. */ MAXSEG = 2, /* Limit MSS */ CORK = 3, /* Never send partially complete segments */ @@ -25,18 +23,18 @@ pub enum TcpOptionName { CONGESTION = 13, /* Congestion control algorithm */ } -pub fn new_tcp_option(name: i32) -> Result> { - let name = TcpOptionName::try_from(name)?; +pub fn new_tcp_option(name: i32) -> Result> { + let name = CTcpOptionName::try_from(name)?; match name { - TcpOptionName::NODELAY => Ok(Box::new(TcpNoDelay::new())), - TcpOptionName::CONGESTION => Ok(Box::new(TcpCongestion::new())), - TcpOptionName::MAXSEG => Ok(Box::new(TcpMaxseg::new())), - TcpOptionName::WINDOW_CLAMP => Ok(Box::new(TcpWindowClamp::new())), + CTcpOptionName::NODELAY => Ok(Box::new(NoDelay::new())), + CTcpOptionName::CONGESTION => Ok(Box::new(Congestion::new())), + CTcpOptionName::MAXSEG => Ok(Box::new(MaxSegment::new())), + CTcpOptionName::WINDOW_CLAMP => Ok(Box::new(WindowClamp::new())), _ => todo!(), } } -impl_raw_sock_option!(TcpNoDelay, read_bool, write_bool); -impl_raw_sock_option!(TcpCongestion, read_congestion, write_congestion); -impl_raw_sock_option!(TcpMaxseg); -impl_raw_sock_option!(TcpWindowClamp); +impl_raw_socket_option!(NoDelay); +impl_raw_socket_option!(Congestion); +impl_raw_socket_option!(MaxSegment); +impl_raw_socket_option!(WindowClamp); diff --git a/services/libs/aster-std/src/util/net/options/utils.rs b/services/libs/aster-std/src/util/net/options/utils.rs index 8cf5fbc9a..cd776f739 100644 --- a/services/libs/aster-std/src/util/net/options/utils.rs +++ b/services/libs/aster-std/src/util/net/options/utils.rs @@ -1,110 +1,173 @@ -use crate::net::socket::ip::tcp_options::Congestion; -use crate::net::socket::options::{LingerOption, SockErrors}; +use crate::net::socket::ip::stream::CongestionControl; +use crate::net::socket::LingerOption; use crate::prelude::*; use crate::vm::vmar::Vmar; use aster_frame::vm::VmIo; use aster_rights::Full; use core::time::Duration; -pub fn read_bool(vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { - if (max_len as usize) < core::mem::size_of::() { - return_errno_with_message!(Errno::EINVAL, "max_len is too short"); - } - - let val = vmar.read_val::(addr)?; - - Ok(val != 0) +/// Create an object by reading its C counterpart from the user space. +/// +/// Note that the format of a value in the user space may be different from that +/// in the kernel space. For example, the type of a boolean value in the kernel +/// is expressed as `bool`, whereas that in the user space is `i32`. +/// +/// In addition, since the user space is not trusted by the kernel, values read +/// from the user space must be validated by the kernel. +pub trait ReadFromUser: Sized { + /// Read a struct from user space by reading its C counterpart. + fn read_from_user(vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result; } -pub fn write_bool(val: &bool, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { - let write_len = core::mem::size_of::(); - - if (max_len as usize) < write_len { - return_errno_with_message!(Errno::EINVAL, "max_len is too short"); - } - - let val = if *val { 1i32 } else { 0i32 }; - vmar.write_val(addr, &val)?; - Ok(write_len) +/// Write an object to user space by writing its C counterpart. +/// +/// Note that the format of a value in the user space may be different from that +/// in the kernel space. But the format should be consistent with `ReadFromUser`, i.e, +/// if we call `read_from_user` and `write_from_user` for the same type, the read value +/// and write value in user space should be of same type. +pub trait WriteToUser { + // Write a struct to user space by writing its C counterpart. + fn write_to_user(&self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result; } -pub fn write_errors( - errors: &SockErrors, - vmar: &Vmar, - addr: Vaddr, - max_len: u32, -) -> Result { - let write_len = core::mem::size_of::(); +/// This macro is used to implement `ReadFromUser` and `WriteToUser` for types that +/// implement the `Pod` trait. +/// FIXME: The macro is somewhat ugly. Ideally, we would prefer to use +/// ```rust +/// impl ReadFromUser for T +/// ``` +/// instead of this macro. However, using the `impl` statement will result in a compilation +/// error, as it is possible for an upstream crate to implement `Pod` for other types like `bool`, +macro_rules! impl_read_write_for_pod_type { + ($pod_ty: ty) => { + impl ReadFromUser for $pod_ty { + fn read_from_user(vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { + if (max_len as usize) < core::mem::size_of::<$pod_ty>() { + return_errno_with_message!(Errno::EINVAL, "max_len is too short"); + } + Ok(vmar.read_val::<$pod_ty>(addr)?) + } + } - if (max_len as usize) < write_len { - return_errno_with_message!(Errno::EINVAL, "max_len is too short"); - } + impl WriteToUser for $pod_ty { + fn write_to_user(&self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { + let write_len = core::mem::size_of::<$pod_ty>(); - let val = errors.as_i32(); - vmar.write_val(addr, &val)?; - Ok(write_len) + if (max_len as usize) < write_len { + return_errno_with_message!(Errno::EINVAL, "max_len is too short"); + } + + vmar.write_val(addr, self)?; + Ok(write_len) + } + } + }; } -pub fn read_linger(vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { - if (max_len as usize) < core::mem::size_of::() { - return_errno_with_message!(Errno::EINVAL, "max_len is too short"); +impl_read_write_for_pod_type!(u32); + +impl ReadFromUser for bool { + fn read_from_user(vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { + if (max_len as usize) < core::mem::size_of::() { + return_errno_with_message!(Errno::EINVAL, "max_len is too short"); + } + + let val = vmar.read_val::(addr)?; + + Ok(val != 0) } - - let linger = vmar.read_val::(addr)?; - - Ok(LingerOption::from(linger)) } -pub fn write_linger( - linger_option: &LingerOption, - vmar: &Vmar, - addr: Vaddr, - max_len: u32, -) -> Result { - let write_len = core::mem::size_of::(); +impl WriteToUser for bool { + fn write_to_user(&self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { + let write_len = core::mem::size_of::(); - if (max_len as usize) < write_len { - return_errno_with_message!(Errno::EINVAL, "max_len is too short"); + if (max_len as usize) < write_len { + return_errno_with_message!(Errno::EINVAL, "max_len is too short"); + } + + let val = if *self { 1i32 } else { 0i32 }; + vmar.write_val(addr, &val)?; + Ok(write_len) } - - let linger = Linger::from(*linger_option); - vmar.write_val(addr, &linger)?; - Ok(write_len) } -pub fn read_congestion(vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { - let mut bytes = vec![0; max_len as usize]; - vmar.read_bytes(addr, &mut bytes)?; - let name = String::from_utf8(bytes).unwrap(); - Congestion::new(&name) +impl WriteToUser for Option { + fn write_to_user(&self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { + let write_len = core::mem::size_of::(); + + if (max_len as usize) < write_len { + return_errno_with_message!(Errno::EINVAL, "max_len is too short"); + } + + let val = match self { + None => 0i32, + Some(error) => error.error() as i32, + }; + + vmar.write_val(addr, &val)?; + Ok(write_len) + } } -pub fn write_congestion( - congestion: &Congestion, - vmar: &Vmar, - addr: Vaddr, - max_len: u32, -) -> Result { - let name = congestion.name().as_bytes(); +impl ReadFromUser for LingerOption { + fn read_from_user(vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { + if (max_len as usize) < core::mem::size_of::() { + return_errno_with_message!(Errno::EINVAL, "max_len is too short"); + } - let write_len = name.len(); - if write_len > max_len as usize { - return_errno_with_message!(Errno::EINVAL, "max_len is too short"); + let c_linger = vmar.read_val::(addr)?; + + Ok(LingerOption::from(c_linger)) } +} - vmar.write_bytes(addr, name)?; +impl WriteToUser for LingerOption { + fn write_to_user(&self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { + let write_len = core::mem::size_of::(); - Ok(write_len) + if (max_len as usize) < write_len { + return_errno_with_message!(Errno::EINVAL, "max_len is too short"); + } + + let linger = CLinger::from(*self); + vmar.write_val(addr, &linger)?; + Ok(write_len) + } +} + +impl ReadFromUser for CongestionControl { + fn read_from_user(vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { + let mut bytes = vec![0; max_len as usize]; + vmar.read_bytes(addr, &mut bytes)?; + let name = String::from_utf8(bytes).unwrap(); + CongestionControl::new(&name) + } +} + +impl WriteToUser for CongestionControl { + fn write_to_user(&self, vmar: &Vmar, addr: Vaddr, max_len: u32) -> Result { + let name = self.name().as_bytes(); + + let write_len = name.len(); + if write_len > max_len as usize { + return_errno_with_message!(Errno::EINVAL, "max_len is too short"); + } + + vmar.write_bytes(addr, name)?; + + Ok(write_len) + } } #[repr(C)] #[derive(Debug, Clone, Copy, Pod)] -struct Linger { +struct CLinger { l_onoff: i32, // linger active l_linger: i32, // how many seconds to linger for } -impl From for Linger { +impl From for CLinger { fn from(value: LingerOption) -> Self { let l_onoff = if value.is_on() { 1 } else { 0 }; @@ -114,8 +177,8 @@ impl From for Linger { } } -impl From for LingerOption { - fn from(value: Linger) -> Self { +impl From for LingerOption { + fn from(value: CLinger) -> Self { let is_on = value.l_onoff != 0; let timeout = Duration::new(value.l_linger as _, 0); LingerOption::new(is_on, timeout)