mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-29 16:13:27 +00:00
Implement UDP getsockopt and setsockopt
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
468dae33f0
commit
dc4df47007
@ -29,8 +29,8 @@ pub(super) enum SocketFamily {
|
||||
impl AnyUnboundSocket {
|
||||
pub fn new_tcp(observer: Weak<dyn Observer<()>>) -> Self {
|
||||
let raw_tcp_socket = {
|
||||
let rx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0u8; RECV_BUF_LEN]);
|
||||
let tx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0u8; SEND_BUF_LEN]);
|
||||
let rx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0u8; TCP_RECV_BUF_LEN]);
|
||||
let tx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0u8; TCP_SEND_BUF_LEN]);
|
||||
RawTcpSocket::new(rx_buffer, tx_buffer)
|
||||
};
|
||||
AnyUnboundSocket {
|
||||
@ -44,7 +44,7 @@ impl AnyUnboundSocket {
|
||||
let metadata = smoltcp::socket::udp::PacketMetadata::EMPTY;
|
||||
let rx_buffer = smoltcp::socket::udp::PacketBuffer::new(
|
||||
vec![metadata; UDP_METADATA_LEN],
|
||||
vec![0u8; UDP_RECEIVE_PAYLOAD_LEN],
|
||||
vec![0u8; UDP_RECV_PAYLOAD_LEN],
|
||||
);
|
||||
let tx_buffer = smoltcp::socket::udp::PacketBuffer::new(
|
||||
vec![metadata; UDP_METADATA_LEN],
|
||||
@ -209,10 +209,10 @@ impl Drop for AnyBoundSocketInner {
|
||||
}
|
||||
|
||||
// For TCP
|
||||
pub const RECV_BUF_LEN: usize = 65536;
|
||||
pub const SEND_BUF_LEN: usize = 65536;
|
||||
pub const TCP_RECV_BUF_LEN: usize = 65536;
|
||||
pub const TCP_SEND_BUF_LEN: usize = 65536;
|
||||
|
||||
// For UDP
|
||||
pub const UDP_SEND_PAYLOAD_LEN: usize = 65536;
|
||||
pub const UDP_RECV_PAYLOAD_LEN: usize = 65536;
|
||||
const UDP_METADATA_LEN: usize = 256;
|
||||
const UDP_SEND_PAYLOAD_LEN: usize = 65536;
|
||||
const UDP_RECEIVE_PAYLOAD_LEN: usize = 65536;
|
||||
|
@ -14,7 +14,8 @@ mod util;
|
||||
mod virtio;
|
||||
|
||||
pub use any_socket::{
|
||||
AnyBoundSocket, AnyUnboundSocket, RawTcpSocket, RawUdpSocket, RECV_BUF_LEN, SEND_BUF_LEN,
|
||||
AnyBoundSocket, AnyUnboundSocket, RawTcpSocket, RawUdpSocket, TCP_RECV_BUF_LEN,
|
||||
TCP_SEND_BUF_LEN, UDP_RECV_PAYLOAD_LEN, UDP_SEND_PAYLOAD_LEN,
|
||||
};
|
||||
pub use loopback::IfaceLoopback;
|
||||
use ostd::sync::LocalIrqDisabled;
|
||||
|
@ -9,12 +9,15 @@ use super::{common::get_ephemeral_endpoint, IpEndpoint, UNSPECIFIED_LOCAL_ENDPOI
|
||||
use crate::{
|
||||
events::{IoEvents, Observer},
|
||||
fs::{file_handle::FileLike, utils::StatusFlags},
|
||||
match_sock_option_mut,
|
||||
net::{
|
||||
poll_ifaces,
|
||||
socket::{
|
||||
options::{Error as SocketError, SocketOption},
|
||||
util::{
|
||||
copy_message_from_user, copy_message_to_user, create_message_buffer,
|
||||
send_recv_flags::SendRecvFlags, socket_addr::SocketAddr, MessageHeader,
|
||||
options::SocketOptionSet, send_recv_flags::SendRecvFlags, socket_addr::SocketAddr,
|
||||
MessageHeader,
|
||||
},
|
||||
Socket,
|
||||
},
|
||||
@ -27,7 +30,21 @@ use crate::{
|
||||
mod bound;
|
||||
mod unbound;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct OptionSet {
|
||||
socket: SocketOptionSet,
|
||||
// TODO: UDP option set
|
||||
}
|
||||
|
||||
impl OptionSet {
|
||||
fn new() -> Self {
|
||||
let socket = SocketOptionSet::new_udp();
|
||||
OptionSet { socket }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DatagramSocket {
|
||||
options: RwLock<OptionSet>,
|
||||
inner: RwLock<Takeable<Inner>>,
|
||||
nonblocking: AtomicBool,
|
||||
pollee: Pollee,
|
||||
@ -80,6 +97,7 @@ impl DatagramSocket {
|
||||
inner: RwLock::new(Takeable::new(Inner::Unbound(unbound_datagram))),
|
||||
nonblocking: AtomicBool::new(nonblocking),
|
||||
pollee,
|
||||
options: RwLock::new(OptionSet::new()),
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -352,6 +370,22 @@ impl Socket for DatagramSocket {
|
||||
|
||||
Ok((copied_bytes, message_header))
|
||||
}
|
||||
|
||||
fn get_option(&self, option: &mut dyn SocketOption) -> Result<()> {
|
||||
match_sock_option_mut!(option, {
|
||||
socket_errors: SocketError => {
|
||||
self.options.write().socket.get_and_clear_sock_errors(socket_errors);
|
||||
return Ok(());
|
||||
},
|
||||
_ => ()
|
||||
});
|
||||
|
||||
self.options.read().socket.get_option(option)
|
||||
}
|
||||
|
||||
fn set_option(&self, option: &dyn SocketOption) -> Result<()> {
|
||||
self.options.write().socket.set_option(option)
|
||||
}
|
||||
}
|
||||
|
||||
impl Observer<()> for DatagramSocket {
|
||||
|
@ -19,16 +19,11 @@ use crate::{
|
||||
net::{
|
||||
poll_ifaces,
|
||||
socket::{
|
||||
options::{
|
||||
Error as SocketError, Linger, RecvBuf, ReuseAddr, ReusePort, SendBuf, SocketOption,
|
||||
},
|
||||
options::{Error as SocketError, SocketOption},
|
||||
util::{
|
||||
copy_message_from_user, copy_message_to_user, create_message_buffer,
|
||||
options::{SocketOptionSet, MIN_RECVBUF, MIN_SENDBUF},
|
||||
send_recv_flags::SendRecvFlags,
|
||||
shutdown_cmd::SockShutdownCmd,
|
||||
socket_addr::SocketAddr,
|
||||
MessageHeader,
|
||||
options::SocketOptionSet, send_recv_flags::SendRecvFlags,
|
||||
shutdown_cmd::SockShutdownCmd, socket_addr::SocketAddr, MessageHeader,
|
||||
},
|
||||
Socket,
|
||||
},
|
||||
@ -561,15 +556,9 @@ impl Socket for StreamSocket {
|
||||
}
|
||||
|
||||
fn get_option(&self, option: &mut dyn SocketOption) -> Result<()> {
|
||||
// Note that the socket error has to be handled separately, because it is automatically
|
||||
// cleared after reading.
|
||||
match_sock_option_mut!(option, {
|
||||
socket_errors: SocketError => {
|
||||
let mut options = self.options.write();
|
||||
let sock_errors = options.socket.sock_errors();
|
||||
socket_errors.set(sock_errors);
|
||||
options.socket.set_sock_errors(None);
|
||||
|
||||
self.options.write().socket.get_and_clear_sock_errors(socket_errors);
|
||||
return Ok(());
|
||||
},
|
||||
_ => ()
|
||||
@ -577,25 +566,12 @@ impl Socket for StreamSocket {
|
||||
|
||||
let options = self.options.read();
|
||||
|
||||
match options.socket.get_option(option) {
|
||||
Err(err) if err.error() == Errno::ENOPROTOOPT => (),
|
||||
res => return res.map(|_| ()),
|
||||
}
|
||||
|
||||
match_sock_option_mut!(option, {
|
||||
// Socket options:
|
||||
socket_reuse_addr: ReuseAddr => {
|
||||
let reuse_addr = options.socket.reuse_addr();
|
||||
socket_reuse_addr.set(reuse_addr);
|
||||
},
|
||||
socket_send_buf: SendBuf => {
|
||||
let send_buf = options.socket.send_buf();
|
||||
socket_send_buf.set(send_buf);
|
||||
},
|
||||
socket_recv_buf: RecvBuf => {
|
||||
let recv_buf = options.socket.recv_buf();
|
||||
socket_recv_buf.set(recv_buf);
|
||||
},
|
||||
socket_reuse_port: ReusePort => {
|
||||
let reuse_port = options.socket.reuse_port();
|
||||
socket_reuse_port.set(reuse_port);
|
||||
},
|
||||
// TCP options:
|
||||
tcp_no_delay: NoDelay => {
|
||||
let no_delay = options.tcp.no_delay();
|
||||
tcp_no_delay.set(no_delay);
|
||||
@ -628,39 +604,14 @@ impl Socket for StreamSocket {
|
||||
fn set_option(&self, option: &dyn SocketOption) -> Result<()> {
|
||||
let mut options = self.options.write();
|
||||
|
||||
match options.socket.set_option(option) {
|
||||
Err(err) if err.error() == Errno::ENOPROTOOPT => (),
|
||||
res => return res,
|
||||
}
|
||||
|
||||
// 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: 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: 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: ReuseAddr => {
|
||||
let reuse_addr = socket_reuse_addr.get().unwrap();
|
||||
options.socket.set_reuse_addr(*reuse_addr);
|
||||
},
|
||||
socket_reuse_port: ReusePort => {
|
||||
let reuse_port = socket_reuse_port.get().unwrap();
|
||||
options.socket.set_reuse_port(*reuse_port);
|
||||
},
|
||||
socket_linger: Linger => {
|
||||
let linger = socket_linger.get().unwrap();
|
||||
options.socket.set_linger(*linger);
|
||||
},
|
||||
// TCP options:
|
||||
tcp_no_delay: NoDelay => {
|
||||
let no_delay = tcp_no_delay.get().unwrap();
|
||||
options.tcp.set_no_delay(*no_delay);
|
||||
|
@ -3,7 +3,13 @@
|
||||
use core::time::Duration;
|
||||
|
||||
use crate::{
|
||||
net::iface::{RECV_BUF_LEN, SEND_BUF_LEN},
|
||||
match_sock_option_mut, match_sock_option_ref,
|
||||
net::{
|
||||
iface::{TCP_RECV_BUF_LEN, TCP_SEND_BUF_LEN, UDP_RECV_PAYLOAD_LEN, UDP_SEND_PAYLOAD_LEN},
|
||||
socket::options::{
|
||||
Error as SocketError, Linger, RecvBuf, ReuseAddr, ReusePort, SendBuf, SocketOption,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
@ -26,11 +32,101 @@ impl SocketOptionSet {
|
||||
sock_errors: None,
|
||||
reuse_addr: false,
|
||||
reuse_port: false,
|
||||
send_buf: SEND_BUF_LEN as u32,
|
||||
recv_buf: RECV_BUF_LEN as u32,
|
||||
send_buf: TCP_SEND_BUF_LEN as u32,
|
||||
recv_buf: TCP_RECV_BUF_LEN as u32,
|
||||
linger: LingerOption::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the default socket level options for udp socket.
|
||||
pub fn new_udp() -> Self {
|
||||
Self {
|
||||
sock_errors: None,
|
||||
reuse_addr: false,
|
||||
reuse_port: false,
|
||||
send_buf: UDP_SEND_PAYLOAD_LEN as u32,
|
||||
recv_buf: UDP_RECV_PAYLOAD_LEN as u32,
|
||||
linger: LingerOption::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets and clears the socket error.
|
||||
///
|
||||
/// When processing the `getsockopt` system call, the socket error is automatically cleared
|
||||
/// after reading. This method should be called to provide this behavior.
|
||||
pub fn get_and_clear_sock_errors(&mut self, option: &mut SocketError) {
|
||||
option.set(self.sock_errors());
|
||||
self.set_sock_errors(None);
|
||||
}
|
||||
|
||||
/// Gets socket-level options.
|
||||
///
|
||||
/// Note that the socket error has to be handled separately, because it is automatically
|
||||
/// cleared after reading. This method does not handle it. Instead,
|
||||
/// [`Self::get_and_clear_socket_errors`] should be used.
|
||||
pub fn get_option(&self, option: &mut dyn SocketOption) -> Result<()> {
|
||||
match_sock_option_mut!(option, {
|
||||
socket_reuse_addr: ReuseAddr => {
|
||||
let reuse_addr = self.reuse_addr();
|
||||
socket_reuse_addr.set(reuse_addr);
|
||||
},
|
||||
socket_send_buf: SendBuf => {
|
||||
let send_buf = self.send_buf();
|
||||
socket_send_buf.set(send_buf);
|
||||
},
|
||||
socket_recv_buf: RecvBuf => {
|
||||
let recv_buf = self.recv_buf();
|
||||
socket_recv_buf.set(recv_buf);
|
||||
},
|
||||
socket_reuse_port: ReusePort => {
|
||||
let reuse_port = self.reuse_port();
|
||||
socket_reuse_port.set(reuse_port);
|
||||
},
|
||||
socket_linger: Linger => {
|
||||
let linger = self.linger();
|
||||
socket_linger.set(linger);
|
||||
},
|
||||
_ => return_errno_with_message!(Errno::ENOPROTOOPT, "the socket option to get is unknown")
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets socket-level options.
|
||||
pub fn set_option(&mut self, option: &dyn SocketOption) -> Result<()> {
|
||||
match_sock_option_ref!(option, {
|
||||
socket_recv_buf: RecvBuf => {
|
||||
let recv_buf = socket_recv_buf.get().unwrap();
|
||||
if *recv_buf <= MIN_RECVBUF {
|
||||
self.set_recv_buf(MIN_RECVBUF);
|
||||
} else {
|
||||
self.set_recv_buf(*recv_buf);
|
||||
}
|
||||
},
|
||||
socket_send_buf: SendBuf => {
|
||||
let send_buf = socket_send_buf.get().unwrap();
|
||||
if *send_buf <= MIN_SENDBUF {
|
||||
self.set_send_buf(MIN_SENDBUF);
|
||||
} else {
|
||||
self.set_send_buf(*send_buf);
|
||||
}
|
||||
},
|
||||
socket_reuse_addr: ReuseAddr => {
|
||||
let reuse_addr = socket_reuse_addr.get().unwrap();
|
||||
self.set_reuse_addr(*reuse_addr);
|
||||
},
|
||||
socket_reuse_port: ReusePort => {
|
||||
let reuse_port = socket_reuse_port.get().unwrap();
|
||||
self.set_reuse_port(*reuse_port);
|
||||
},
|
||||
socket_linger: Linger => {
|
||||
let linger = socket_linger.get().unwrap();
|
||||
self.set_linger(*linger);
|
||||
},
|
||||
_ => return_errno_with_message!(Errno::ENOPROTOOPT, "the socket option to be set is unknown")
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub const MIN_SENDBUF: u32 = 2304;
|
||||
|
Reference in New Issue
Block a user