Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions os/StarryOS/kernel/src/syscall/net/opt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,27 +89,45 @@ macro_rules! call_dispatch {

call_dispatch! {
$dispatch, $pat,
// ---- Implemented socket options ----
(SOL_SOCKET, SO_REUSEADDR) => ReuseAddress as IntBool,
(SOL_SOCKET, SO_ERROR) => Error,
(SOL_SOCKET, SO_DONTROUTE) => DontRoute as IntBool,
(SOL_SOCKET, SO_SNDBUF) => SendBuffer as Int<usize>,
(SOL_SOCKET, SO_RCVBUF) => ReceiveBuffer as Int<usize>,
(SOL_SOCKET, SO_DONTROUTE) => DontRoute as IntBool, // stored but routing logic ignores it
(SOL_SOCKET, SO_SNDBUF) => SendBuffer as Int<usize>, // TODO: set is no-op, smoltcp uses fixed buffer
(SOL_SOCKET, SO_RCVBUF) => ReceiveBuffer as Int<usize>,// TODO: set is no-op, smoltcp uses fixed buffer
(SOL_SOCKET, SO_KEEPALIVE) => KeepAlive as IntBool,
(SOL_SOCKET, SO_RCVTIMEO) => ReceiveTimeout as Duration,
(SOL_SOCKET, SO_SNDTIMEO) => SendTimeout as Duration,
(SOL_SOCKET, SO_PASSCRED) => PassCredentials as IntBool,
(SOL_SOCKET, SO_PASSCRED) => PassCredentials as IntBool, // TODO: set accepted but no-op for non-unix
(SOL_SOCKET, SO_PEERCRED) => PeerCredentials as Ucred,
(SOL_SOCKET, SO_TYPE) => SocketType as Int<i32>, // read-only
(SOL_SOCKET, SO_PROTOCOL) => SocketProtocol as Int<i32>,// read-only
(SOL_SOCKET, SO_DOMAIN) => SocketDomain as Int<i32>, // read-only

(PROTO_TCP, TCP_NODELAY) => NoDelay as IntBool,
(PROTO_TCP, TCP_MAXSEG) => MaxSegment as Int<usize>,
(PROTO_TCP, TCP_MAXSEG) => MaxSegment as Int<usize>, // TODO: hardcoded 1460, get actual MSS
(PROTO_TCP, TCP_KEEPIDLE) => TcpKeepIdle as Int<u32>,
(PROTO_TCP, TCP_KEEPINTVL) => TcpKeepInterval as Int<u32>,
(PROTO_TCP, TCP_KEEPCNT) => TcpKeepCount as Int<u32>,
(PROTO_TCP, TCP_USER_TIMEOUT) => TcpUserTimeout as Int<u32>,
(PROTO_TCP, TCP_INFO) => TcpInfo,
(PROTO_TCP, TCP_INFO) => TcpInfo, // TODO: stub, returns empty struct

(PROTO_IP, IP_TTL) => Ttl as Int<u8>,
(PROTO_IP, IP_RECVERR) => RecvErr as IntBool,
(PROTO_IP, IP_RECVERR) => RecvErr as IntBool, // TODO: hardcoded false, no errqueue support
// ---- Not yet implemented (add as needed) ----
// (SOL_SOCKET, SO_LINGER) => ..., // TODO: needs close() linger semantics
// (SOL_SOCKET, SO_REUSEPORT) => ..., // TODO: needs kernel support
// (SOL_SOCKET, SO_PRIORITY) => ..., // TODO: needs kernel support
// (SOL_SOCKET, SO_RCVLOWAT) => ..., // TODO: needs kernel support
// (SOL_SOCKET, SO_SNDLOWAT) => ..., // TODO: needs kernel support
// (PROTO_TCP, TCP_CORK) => ..., // TODO: needs smoltcp support
// (PROTO_TCP, TCP_DEFER_ACCEPT) => ..., // TODO: needs kernel support
// (PROTO_TCP, TCP_QUICKACK) => ..., // TODO: needs kernel support
// (PROTO_TCP, TCP_SYNCNT) => ..., // TODO: needs kernel support
// (PROTO_TCP, TCP_WINDOW_CLAMP) => ..., // TODO: needs kernel support
// (PROTO_IP, IP_TOS) => ..., // TODO: needs kernel support
// (PROTO_IP, IP_OPTIONS) => ..., // TODO: needs kernel support
// (IPPROTO_IPV6, IPV6_V6ONLY) => ..., // TODO: currently hardcoded inline
}
}};
($dispatch:ident, $in:expr, $($pat:pat => $which:ident $(as $conv:ty)?),* $(,)?) => {
Expand Down
39 changes: 31 additions & 8 deletions os/arceos/modules/axnet-ng/src/general.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use core::{
sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering},
sync::atomic::{AtomicBool, AtomicI32, AtomicU32, AtomicU64, Ordering},
task::Waker,
time::Duration,
};

