Add syscall getsockopt

This commit is contained in:
Jianfeng Jiang
2023-06-13 17:15:07 +08:00
committed by Tate, Hongliang Tian
parent dcfbeb270d
commit 9d06f60ecc
7 changed files with 77 additions and 34 deletions

View File

@ -9,9 +9,7 @@ use crate::{
iface::{AnyBoundSocket, AnyUnboundSocket, RawUdpSocket}, iface::{AnyBoundSocket, AnyUnboundSocket, RawUdpSocket},
poll_ifaces, poll_ifaces,
socket::{ socket::{
util::{ util::{send_recv_flags::SendRecvFlags, sockaddr::SocketAddr},
send_recv_flags::SendRecvFlags, sock_options::SockOptionName, sockaddr::SocketAddr,
},
Socket, 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 // FIXME: respect RecvFromFlags
fn recvfrom(&self, buf: &mut [u8], flags: SendRecvFlags) -> Result<(usize, SocketAddr)> { fn recvfrom(&self, buf: &mut [u8], flags: SendRecvFlags) -> Result<(usize, SocketAddr)> {
debug_assert!(flags.is_all_supported()); debug_assert!(flags.is_all_supported());

View File

@ -162,11 +162,6 @@ impl Socket for StreamSocket {
return_errno_with_message!(Errno::EINVAL, "getsockopt not implemented"); 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)> { fn recvfrom(&self, buf: &mut [u8], flags: SendRecvFlags) -> Result<(usize, SocketAddr)> {
let state = self.state.read(); let state = self.state.read();
let (recv_size, remote_endpoint) = match &*state { let (recv_size, remote_endpoint) = match &*state {

View File

@ -2,7 +2,7 @@ use crate::{fs::file_handle::FileLike, prelude::*};
pub use self::util::send_recv_flags::SendRecvFlags; pub use self::util::send_recv_flags::SendRecvFlags;
pub use self::util::shutdown_cmd::SockShutdownCmd; 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 use self::util::sockaddr::SocketAddr;
pub mod ip; pub mod ip;
@ -51,7 +51,12 @@ pub trait Socket: FileLike + Send + Sync {
} }
/// Set options on the socket /// 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"); return_errno_with_message!(Errno::EINVAL, "setsockopt not implemented");
} }

View File

@ -23,4 +23,19 @@ pub enum SockOptionName {
SO_LINGER = 13, SO_LINGER = 13,
SO_BSDCOMPAT = 14, SO_BSDCOMPAT = 14,
SO_REUSEPORT = 15, 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,
} }

View File

@ -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<SyscallReturn> {
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))
}

View File

@ -78,6 +78,7 @@ use self::execve::sys_execveat;
use self::getpeername::sys_getpeername; use self::getpeername::sys_getpeername;
use self::getrandom::sys_getrandom; use self::getrandom::sys_getrandom;
use self::getsockname::sys_getsockname; use self::getsockname::sys_getsockname;
use self::getsockopt::sys_getsockopt;
use self::listen::sys_listen; use self::listen::sys_listen;
use self::pread64::sys_pread64; use self::pread64::sys_pread64;
use self::recvfrom::sys_recvfrom; use self::recvfrom::sys_recvfrom;
@ -118,6 +119,7 @@ mod getpid;
mod getppid; mod getppid;
mod getrandom; mod getrandom;
mod getsockname; mod getsockname;
mod getsockopt;
mod gettid; mod gettid;
mod gettimeofday; mod gettimeofday;
mod getuid; mod getuid;
@ -239,6 +241,7 @@ define_syscall_nums!(
SYS_GETSOCKNAME = 51, SYS_GETSOCKNAME = 51,
SYS_GETPEERNAME = 52, SYS_GETPEERNAME = 52,
SYS_SETSOCKOPT = 54, SYS_SETSOCKOPT = 54,
SYS_GETSOCKOPT = 55,
SYS_CLONE = 56, SYS_CLONE = 56,
SYS_FORK = 57, SYS_FORK = 57,
SYS_EXECVE = 59, SYS_EXECVE = 59,
@ -398,6 +401,7 @@ pub fn syscall_dispatch(
SYS_GETSOCKNAME => syscall_handler!(3, sys_getsockname, args), SYS_GETSOCKNAME => syscall_handler!(3, sys_getsockname, args),
SYS_GETPEERNAME => syscall_handler!(3, sys_getpeername, args), SYS_GETPEERNAME => syscall_handler!(3, sys_getpeername, args),
SYS_SETSOCKOPT => syscall_handler!(5, sys_setsockopt, 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_CLONE => syscall_handler!(5, sys_clone, args, context.clone()),
SYS_FORK => syscall_handler!(0, sys_fork, context.clone()), SYS_FORK => syscall_handler!(0, sys_fork, context.clone()),
SYS_EXECVE => syscall_handler!(3, sys_execve, args, context), SYS_EXECVE => syscall_handler!(3, sys_execve, args, context),

View File

@ -1,5 +1,5 @@
use crate::log_syscall_entry; 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::util::read_bytes_from_user;
use crate::{fs::file_table::FileDescripter, prelude::*}; use crate::{fs::file_table::FileDescripter, prelude::*};
@ -15,9 +15,6 @@ pub fn sys_setsockopt(
) -> Result<SyscallReturn> { ) -> Result<SyscallReturn> {
log_syscall_entry!(SYS_SETSOCKOPT); log_syscall_entry!(SYS_SETSOCKOPT);
let level = SockOptionLevel::try_from(level)?; 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)?; let sock_option_name = SockOptionName::try_from(optname)?;
if optval == 0 { if optval == 0 {
return_errno_with_message!(Errno::EINVAL, "optval is null pointer"); 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]; let mut sock_opt_val = vec![0u8; optlen];
read_bytes_from_user(optval, &mut sock_opt_val)?; 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 current = current!();
let file_table = current.file_table().lock(); let file_table = current.file_table().lock();
let socket = file_table let socket = file_table
.get_file(sockfd)? .get_file(sockfd)?
.as_socket() .as_socket()
.ok_or(Error::with_message( .ok_or_else(|| Error::with_message(Errno::ENOTSOCK, "the file is not socket"))?;
Errno::ENOTSOCK, // TODO: do setsockopt
"the file is not socket",
))?;
socket.set_sock_option(sock_option_name, &sock_opt_val)?;
Ok(SyscallReturn::Return(0)) 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,
}