Skip to content

Commit

Permalink
syscall: Support SO_REUSEADDR for udp
Browse files Browse the repository at this point in the history
Signed-off-by: rayylee <[email protected]>
  • Loading branch information
hbuxiaofei committed Apr 16, 2024
1 parent ab29b3d commit 878bd4c
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 17 deletions.
18 changes: 16 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions modules/axnet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ version = "0.5.11"
default-features = false

[dependencies.smoltcp]
git = "https://github.com/rcore-os/smoltcp.git"
rev = "2ade274"
git = "https://github.com/YXalix/smoltcp.git"
default-features = false
features = [
"alloc", "log", # no std
Expand Down
22 changes: 21 additions & 1 deletion modules/axnet/src/smoltcp_impl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ use alloc::vec;
use core::cell::RefCell;
use core::ops::DerefMut;

use axerrno::{ax_err, ax_err_type, AxError, AxResult};
use axdriver::prelude::*;
use axhal::time::{current_time_nanos, NANOS_PER_MICROS};
use axsync::Mutex;
use driver_net::{DevError, NetBufPtr};
use lazy_init::LazyInit;
use smoltcp::iface::{Config, Interface, SocketHandle, SocketSet};
use smoltcp::phy::{Device, DeviceCapabilities, Medium, RxToken, TxToken};
use smoltcp::socket::{self, AnySocket};
use smoltcp::socket::{self, AnySocket, Socket};
use smoltcp::time::Instant;
use smoltcp::wire::{EthernetAddress, HardwareAddress, IpAddress, IpCidr};

Expand Down Expand Up @@ -130,6 +131,23 @@ impl<'a> SocketSetWrapper<'a> {
f(socket)
}

pub fn bind_check(&self, addr: IpAddress, port: u16) -> AxResult {
let mut sockets = self.0.lock();
error!("checking addr: {:?}, port: {}", addr, port);
for item in sockets.iter_mut() {
match item.1 {
Socket::Udp(s) => {
error!("{}", s.endpoint().port);
if s.endpoint().port == port {
return Err(AxError::AddrInUse);
}
},
_ => continue,
};
}
Ok(())
}

pub fn poll_interfaces(&self) {
#[cfg(feature = "ip")]
{
Expand Down Expand Up @@ -350,6 +368,8 @@ pub(crate) fn init(_net_dev: AxNetDevice) {
.push(IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8))
.unwrap();
});
let multicast_addr = IpAddress::v4(239, 255, 0, 1);
let _= iface.join_multicast_group(&mut device, multicast_addr, Instant::from_micros_const((current_time_nanos() / NANOS_PER_MICROS) as i64));
LOOPBACK.init_by(Mutex::new(iface));
LOOPBACK_DEV.init_by(Mutex::new(device));
}
Expand Down
26 changes: 25 additions & 1 deletion modules/axnet/src/smoltcp_impl/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct UdpSocket {
local_addr: RwLock<Option<IpEndpoint>>,
peer_addr: RwLock<Option<IpEndpoint>>,
nonblock: AtomicBool,
reuse_addr: AtomicBool,
}

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

Expand All @@ -63,6 +65,22 @@ impl UdpSocket {
self.nonblock.load(Ordering::Acquire)
}

/// 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);
}

/// Moves this UDP socket into or out of nonblocking mode.
///
/// This will result in `recv`, `recv_from`, `send`, and `send_to`
Expand Down Expand Up @@ -95,6 +113,12 @@ impl UdpSocket {
addr: (!is_unspecified(local_endpoint.addr)).then_some(local_endpoint.addr),
port: 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 {
BindError::InvalidState => ax_err!(AlreadyExists, "socket bind() failed"),
Expand Down Expand Up @@ -233,7 +257,7 @@ impl UdpSocket {
multicast_addr, interface_addr
);
let _ = LOOPBACK.lock().join_multicast_group(LOOPBACK_DEV.lock().deref_mut(), multicast_addr, timestamp);
}
}
}

/// Private methods
Expand Down
22 changes: 11 additions & 11 deletions ulib/axstarry/src/syscall_net/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,23 +153,19 @@ impl SocketOption {
pub fn set(&self, socket: &Socket, opt: &[u8]) -> SyscallResult {
match self {
SocketOption::SO_REUSEADDR => {
// unimplemented!("wait for implementation of SO_REUSEADDR");
if opt.len() < 4 {
panic!("can't read a int from socket opt value");
}

let opt_value = i32::from_ne_bytes(<[u8; 4]>::try_from(&opt[0..4]).unwrap());

socket.set_reuse_addr(opt_value != 0);
// socket.reuse_addr = opt_value != 0;
Ok((0))
}
SocketOption::SO_DONTROUTE => {
if opt.len() < 4 {
panic!("can't read a int from socket opt value");
}

let opt_value = i32::from_ne_bytes(<[u8; 4]>::try_from(&opt[0..4]).unwrap());

socket.set_reuse_addr(opt_value != 0);
// socket.reuse_addr = opt_value != 0;
Ok((0))
Expand Down Expand Up @@ -450,7 +446,6 @@ pub struct Socket {
recv_timeout: Mutex<Option<TimeVal>>,

// fake options
reuse_addr: AtomicBool,
dont_route: bool,
send_buf_size: AtomicU64,
recv_buf_size: AtomicU64,
Expand All @@ -472,7 +467,11 @@ impl Socket {
*self.recv_timeout.lock()
}
fn get_reuse_addr(&self) -> bool {
self.reuse_addr.load(core::sync::atomic::Ordering::Acquire)
let inner = self.inner.lock();
match &*inner {
SocketInner::Udp(s) => s.is_reuse_addr(),
_ => unimplemented!("get_reuse_addr on other socket")
}
}

fn get_send_buf_size(&self) -> u64 {
Expand All @@ -494,8 +493,11 @@ impl Socket {
}

fn set_reuse_addr(&self, flag: bool) {
self.reuse_addr
.store(flag, core::sync::atomic::Ordering::Release)
let inner = self.inner.lock();
match &*inner {
SocketInner::Udp(s) => s.set_reuse_addr(flag),
_ => unimplemented!("set_reuse_addr on other socket")
}
}

fn set_send_buf_size(&self, size: u64) {
Expand Down Expand Up @@ -536,7 +538,6 @@ impl Socket {
inner: Mutex::new(inner),
close_exec: false,
recv_timeout: Mutex::new(None),
reuse_addr: AtomicBool::new(false),
dont_route: false,
send_buf_size: AtomicU64::new(64 * 1024),
recv_buf_size: AtomicU64::new(64 * 1024),
Expand Down Expand Up @@ -658,7 +659,6 @@ impl Socket {
inner: Mutex::new(SocketInner::Tcp(new_socket)),
close_exec: false,
recv_timeout: Mutex::new(None),
reuse_addr: AtomicBool::new(false),
dont_route: false,
send_buf_size: AtomicU64::new(64 * 1024),
recv_buf_size: AtomicU64::new(64 * 1024),
Expand Down

0 comments on commit 878bd4c

Please sign in to comment.