use ax_errno::AxResult;
use ax_errno::{AxError, AxResult, LinuxError};
use ax_task::future::{block_on, poll_io, timeout};
use axpoll::{IoEvents, Pollable};

Expand All @@ -24,14 +24,20 @@ pub(crate) struct GeneralOptions {
recv_timeout_nanos: AtomicU64,

device_mask: AtomicU32,
}
impl Default for GeneralOptions {
fn default() -> Self {
Self::new()
}

/// Socket type: SOCK_STREAM (1), SOCK_DGRAM (2), SOCK_RAW (3).
socket_type: AtomicI32,
/// Socket domain: AF_INET (2), AF_UNIX (1), AF_VSOCK (40).
domain: i32,
/// IP protocol: IPPROTO_TCP (6), IPPROTO_UDP (17), IPPROTO_ICMP (1), etc.
protocol: i32,
}
impl GeneralOptions {
pub fn new() -> Self {
/// Create new GeneralOptions. `socket_type` is the SOCK_* constant
/// (e.g. SOCK_STREAM=1, SOCK_DGRAM=2, SOCK_RAW=3).
/// `domain` is the AF_* constant (e.g. AF_INET=2, AF_UNIX=1, AF_VSOCK=40).
/// `protocol` is the IPPROTO_* constant (e.g. IPPROTO_TCP=6, IPPROTO_UDP=17, IPPROTO_ICMP=1).
pub fn new(socket_type: i32, domain: i32, protocol: i32) -> Self {
Self {
nonblock: AtomicBool::new(false),
reuse_address: AtomicBool::new(false),
Expand All @@ -40,6 +46,10 @@ impl GeneralOptions {
recv_timeout_nanos: AtomicU64::new(0),

device_mask: AtomicU32::new(0),

socket_type: AtomicI32::new(socket_type),
domain,
protocol,
}
}

Expand Down Expand Up @@ -152,6 +162,15 @@ impl Configurable for GeneralOptions {
O::RecvErr(val) => {
**val = false;
}
O::SocketType(t) => {
**t = self.socket_type.load(Ordering::Relaxed);
}
O::SocketProtocol(proto) => {
**proto = self.protocol;
}
O::SocketDomain(domain) => {
**domain = self.domain;
}
_ => return Ok(false),
}
Ok(true)
Expand Down Expand Up @@ -181,6 +200,10 @@ impl Configurable for GeneralOptions {
O::RecvErr(_) => {
// TODO: Retrieve ICMP errors via errqueue
}
O::SocketType(_) | O::SocketProtocol(_) | O::SocketDomain(_) => {
// Read-only options
return Err(AxError::from(LinuxError::ENOPROTOOPT));
}
_ => return Ok(false),
}
Ok(true)
Expand Down
3 changes: 3 additions & 0 deletions os/arceos/modules/axnet-ng/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ define_options! {
SendBufferForce(usize),
PassCredentials(bool),
PeerCredentials(UnixCredentials),
SocketType(i32),
SocketProtocol(i32),
SocketDomain(i32),

// --- TCP level options (TCP_*) ----
NoDelay(bool),
Expand Down
2 changes: 1 addition & 1 deletion os/arceos/modules/axnet-ng/src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl RawSocket {
/// Creates a raw socket for the given IP version and protocol.
pub fn new(ip_version: IpVersion, ip_protocol: IpProtocol) -> Self {
let handle = SOCKET_SET.add(new_raw_socket(ip_version, ip_protocol));
let general = GeneralOptions::new();
let general = GeneralOptions::new(3, 2, u8::from(ip_protocol) as i32); // SOCK_RAW
general.set_device_mask(u32::MAX);
Self {
handle,
Expand Down
4 changes: 2 additions & 2 deletions os/arceos/modules/axnet-ng/src/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl TcpSocket {
peer_endpoint: Mutex::new(None),
bound_registered: AtomicBool::new(false),

general: GeneralOptions::new(),
general: GeneralOptions::new(1, 2, 6), // SOCK_STREAM
pending_error: AtomicI32::new(0),
keep_idle_secs: AtomicU32::new(TCP_KEEPIDLE_DEFAULT_SECS),
keep_interval_secs: AtomicU32::new(TCP_KEEPINTVL_DEFAULT_SECS),
Expand All @@ -98,7 +98,7 @@ impl TcpSocket {
peer_endpoint: Mutex::new(Some(remote_endpoint)),
bound_registered: AtomicBool::new(false),

general: GeneralOptions::new(),
general: GeneralOptions::new(1, 2, 6), // SOCK_STREAM
pending_error: AtomicI32::new(0),
keep_idle_secs: AtomicU32::new(TCP_KEEPIDLE_DEFAULT_SECS),
keep_interval_secs: AtomicU32::new(TCP_KEEPINTVL_DEFAULT_SECS),
Expand Down
2 changes: 1 addition & 1 deletion os/arceos/modules/axnet-ng/src/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl UdpSocket {
local_addr: RwLock::new(None),
peer_addr: RwLock::new(None),

general: GeneralOptions::new(),
general: GeneralOptions::new(2, 2, 17), // SOCK_DGRAM
cork: Mutex::new(None),
}
}
Expand Down
4 changes: 2 additions & 2 deletions os/arceos/modules/axnet-ng/src/unix/dgram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl DgramTransport {
connected: RwLock::new(None),
local_addr: RwLock::new(UnixSocketAddr::Unnamed),
poll_state: Arc::default(),
general: GeneralOptions::default(),
general: GeneralOptions::new(2, 1, 0), // SOCK_DGRAM
pid,
}
}
Expand All @@ -73,7 +73,7 @@ impl DgramTransport {
connected: RwLock::new(Some(connected)),
local_addr: RwLock::new(UnixSocketAddr::Unnamed),
poll_state: Arc::default(),
general: GeneralOptions::default(),
general: GeneralOptions::new(2, 1, 0), // SOCK_DGRAM
pid,
}
}
Expand Down
2 changes: 1 addition & 1 deletion os/arceos/modules/axnet-ng/src/unix/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ impl StreamTransport {
channel: Mutex::new(channel),
conn_rx: Mutex::new(None),
poll_state: PollSet::new(),
general: GeneralOptions::default(),
general: GeneralOptions::new(1, 1, 0), // SOCK_STREAM
pid,
rx_closed: AtomicBool::new(false),
tx_closed: AtomicBool::new(false),
Expand Down
4 changes: 2 additions & 2 deletions os/arceos/modules/axnet-ng/src/vsock/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl VsockStreamTransport {
conn_id: Mutex::new(None),
connection: Mutex::new(None),
state: StateLock::new(State::Idle),
general: GeneralOptions::new(),
general: GeneralOptions::new(1, 40, 0), // SOCK_STREAM
}
}

Expand Down Expand Up @@ -122,7 +122,7 @@ impl VsockTransportOps for VsockStreamTransport {
conn_id: Mutex::new(Some(conn_id)),
connection: Mutex::new(Some(conn)),
state: StateLock::new(State::Connected),
general: GeneralOptions::default(),
general: GeneralOptions::new(1, 40, 0), // SOCK_STREAM
};

Ok((VsockTransport::Stream(new_transport), peer_addr))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.20)
project(test-sockopt C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
add_executable(test-sockopt src/main.c)
target_include_directories(test-sockopt PRIVATE src)
target_compile_options(test-sockopt PRIVATE -Wall -Wextra -Werror)
install(TARGETS test-sockopt RUNTIME DESTINATION usr/bin)
153 changes: 153 additions & 0 deletions test-suit/starryos/normal/qemu-smp1/test-sockopt/c/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* test-sockopt — getsockopt / setsockopt 控制面系统调用测试
*
* 覆盖 SO_TYPE / SO_PROTOCOL / SO_DOMAIN 三个只读 socket option。
* 依据: Linux man-pages 7 socket(7) getsockopt(2)。
*
* =====================================================================
* 手册摘要 (man 7 socket, man 2 getsockopt)
* =====================================================================
*
* ── SO_TYPE ───────────────────────────────────────────────────────────
* int type;
* getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len);
*
* 返回 socket 创建时的类型参数 (SOCK_STREAM=1, SOCK_DGRAM=2, SOCK_RAW=3)。
* 只读; setsockopt 返回 ENOPROTOOPT。
*
* ── SO_PROTOCOL ──────────────────────────────────────────────────────
* int proto;
* getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &proto, &len);
*
* 返回 socket 创建时的协议号 (IPPROTO_TCP=6, IPPROTO_UDP=17, 等)。
* 只读; setsockopt 返回 ENOPROTOOPT。
* Linux 3.13+ 可用。
*
* ── SO_DOMAIN ────────────────────────────────────────────────────────
* int domain;
* getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &domain, &len);
*
* 返回 socket 创建时的地址族 (AF_INET=2, AF_UNIX=1, AF_VSOCK=40, 等)。
* 只读; setsockopt 返回 ENOPROTOOPT。
* Linux 3.13+ 可用。
*/

#include "test_framework.h"

#include <errno.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

/* ---- SO_TYPE (3) ---- */

static void test_so_type(void) {
TEST_START("SO_TYPE");

int fd_tcp = socket(AF_INET, SOCK_STREAM, 0);
int fd_udp = socket(AF_INET, SOCK_DGRAM, 0);
CHECK(fd_tcp >= 0, "socket(TCP)");
CHECK(fd_udp >= 0, "socket(UDP)");

/* TCP: SO_TYPE == SOCK_STREAM (1) */
int type = -1;
socklen_t len = sizeof(type);
CHECK_RET(getsockopt(fd_tcp, SOL_SOCKET, SO_TYPE, &type, &len), 0,
"getsockopt(SO_TYPE) on TCP");
CHECK(type == SOCK_STREAM, "TCP: SO_TYPE == SOCK_STREAM (1)");

/* UDP: SO_TYPE == SOCK_DGRAM (2) */
type = -1;
len = sizeof(type);
CHECK_RET(getsockopt(fd_udp, SOL_SOCKET, SO_TYPE, &type, &len), 0,
"getsockopt(SO_TYPE) on UDP");
CHECK(type == SOCK_DGRAM, "UDP: SO_TYPE == SOCK_DGRAM (2)");

/* 只读: setsockopt 必须拒绝 */
int val = 1;
CHECK_ERR(setsockopt(fd_tcp, SOL_SOCKET, SO_TYPE, &val, sizeof(val)),
ENOPROTOOPT, "setsockopt(SO_TYPE) returns ENOPROTOOPT");

close(fd_tcp);
close(fd_udp);
}

/* ---- SO_PROTOCOL (3) ---- */

static void test_so_protocol(void) {
TEST_START("SO_PROTOCOL");

int fd_tcp = socket(AF_INET, SOCK_STREAM, 0);
int fd_udp = socket(AF_INET, SOCK_DGRAM, 0);
CHECK(fd_tcp >= 0, "socket(TCP)");
CHECK(fd_udp >= 0, "socket(UDP)");

/* TCP: SO_PROTOCOL == IPPROTO_TCP (6) */
int proto = -1;
socklen_t len = sizeof(proto);
CHECK_RET(getsockopt(fd_tcp, SOL_SOCKET, SO_PROTOCOL, &proto, &len), 0,
"getsockopt(SO_PROTOCOL) on TCP");
CHECK(proto == 6, "TCP: SO_PROTOCOL == IPPROTO_TCP (6)");

/* UDP: SO_PROTOCOL == IPPROTO_UDP (17) */
proto = -1;
len = sizeof(proto);
CHECK_RET(getsockopt(fd_udp, SOL_SOCKET, SO_PROTOCOL, &proto, &len), 0,
"getsockopt(SO_PROTOCOL) on UDP");
CHECK(proto == 17, "UDP: SO_PROTOCOL == IPPROTO_UDP (17)");

/* 只读: setsockopt 必须拒绝 */
int val = 1;
CHECK_ERR(setsockopt(fd_tcp, SOL_SOCKET, SO_PROTOCOL, &val, sizeof(val)),
ENOPROTOOPT, "setsockopt(SO_PROTOCOL) returns ENOPROTOOPT");

close(fd_tcp);
close(fd_udp);
}

/* ---- SO_DOMAIN (3) ---- */

static void test_so_domain(void) {
TEST_START("SO_DOMAIN");

int fd_tcp = socket(AF_INET, SOCK_STREAM, 0);
int fd_udp = socket(AF_INET, SOCK_DGRAM, 0);
CHECK(fd_tcp >= 0, "socket(TCP)");
CHECK(fd_udp >= 0, "socket(UDP)");

/* TCP: SO_DOMAIN == AF_INET (2) */
int domain = -1;
socklen_t len = sizeof(domain);
CHECK_RET(getsockopt(fd_tcp, SOL_SOCKET, SO_DOMAIN, &domain, &len), 0,
"getsockopt(SO_DOMAIN) on TCP");
CHECK(domain == AF_INET, "TCP: SO_DOMAIN == AF_INET (2)");

/* UDP: SO_DOMAIN == AF_INET (2) */
domain = -1;
len = sizeof(domain);
CHECK_RET(getsockopt(fd_udp, SOL_SOCKET, SO_DOMAIN, &domain, &len), 0,
"getsockopt(SO_DOMAIN) on UDP");
CHECK(domain == AF_INET, "UDP: SO_DOMAIN == AF_INET (2)");

/* 只读: setsockopt 必须拒绝 */
int val = 1;
CHECK_ERR(setsockopt(fd_tcp, SOL_SOCKET, SO_DOMAIN, &val, sizeof(val)),
ENOPROTOOPT, "setsockopt(SO_DOMAIN) returns ENOPROTOOPT");

close(fd_tcp);
close(fd_udp);
}

/* ---- Main ---- */

int main(void) {
/* P0: pip blocker */
test_so_type();

/* P1: protocol / domain */
test_so_protocol();
test_so_domain();

TEST_DONE();
}
Loading