Skip to content

Commit

Permalink
Add SO_REUSEADDR support
Browse files Browse the repository at this point in the history
  • Loading branch information
YXalix committed Apr 27, 2024
1 parent 57f4665 commit 44a031e
Show file tree
Hide file tree
Showing 14 changed files with 145 additions and 48 deletions.
3 changes: 0 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,3 @@ lto = true

[patch.crates-io]
crate_interface = { path = "crates/crate_interface" }

[patch."https://github.com/rcore-os/smoltcp.git"]
smoltcp = { git = "https://github.com/c0per/smoltcp", branch = "starryos" }
7 changes: 5 additions & 2 deletions modules/axnet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ smoltcp = []
# 启用ip协议与否
ip = []

default = ["smoltcp"]
signal = []

default = ["smoltcp", "signal"]

[dependencies]
log = "0.4"
Expand All @@ -29,10 +31,11 @@ axsync = { path = "../axsync" }
axtask = { path = "../axtask" }
axdriver = { path = "../axdriver", features = ["net"] }
axio = { path = "../../crates/axio" }
crate_interface = { path = "../../crates/crate_interface" }

[dependencies.smoltcp]
git = "https://github.com/rcore-os/smoltcp.git"
rev = "2ade274"
rev = "b7134a3"
default-features = false
features = [
"alloc", "log", # no std
Expand Down
4 changes: 2 additions & 2 deletions modules/axnet/src/smoltcp_impl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ impl<'a> SocketSetWrapper<'a> {

pub fn new_udp_socket() -> socket::udp::Socket<'a> {
let udp_rx_buffer = socket::udp::PacketBuffer::new(
vec![socket::udp::PacketMetadata::EMPTY; 8],
vec![socket::udp::PacketMetadata::EMPTY; 256],
vec![0; UDP_RX_BUF_LEN],
);
let udp_tx_buffer = socket::udp::PacketBuffer::new(
vec![socket::udp::PacketMetadata::EMPTY; 8],
vec![socket::udp::PacketMetadata::EMPTY; 256],
vec![0; UDP_TX_BUF_LEN],
);
socket::udp::Socket::new(udp_rx_buffer, udp_tx_buffer)
Expand Down
45 changes: 31 additions & 14 deletions modules/axnet/src/smoltcp_impl/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ use smoltcp::iface::SocketHandle;
use smoltcp::socket::tcp::{self, ConnectError, State};
use smoltcp::wire::{IpEndpoint, IpListenEndpoint};

#[cfg(feature = "signal")]
use crate_interface::{call_interface, def_interface};

use super::addr::{from_core_sockaddr, into_core_sockaddr, is_unspecified, UNSPECIFIED_ENDPOINT};
use super::{SocketSetWrapper, LISTEN_TABLE, SOCKET_SET};

Expand All @@ -27,6 +30,16 @@ const STATE_CONNECTING: u8 = 2;
const STATE_CONNECTED: u8 = 3;
const STATE_LISTENING: u8 = 4;

#[cfg(feature = "signal")]
#[def_interface]
/// Handler to send signals.
pub trait SignalCaller {
/// Handles interrupt requests for the given IRQ number.
fn send_signal(tid: isize, signum: isize);
/// Return true if current task have a signal pending.
fn current_have_signal() -> bool;
}

/// A TCP socket that provides POSIX-like APIs.
///
/// - [`connect`] is for TCP clients.
Expand Down Expand Up @@ -307,19 +320,19 @@ impl TcpSocket {
let handle = unsafe { self.handle.get().read().unwrap() };
self.block_on(|| {
SOCKET_SET.with_socket_mut::<tcp::Socket, _, _>(handle, |socket| {
if !socket.is_active() {
// not open
ax_err!(ConnectionRefused, "socket recv() failed")
} else if !socket.may_recv() {
// connection closed
Ok(0)
} else if socket.recv_queue() > 0 {
if socket.recv_queue() > 0 {
// data available
// TODO: use socket.recv(|buf| {...})
let len = socket
.recv_slice(buf)
.map_err(|_| ax_err_type!(BadState, "socket recv() failed"))?;
Ok(len)
} else if !socket.is_active() {
// not open
ax_err!(ConnectionRefused, "socket recv() failed")
} else if !socket.may_recv() {
// connection closed
Ok(0)
} else {
// no more data
Err(AxError::WouldBlock)
Expand All @@ -343,19 +356,19 @@ impl TcpSocket {
let handle = unsafe { self.handle.get().read().unwrap() };
self.block_on(|| {
SOCKET_SET.with_socket_mut::<tcp::Socket, _, _>(handle, |socket| {
if !socket.is_active() {
// not open
ax_err!(ConnectionRefused, "socket recv() failed")
} else if !socket.may_recv() {
// connection closed
Ok(0)
} else if socket.recv_queue() > 0 {
if socket.recv_queue() > 0 {
// data available
// TODO: use socket.recv(|buf| {...})
let len = socket
.recv_slice(buf)
.map_err(|_| ax_err_type!(BadState, "socket recv() failed"))?;
Ok(len)
} else if !socket.is_active() {
// not open
ax_err!(ConnectionRefused, "socket recv() failed")
} else if !socket.may_recv() {
// connection closed
Ok(0)
} else {
// no more data
if current_ticks() > expire_at {
Expand Down Expand Up @@ -609,6 +622,10 @@ impl TcpSocket {
f()
} else {
loop {
#[cfg(feature = "signal")]
if call_interface!(SignalCaller::current_have_signal) {
return Err(AxError::Interrupted);
}
SOCKET_SET.poll_interfaces();
match f() {
Ok(t) => return Ok(t),
Expand Down
40 changes: 39 additions & 1 deletion modules/axnet/src/smoltcp_impl/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,33 @@ use axio::{PollState, Read, Write};
use axsync::Mutex;
use spin::RwLock;

#[cfg(feature = "signal")]
use crate_interface::{call_interface, def_interface};

use smoltcp::iface::SocketHandle;
use smoltcp::socket::udp::{self, BindError, SendError};
use smoltcp::wire::{IpEndpoint, IpListenEndpoint};

use super::addr::{from_core_sockaddr, into_core_sockaddr, is_unspecified, UNSPECIFIED_ENDPOINT};
use super::{SocketSetWrapper, SOCKET_SET};

#[cfg(feature = "signal")]
#[def_interface]
/// Handler to send signals.
pub trait SignalCaller {
/// Handles interrupt requests for the given IRQ number.
fn send_signal(tid: isize, signum: isize);
/// Return true if current task have a signal pending.
fn current_have_signal() -> bool;
}

/// A UDP socket that provides POSIX-like APIs.
pub struct UdpSocket {
handle: SocketHandle,
local_addr: RwLock<Option<IpEndpoint>>,
peer_addr: RwLock<Option<IpEndpoint>>,
nonblock: AtomicBool,
reuse_addr: AtomicBool,
}

impl UdpSocket {
Expand All @@ -33,6 +47,7 @@ impl UdpSocket {
local_addr: RwLock::new(None),
peer_addr: RwLock::new(None),
nonblock: AtomicBool::new(false),
reuse_addr: AtomicBool::new(false),
}
}

Expand Down Expand Up @@ -79,6 +94,22 @@ impl UdpSocket {
});
}

/// Returns whether this socket is in reuse address mode.
#[inline]
pub fn is_reuse_addr(&self) -> bool {
self.reuse_addr.load(Ordering::Acquire)
}

/// Moves this UDP socket into or out of reuse address mode.
///
/// When a socket is bound, the `SO_REUSEADDR` option allows multiple sockets to be bound to the
/// same address if they are bound to different local addresses. This option must be set before
/// calling `bind`.
#[inline]
pub fn set_reuse_addr(&self, reuse_addr: bool) {
self.reuse_addr.store(reuse_addr, Ordering::Release);
}

/// Binds an unbound socket to the given address and port.
///
/// It's must be called before [`send_to`](Self::send_to) and
Expand All @@ -99,7 +130,10 @@ impl UdpSocket {
port: local_endpoint.port,
};

SOCKET_SET.bind_check(local_endpoint.addr, local_endpoint.port)?;
if !self.is_reuse_addr() {
// Check if the address is already in use
SOCKET_SET.bind_check(local_endpoint.addr, local_endpoint.port)?;
}

SOCKET_SET.with_socket_mut::<udp::Socket, _, _>(self.handle, |socket| {
socket.bind(endpoint).or_else(|e| match e {
Expand Down Expand Up @@ -295,6 +329,10 @@ impl UdpSocket {
f()
} else {
loop {
#[cfg(feature = "signal")]
if call_interface!(SignalCaller::current_have_signal) {
return Err(AxError::Interrupted);
}
SOCKET_SET.poll_interfaces();
match f() {
Ok(t) => return Ok(t),
Expand Down
4 changes: 4 additions & 0 deletions modules/axprocess/src/signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,4 +329,8 @@ impl SignalCaller for SignalCallerImpl {
fn send_signal(tid: isize, signum: isize) {
send_signal_to_thread(tid, signum).unwrap();
}

fn current_have_signal() -> bool {
current_process().have_signals().is_some()
}
}
2 changes: 2 additions & 0 deletions modules/axtask/src/stat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ pub struct TimeStat {
pub trait SignalCaller {
/// Handles interrupt requests for the given IRQ number.
fn send_signal(tid: isize, signum: isize);
/// Return true if current task have a signal pending.
fn current_have_signal() -> bool;
}

#[allow(unused)]
Expand Down
9 changes: 8 additions & 1 deletion ulib/axstarry/src/syscall_fs/ctype/epoll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ pub struct EpollEvent {
pub event_type: EpollEventType,
/// 事件中使用到的数据,如fd等
pub data: u64,
pub fd: i32,
pub data_u32: u32,
pub data_u64: u64,
}

numeric_enum_macro::numeric_enum! {
Expand Down Expand Up @@ -105,7 +108,8 @@ impl EpollFile {
// 添加事件
EpollCtl::ADD => {
if inner.monitor_list.contains_key(&fd) {
return Err(SyscallError::EEXIST);
// return Err(SyscallError::EEXIST);
inner.monitor_list.insert(fd, event);
}
inner.monitor_list.insert(fd, event);
}
Expand Down Expand Up @@ -181,6 +185,9 @@ impl EpollFile {
ret_events.push(EpollEvent {
event_type: EpollEventType::EPOLLERR,
data: req_event.data,
fd: -1,
data_u32: 0,
data_u64: 0,
});
}
}
Expand Down
3 changes: 3 additions & 0 deletions ulib/axstarry/src/syscall_fs/fs_syscall_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ numeric_enum_macro::numeric_enum! {
SELECT = 23,
PSELECT6 = 270,
READLINK = 89,
CHMOD = 90,
PREADLINKAT = 267,
FSTAT = 5,
LSTAT = 6,
Expand All @@ -124,5 +125,7 @@ numeric_enum_macro::numeric_enum! {
RENAMEAT = 264,
RENAMEAT2 = 316,
COPYFILERANGE = 326,
EPOLL_CREATE1 = 291,
EPOLL_PWAIT = 281,
}
}
5 changes: 5 additions & 0 deletions ulib/axstarry/src/syscall_fs/imp/epoll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ pub fn syscall_epoll_wait(args: [usize; 6]) -> SyscallResult {
let max_event = max_event as usize;
let process = current_process();
let start: VirtAddr = (event as usize).into();
// FIXME: this is a temporary solution
// the memory will out of mapped memory if the max_event is too large
// maybe give the max_event a limit is a better solution
let max_event = core::cmp::min(max_event, 400);
let end = start + max_event * core::mem::size_of::<EpollEvent>();
if process.manual_alloc_range_for_lazy(start, end).is_err() {
return Err(SyscallError::EFAULT);
Expand All @@ -112,6 +116,7 @@ pub fn syscall_epoll_wait(args: [usize; 6]) -> SyscallResult {
} else {
usize::MAX
};
drop(fd_table);
let ret_events = epoll_file.epoll_wait(timeout);
if ret_events.is_err() {
return Err(SyscallError::EINTR);
Expand Down
12 changes: 10 additions & 2 deletions ulib/axstarry/src/syscall_fs/imp/poll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,17 @@ pub fn syscall_pselect6(args: [usize; 6]) -> SyscallResult {
if current_ticks() as usize > expire_time {
return Ok(0);
}
// TODO: fix this and use mask to ignore specific signal
// #[cfg(feature = "signal")]
// if process.have_signals().is_some() {
// if process.signal_modules
// return Err(SyscallError::EINTR);
// }
#[cfg(feature = "signal")]
if process.have_signals().is_some() {
return Err(SyscallError::EINTR);
if let Some(signalno) = process.have_signals() {
if signalno == 9 {
return Ok(0);
}
}
}
}
6 changes: 6 additions & 0 deletions ulib/axstarry/src/syscall_fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,11 @@ pub fn fs_syscall(syscall_id: fs_syscall_id::FsSyscallId, args: [usize; 6]) -> S
READLINK => syscall_readlink(args),
#[cfg(target_arch = "x86_64")]
CREAT => Err(axerrno::LinuxError::EPERM),
#[cfg(target_arch = "x86_64")]
EPOLL_CREATE1 => unimplemented!("epoll_create1"),
#[cfg(target_arch = "x86_64")]
EPOLL_PWAIT => unimplemented!("epoll_ctl"),
#[cfg(target_arch = "x86_64")]
CHMOD => Ok(0),
}
}
3 changes: 1 addition & 2 deletions ulib/axstarry/src/syscall_net/imp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,8 +481,7 @@ pub fn syscall_set_sock_opt(args: [usize; 6]) -> SyscallResult {
return Ok(0);
};

option.set(socket, opt);
Ok(0)
option.set(socket, opt)
}
}
}
Expand Down
Loading

0 comments on commit 44a031e

Please sign in to comment.