mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-16 08:46:48 +00:00
Refactor sock option implementations
This commit is contained in:
parent
782cd05ade
commit
f8eca84a99
6
Makefile
6
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
|
@ -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<Self>) -> Option<Arc<dyn Socket>> {
|
||||
None
|
||||
}
|
||||
|
||||
|
@ -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<Arc<dyn Socket>> {
|
||||
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"))
|
||||
}
|
||||
|
@ -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<Self>) -> Option<Arc<dyn Socket>> {
|
||||
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(())
|
||||
|
@ -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;
|
||||
|
@ -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>,
|
||||
options: RwLock<OptionSet>,
|
||||
state: RwLock<State>,
|
||||
}
|
||||
|
||||
@ -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<Self>) -> Option<Arc<dyn Socket>> {
|
||||
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);
|
||||
|
@ -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<Self> {
|
||||
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<input = bool, output = bool> {}
|
||||
pub struct TcpCongestion<input = Congestion, output = Congestion> {}
|
||||
pub struct TcpMaxseg<input = u32, output = u32> {}
|
||||
pub struct TcpWindowClamp<input = u32, output = u32> {}
|
||||
impl_socket_options!(
|
||||
pub struct NoDelay(bool);
|
||||
pub struct Congestion(CongestionControl);
|
||||
pub struct MaxSegment(u32);
|
||||
pub struct WindowClamp(u32);
|
||||
);
|
||||
|
59
services/libs/aster-std/src/net/socket/ip/stream/util.rs
Normal file
59
services/libs/aster-std/src/net/socket/ip/stream/util.rs
Normal file
@ -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<Self> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
|
||||
|
83
services/libs/aster-std/src/net/socket/options/macros.rs
Normal file
83
services/libs/aster-std/src/net/socket/options/macros.rs
Normal file
@ -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
|
||||
}
|
||||
}};
|
||||
}
|
@ -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 <input=$input:ty, output=$output:ty> {}
|
||||
)*) => {
|
||||
$(
|
||||
$(#[$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<crate::error::Error>);
|
||||
pub struct Linger(LingerOption);
|
||||
);
|
||||
|
@ -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<input = bool, output = bool> {}
|
||||
pub struct SocketReusePort<input = bool, output = bool> {}
|
||||
pub struct SocketSendBuf<input = u32, output = u32> {}
|
||||
pub struct SocketRecvBuf<input = u32, output = u32> {}
|
||||
pub struct SocketError<input = (), output = SockErrors> {}
|
||||
pub struct SocketLinger<input = LingerOption, output = LingerOption> {}
|
||||
);
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SockErrors(Option<Error>);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
@ -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)]
|
||||
|
@ -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<Self>) -> Option<Arc<dyn Socket>> {
|
||||
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)
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod options;
|
||||
pub mod send_recv_flags;
|
||||
pub mod shutdown_cmd;
|
||||
pub mod sockaddr;
|
||||
pub mod socket_addr;
|
||||
|
53
services/libs/aster-std/src/net/socket/util/options.rs
Normal file
53
services/libs/aster-std/src/net/socket/util/options.rs
Normal file
@ -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<Error>,
|
||||
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
|
||||
}
|
||||
}
|
@ -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<SyscallReturn> {
|
||||
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 _))
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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<SyscallReturn> {
|
||||
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))
|
||||
}
|
||||
|
@ -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<SyscallReturn> {
|
||||
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))
|
||||
|
@ -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<SyscallReturn> {
|
||||
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))?;
|
||||
|
@ -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<SyscallReturn> {
|
||||
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))
|
||||
}
|
||||
|
@ -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])?;
|
||||
|
@ -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 _))
|
||||
}
|
||||
|
@ -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<SyscallReturn> {
|
||||
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
|
||||
};
|
||||
|
@ -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<SyscallReturn> {
|
||||
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))
|
||||
}
|
||||
|
@ -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<SyscallReturn> {
|
||||
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<SyscallRetur
|
||||
);
|
||||
let nonblocking = sock_flags.contains(SockFlags::SOCK_NONBLOCK);
|
||||
let file_like = match (domain, sock_type, protocol) {
|
||||
(SaFamily::AF_UNIX, SockType::SOCK_STREAM, _) => Arc::new(UnixStreamSocket::new(
|
||||
(CSocketAddrFamily::AF_UNIX, SockType::SOCK_STREAM, _) => Arc::new(UnixStreamSocket::new(
|
||||
sock_flags.contains(SockFlags::SOCK_NONBLOCK),
|
||||
)) as Arc<dyn FileLike>,
|
||||
(
|
||||
SaFamily::AF_INET,
|
||||
CSocketAddrFamily::AF_INET,
|
||||
SockType::SOCK_STREAM,
|
||||
Protocol::IPPROTO_IP | Protocol::IPPROTO_TCP,
|
||||
) => Arc::new(StreamSocket::new(nonblocking)) as Arc<dyn FileLike>,
|
||||
(SaFamily::AF_INET, SockType::SOCK_DGRAM, Protocol::IPPROTO_IP | Protocol::IPPROTO_UDP) => {
|
||||
Arc::new(DatagramSocket::new(nonblocking)) as Arc<dyn FileLike>
|
||||
}
|
||||
(
|
||||
CSocketAddrFamily::AF_INET,
|
||||
SockType::SOCK_DGRAM,
|
||||
Protocol::IPPROTO_IP | Protocol::IPPROTO_UDP,
|
||||
) => Arc::new(DatagramSocket::new(nonblocking)) as Arc<dyn FileLike>,
|
||||
_ => return_errno_with_message!(Errno::EAFNOSUPPORT, "unsupported domain"),
|
||||
};
|
||||
let fd = {
|
||||
|
@ -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<SyscallReturn> {
|
||||
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"
|
||||
|
@ -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<SocketAddr> {
|
||||
debug_assert!(addr_len >= core::mem::size_of::<SockAddr>());
|
||||
let sockaddr: SockAddr = read_val_from_user(addr)?;
|
||||
debug_assert!(addr_len >= core::mem::size_of::<CSocketAddr>());
|
||||
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::<SockAddr>());
|
||||
CSocketAddrFamily::AF_UNIX => {
|
||||
debug_assert!(addr_len >= core::mem::size_of::<CSocketAddr>());
|
||||
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::<u16>();
|
||||
@ -37,14 +37,14 @@ pub fn read_socket_addr_from_user(addr: Vaddr, addr_len: usize) -> Result<Socket
|
||||
|
||||
SocketAddr::Unix(unix_socket_addr)
|
||||
}
|
||||
SaFamily::AF_INET => {
|
||||
debug_assert!(addr_len >= core::mem::size_of::<SockAddrInet>());
|
||||
let sock_addr_in: SockAddrInet = read_val_from_user(addr)?;
|
||||
CSocketAddrFamily::AF_INET => {
|
||||
debug_assert!(addr_len >= core::mem::size_of::<CSocketAddrInet>());
|
||||
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::<SockAddrInet6>());
|
||||
let sock_addr_in6: SockAddrInet6 = read_val_from_user(addr)?;
|
||||
CSocketAddrFamily::AF_INET6 => {
|
||||
debug_assert!(addr_len >= core::mem::size_of::<CSocketAddrInet6>());
|
||||
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::<i32>(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::<SockAddrUnix>();
|
||||
let sock_addr_unix = CSocketAddrUnix::try_from(path)?;
|
||||
let write_size = core::mem::size_of::<CSocketAddrUnix>();
|
||||
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::<SockAddrInet>();
|
||||
let in_addr = CInetAddr::from(*addr);
|
||||
let sock_addr_in = CSocketAddrInet::new(*port, in_addr);
|
||||
let write_size = core::mem::size_of::<CSocketAddrInet>();
|
||||
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<SaFamily> {
|
||||
Ok(SaFamily::try_from(self.sa_family as i32)?)
|
||||
impl CSocketAddr {
|
||||
pub fn sa_family(&self) -> Result<CSocketAddrFamily> {
|
||||
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<InetAddr> for Ipv4Address {
|
||||
fn from(value: InetAddr) -> Self {
|
||||
impl From<CInetAddr> for Ipv4Address {
|
||||
fn from(value: CInetAddr) -> Self {
|
||||
let addr = value.as_bytes();
|
||||
Ipv4Address::from_bytes(addr)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Ipv4Address> for InetAddr {
|
||||
impl From<Ipv4Address> for CInetAddr {
|
||||
fn from(value: Ipv4Address) -> Self {
|
||||
let bytes = value.as_bytes();
|
||||
InetAddr::from_bytes(bytes)
|
||||
CInetAddr::from_bytes(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SockAddrInet> for SocketAddr {
|
||||
fn from(value: SockAddrInet) -> Self {
|
||||
impl From<CSocketAddrInet> 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<Self> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
@ -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<Arc<dyn Socket>> {
|
||||
let current = current!();
|
||||
let file_table = current.file_table().lock();
|
||||
file_table.get_socket(sockfd)
|
||||
}
|
||||
|
@ -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<Full>, addr: Vaddr, max_len: u32) -> Result<()>;
|
||||
pub trait RawSocketOption: SocketOption {
|
||||
fn read_from_user(&mut self, vmar: &Vmar<Full>, addr: Vaddr, max_len: u32) -> Result<()>;
|
||||
|
||||
fn write_output(&self, vmar: &Vmar<Full>, addr: Vaddr, max_len: u32) -> Result<usize>;
|
||||
fn write_to_user(&self, vmar: &Vmar<Full>, addr: Vaddr, max_len: u32) -> Result<usize>;
|
||||
|
||||
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<Full>, 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<Full>,
|
||||
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<Full>, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
use aster_frame::vm::VmIo;
|
||||
fn write_to_user(&self, vmar: &Vmar<Full>, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
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<Full>, addr: Vaddr, max_len: u32) -> Result<()> {
|
||||
let input = $reader(vmar, addr, max_len)?;
|
||||
self.set_input(input);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_output(&self, vmar: &Vmar<Full>, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
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<Full>,
|
||||
_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<Full>, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
use jinux_frame::vm::VmIo;
|
||||
fn write_to_user(&self, vmar: &Vmar<Full>, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
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<Full>,
|
||||
_addr: Vaddr,
|
||||
_max_len: u32,
|
||||
) -> Result<()> {
|
||||
return_errno_with_message!(Errno::ENOPROTOOPT, "the option is getter-only");
|
||||
}
|
||||
|
||||
fn write_output(&self, vmar: &Vmar<Full>, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
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<Box<dyn RawSockOption>> {
|
||||
pub fn new_raw_socket_option(
|
||||
level: CSocketOptionLevel,
|
||||
name: i32,
|
||||
) -> Result<Box<dyn RawSocketOption>> {
|
||||
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<Box<dy
|
||||
#[repr(i32)]
|
||||
#[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum SockOptionLevel {
|
||||
pub enum CSocketOptionLevel {
|
||||
SOL_IP = 0,
|
||||
SOL_SOCKET = 1,
|
||||
SOL_TCP = 6,
|
||||
|
@ -1,15 +1,12 @@
|
||||
use super::RawSocketOption;
|
||||
use crate::net::socket::options::{
|
||||
SockOption, SocketError, SocketLinger, SocketRecvBuf, SocketReuseAddr, SocketReusePort,
|
||||
SocketSendBuf,
|
||||
Error, Linger, RecvBuf, ReuseAddr, ReusePort, SendBuf, SocketOption,
|
||||
};
|
||||
use crate::prelude::*;
|
||||
use crate::vm::vmar::Vmar;
|
||||
use crate::{impl_raw_sock_option, impl_raw_sock_option_get_only};
|
||||
use crate::{impl_raw_sock_option_get_only, impl_raw_socket_option};
|
||||
use aster_rights::Full;
|
||||
|
||||
use super::utils::{read_bool, read_linger, write_bool, write_errors, write_linger};
|
||||
use super::RawSockOption;
|
||||
|
||||
/// Socket level options.
|
||||
///
|
||||
/// The definition is from https://elixir.bootlin.com/linux/v6.0.9/source/include/uapi/asm-generic/socket.h.
|
||||
@ -17,7 +14,7 @@ use super::RawSockOption;
|
||||
#[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
enum SocketOptionName {
|
||||
enum CSocketOptionName {
|
||||
DEBUG = 1,
|
||||
REUSEADDR = 2,
|
||||
TYPE = 3,
|
||||
@ -39,22 +36,22 @@ enum SocketOptionName {
|
||||
SNDTIMEO_NEW = 67,
|
||||
}
|
||||
|
||||
pub fn new_socket_option(name: i32) -> Result<Box<dyn RawSockOption>> {
|
||||
let name = SocketOptionName::try_from(name)?;
|
||||
pub fn new_socket_option(name: i32) -> Result<Box<dyn RawSocketOption>> {
|
||||
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);
|
||||
|
@ -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<Box<dyn RawSockOption>> {
|
||||
let name = TcpOptionName::try_from(name)?;
|
||||
pub fn new_tcp_option(name: i32) -> Result<Box<dyn RawSocketOption>> {
|
||||
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);
|
||||
|
@ -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<Full>, addr: Vaddr, max_len: u32) -> Result<bool> {
|
||||
if (max_len as usize) < core::mem::size_of::<i32>() {
|
||||
return_errno_with_message!(Errno::EINVAL, "max_len is too short");
|
||||
}
|
||||
|
||||
let val = vmar.read_val::<i32>(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<Full>, addr: Vaddr, max_len: u32) -> Result<Self>;
|
||||
}
|
||||
|
||||
pub fn write_bool(val: &bool, vmar: &Vmar<Full>, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
let write_len = core::mem::size_of::<i32>();
|
||||
|
||||
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<Full>, addr: Vaddr, max_len: u32) -> Result<usize>;
|
||||
}
|
||||
|
||||
pub fn write_errors(
|
||||
errors: &SockErrors,
|
||||
vmar: &Vmar<Full>,
|
||||
addr: Vaddr,
|
||||
max_len: u32,
|
||||
) -> Result<usize> {
|
||||
let write_len = core::mem::size_of::<i32>();
|
||||
/// 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 <T: Pod> 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<Full>, addr: Vaddr, max_len: u32) -> Result<Self> {
|
||||
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<Full>, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
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<Full>, addr: Vaddr, max_len: u32) -> Result<LingerOption> {
|
||||
if (max_len as usize) < core::mem::size_of::<Linger>() {
|
||||
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<Full>, addr: Vaddr, max_len: u32) -> Result<Self> {
|
||||
if (max_len as usize) < core::mem::size_of::<i32>() {
|
||||
return_errno_with_message!(Errno::EINVAL, "max_len is too short");
|
||||
}
|
||||
|
||||
let val = vmar.read_val::<i32>(addr)?;
|
||||
|
||||
Ok(val != 0)
|
||||
}
|
||||
|
||||
let linger = vmar.read_val::<Linger>(addr)?;
|
||||
|
||||
Ok(LingerOption::from(linger))
|
||||
}
|
||||
|
||||
pub fn write_linger(
|
||||
linger_option: &LingerOption,
|
||||
vmar: &Vmar<Full>,
|
||||
addr: Vaddr,
|
||||
max_len: u32,
|
||||
) -> Result<usize> {
|
||||
let write_len = core::mem::size_of::<Linger>();
|
||||
impl WriteToUser for bool {
|
||||
fn write_to_user(&self, vmar: &Vmar<Full>, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
let write_len = core::mem::size_of::<i32>();
|
||||
|
||||
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<Full>, addr: Vaddr, max_len: u32) -> Result<Congestion> {
|
||||
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<Error> {
|
||||
fn write_to_user(&self, vmar: &Vmar<Full>, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
let write_len = core::mem::size_of::<i32>();
|
||||
|
||||
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<Full>,
|
||||
addr: Vaddr,
|
||||
max_len: u32,
|
||||
) -> Result<usize> {
|
||||
let name = congestion.name().as_bytes();
|
||||
impl ReadFromUser for LingerOption {
|
||||
fn read_from_user(vmar: &Vmar<Full>, addr: Vaddr, max_len: u32) -> Result<Self> {
|
||||
if (max_len as usize) < core::mem::size_of::<CLinger>() {
|
||||
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::<CLinger>(addr)?;
|
||||
|
||||
Ok(LingerOption::from(c_linger))
|
||||
}
|
||||
}
|
||||
|
||||
vmar.write_bytes(addr, name)?;
|
||||
impl WriteToUser for LingerOption {
|
||||
fn write_to_user(&self, vmar: &Vmar<Full>, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
let write_len = core::mem::size_of::<CLinger>();
|
||||
|
||||
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<Full>, addr: Vaddr, max_len: u32) -> Result<Self> {
|
||||
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<Full>, addr: Vaddr, max_len: u32) -> Result<usize> {
|
||||
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<LingerOption> for Linger {
|
||||
impl From<LingerOption> for CLinger {
|
||||
fn from(value: LingerOption) -> Self {
|
||||
let l_onoff = if value.is_on() { 1 } else { 0 };
|
||||
|
||||
@ -114,8 +177,8 @@ impl From<LingerOption> for Linger {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Linger> for LingerOption {
|
||||
fn from(value: Linger) -> Self {
|
||||
impl From<CLinger> 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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user