From 9d06f60ecca7cbfd1064c099f8cdd968609b8707 Mon Sep 17 00:00:00 2001 From: Jianfeng Jiang Date: Tue, 13 Jun 2023 17:15:07 +0800 Subject: [PATCH] Add syscall getsockopt --- .../jinux-std/src/net/socket/ip/datagram.rs | 9 +--- .../jinux-std/src/net/socket/ip/stream/mod.rs | 5 -- services/libs/jinux-std/src/net/socket/mod.rs | 9 +++- .../src/net/socket/util/sock_options.rs | 15 ++++++ .../libs/jinux-std/src/syscall/getsockopt.rs | 46 +++++++++++++++++++ services/libs/jinux-std/src/syscall/mod.rs | 4 ++ .../libs/jinux-std/src/syscall/setsockopt.rs | 23 ++-------- 7 files changed, 77 insertions(+), 34 deletions(-) create mode 100644 services/libs/jinux-std/src/syscall/getsockopt.rs diff --git a/services/libs/jinux-std/src/net/socket/ip/datagram.rs b/services/libs/jinux-std/src/net/socket/ip/datagram.rs index 04a23ba1d..8382dd6e2 100644 --- a/services/libs/jinux-std/src/net/socket/ip/datagram.rs +++ b/services/libs/jinux-std/src/net/socket/ip/datagram.rs @@ -9,9 +9,7 @@ use crate::{ iface::{AnyBoundSocket, AnyUnboundSocket, RawUdpSocket}, poll_ifaces, socket::{ - util::{ - send_recv_flags::SendRecvFlags, sock_options::SockOptionName, sockaddr::SocketAddr, - }, + util::{send_recv_flags::SendRecvFlags, sockaddr::SocketAddr}, Socket, }, }, @@ -216,11 +214,6 @@ impl Socket for DatagramSocket { } } - fn set_sock_option(&self, optname: SockOptionName, option_val: &[u8]) -> Result<()> { - // FIXME: deal with sock options here - Ok(()) - } - // FIXME: respect RecvFromFlags fn recvfrom(&self, buf: &mut [u8], flags: SendRecvFlags) -> Result<(usize, SocketAddr)> { debug_assert!(flags.is_all_supported()); diff --git a/services/libs/jinux-std/src/net/socket/ip/stream/mod.rs b/services/libs/jinux-std/src/net/socket/ip/stream/mod.rs index 238bc5588..8b714eb9f 100644 --- a/services/libs/jinux-std/src/net/socket/ip/stream/mod.rs +++ b/services/libs/jinux-std/src/net/socket/ip/stream/mod.rs @@ -162,11 +162,6 @@ impl Socket for StreamSocket { return_errno_with_message!(Errno::EINVAL, "getsockopt not implemented"); } - fn set_sock_option(&self, optname: SockOptionName, option_val: &[u8]) -> Result<()> { - // TODO: implement setsockopt - Ok(()) - } - fn recvfrom(&self, buf: &mut [u8], flags: SendRecvFlags) -> Result<(usize, SocketAddr)> { let state = self.state.read(); let (recv_size, remote_endpoint) = match &*state { diff --git a/services/libs/jinux-std/src/net/socket/mod.rs b/services/libs/jinux-std/src/net/socket/mod.rs index 7cd1b036b..0924cb53c 100644 --- a/services/libs/jinux-std/src/net/socket/mod.rs +++ b/services/libs/jinux-std/src/net/socket/mod.rs @@ -2,7 +2,7 @@ use crate::{fs::file_handle::FileLike, prelude::*}; pub use self::util::send_recv_flags::SendRecvFlags; pub use self::util::shutdown_cmd::SockShutdownCmd; -pub use self::util::sock_options::SockOptionName; +pub use self::util::sock_options::{SockOptionLevel, SockOptionName}; pub use self::util::sockaddr::SocketAddr; pub mod ip; @@ -51,7 +51,12 @@ pub trait Socket: FileLike + Send + Sync { } /// Set options on the socket - fn set_sock_option(&self, optname: SockOptionName, option_val: &[u8]) -> Result<()> { + fn set_sock_option( + &self, + opt_level: SockOptionLevel, + optname: SockOptionName, + option_val: &[u8], + ) -> Result<()> { return_errno_with_message!(Errno::EINVAL, "setsockopt not implemented"); } diff --git a/services/libs/jinux-std/src/net/socket/util/sock_options.rs b/services/libs/jinux-std/src/net/socket/util/sock_options.rs index 3f2d79be7..0c75e1c2b 100644 --- a/services/libs/jinux-std/src/net/socket/util/sock_options.rs +++ b/services/libs/jinux-std/src/net/socket/util/sock_options.rs @@ -23,4 +23,19 @@ pub enum SockOptionName { SO_LINGER = 13, SO_BSDCOMPAT = 14, SO_REUSEPORT = 15, + SO_RCVTIMEO_NEW = 66, + SO_SNDTIMEO_NEW = 67, +} + +#[repr(i32)] +#[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq)] +#[allow(non_camel_case_types)] +/// Sock Opt level. The definition is from https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/socket.h#L343 +pub enum SockOptionLevel { + SOL_IP = 0, + SOL_SOCKET = 1, + SOL_TCP = 6, + SOL_UDP = 17, + SOL_IPV6 = 41, + SOL_RAW = 255, } diff --git a/services/libs/jinux-std/src/syscall/getsockopt.rs b/services/libs/jinux-std/src/syscall/getsockopt.rs new file mode 100644 index 000000000..e4a318128 --- /dev/null +++ b/services/libs/jinux-std/src/syscall/getsockopt.rs @@ -0,0 +1,46 @@ +use crate::{ + fs::file_table::FileDescripter, + log_syscall_entry, + net::socket::{SockOptionLevel, SockOptionName}, + prelude::*, + syscall::SYS_SETSOCKOPT, + util::{read_val_from_user, write_val_to_user}, +}; + +use super::SyscallReturn; + +pub fn sys_getsockopt( + sockfd: FileDescripter, + level: i32, + optname: i32, + optval: Vaddr, + optlen_addr: Vaddr, +) -> Result { + log_syscall_entry!(SYS_SETSOCKOPT); + let level = SockOptionLevel::try_from(level)?; + let sock_option_name = SockOptionName::try_from(optname)?; + 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 = {sock_option_name:?}, optlen = {optlen}" + ); + let current = current!(); + let file_table = current.file_table().lock(); + let socket = file_table + .get_file(sockfd)? + .as_socket() + .ok_or_else(|| Error::with_message(Errno::ENOTSOCK, "the file is not socket"))?; + + // FIXME: This is only a workaround. Writing zero means the socket does not have error. + // The linux manual says that writing a non-zero value if there are errors. But what value is it? + if sock_option_name == SockOptionName::SO_ERROR { + assert!(optlen == 4); + write_val_to_user(optval, &0i32)?; + } + + // TODO: do real getsockopt + + Ok(SyscallReturn::Return(0)) +} diff --git a/services/libs/jinux-std/src/syscall/mod.rs b/services/libs/jinux-std/src/syscall/mod.rs index 03c866034..50432aa3f 100644 --- a/services/libs/jinux-std/src/syscall/mod.rs +++ b/services/libs/jinux-std/src/syscall/mod.rs @@ -78,6 +78,7 @@ use self::execve::sys_execveat; use self::getpeername::sys_getpeername; use self::getrandom::sys_getrandom; use self::getsockname::sys_getsockname; +use self::getsockopt::sys_getsockopt; use self::listen::sys_listen; use self::pread64::sys_pread64; use self::recvfrom::sys_recvfrom; @@ -118,6 +119,7 @@ mod getpid; mod getppid; mod getrandom; mod getsockname; +mod getsockopt; mod gettid; mod gettimeofday; mod getuid; @@ -239,6 +241,7 @@ define_syscall_nums!( SYS_GETSOCKNAME = 51, SYS_GETPEERNAME = 52, SYS_SETSOCKOPT = 54, + SYS_GETSOCKOPT = 55, SYS_CLONE = 56, SYS_FORK = 57, SYS_EXECVE = 59, @@ -398,6 +401,7 @@ pub fn syscall_dispatch( SYS_GETSOCKNAME => syscall_handler!(3, sys_getsockname, args), SYS_GETPEERNAME => syscall_handler!(3, sys_getpeername, args), SYS_SETSOCKOPT => syscall_handler!(5, sys_setsockopt, args), + SYS_GETSOCKOPT => syscall_handler!(5, sys_getsockopt, args), SYS_CLONE => syscall_handler!(5, sys_clone, args, context.clone()), SYS_FORK => syscall_handler!(0, sys_fork, context.clone()), SYS_EXECVE => syscall_handler!(3, sys_execve, args, context), diff --git a/services/libs/jinux-std/src/syscall/setsockopt.rs b/services/libs/jinux-std/src/syscall/setsockopt.rs index 70773d661..b9bc864b3 100644 --- a/services/libs/jinux-std/src/syscall/setsockopt.rs +++ b/services/libs/jinux-std/src/syscall/setsockopt.rs @@ -1,5 +1,5 @@ use crate::log_syscall_entry; -use crate::net::socket::SockOptionName; +use crate::net::socket::{SockOptionLevel, SockOptionName}; use crate::util::read_bytes_from_user; use crate::{fs::file_table::FileDescripter, prelude::*}; @@ -15,9 +15,6 @@ pub fn sys_setsockopt( ) -> Result { log_syscall_entry!(SYS_SETSOCKOPT); let level = SockOptionLevel::try_from(level)?; - if level != SockOptionLevel::SOL_SOCKET { - return_errno_with_message!(Errno::ENOPROTOOPT, "Unsupported sockoption level"); - } let sock_option_name = SockOptionName::try_from(optname)?; if optval == 0 { return_errno_with_message!(Errno::EINVAL, "optval is null pointer"); @@ -25,25 +22,13 @@ pub fn sys_setsockopt( let mut sock_opt_val = vec![0u8; optlen]; read_bytes_from_user(optval, &mut sock_opt_val)?; - debug!("sockfd = {sockfd}, optname = {sock_option_name:?}, optval = {sock_opt_val:?}"); + debug!("level = {level:?}, sockfd = {sockfd}, optname = {sock_option_name:?}, optval = {sock_opt_val:?}"); 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", - ))?; - socket.set_sock_option(sock_option_name, &sock_opt_val)?; + .ok_or_else(|| Error::with_message(Errno::ENOTSOCK, "the file is not socket"))?; + // TODO: do setsockopt Ok(SyscallReturn::Return(0)) } - -#[repr(i32)] -#[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq)] -#[allow(non_camel_case_types)] -/// Sock Opt level -enum SockOptionLevel { - SOL_IP = 0, - SOL_SOCKET = 1, -}