mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-29 14:23:22 +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 {
|
impl AnyUnboundSocket {
|
||||||
pub fn new_tcp(observer: Weak<dyn Observer<()>>) -> Self {
|
pub fn new_tcp(observer: Weak<dyn Observer<()>>) -> Self {
|
||||||
let raw_tcp_socket = {
|
let raw_tcp_socket = {
|
||||||
let rx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0u8; RECV_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; SEND_BUF_LEN]);
|
let tx_buffer = smoltcp::socket::tcp::SocketBuffer::new(vec![0u8; TCP_SEND_BUF_LEN]);
|
||||||
RawTcpSocket::new(rx_buffer, tx_buffer)
|
RawTcpSocket::new(rx_buffer, tx_buffer)
|
||||||
};
|
};
|
||||||
AnyUnboundSocket {
|
AnyUnboundSocket {
|
||||||
@ -44,7 +44,7 @@ impl AnyUnboundSocket {
|
|||||||
let metadata = smoltcp::socket::udp::PacketMetadata::EMPTY;
|
let metadata = smoltcp::socket::udp::PacketMetadata::EMPTY;
|
||||||
let rx_buffer = smoltcp::socket::udp::PacketBuffer::new(
|
let rx_buffer = smoltcp::socket::udp::PacketBuffer::new(
|
||||||
vec![metadata; UDP_METADATA_LEN],
|
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(
|
let tx_buffer = smoltcp::socket::udp::PacketBuffer::new(
|
||||||
vec![metadata; UDP_METADATA_LEN],
|
vec![metadata; UDP_METADATA_LEN],
|
||||||
@ -209,10 +209,10 @@ impl Drop for AnyBoundSocketInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For TCP
|
// For TCP
|
||||||
pub const RECV_BUF_LEN: usize = 65536;
|
pub const TCP_RECV_BUF_LEN: usize = 65536;
|
||||||
pub const SEND_BUF_LEN: usize = 65536;
|
pub const TCP_SEND_BUF_LEN: usize = 65536;
|
||||||
|
|
||||||
// For UDP
|
// 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_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;
|
mod virtio;
|
||||||
|
|
||||||
pub use any_socket::{
|
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;
|
pub use loopback::IfaceLoopback;
|
||||||
use ostd::sync::LocalIrqDisabled;
|
use ostd::sync::LocalIrqDisabled;
|
||||||
|
@ -9,12 +9,15 @@ use super::{common::get_ephemeral_endpoint, IpEndpoint, UNSPECIFIED_LOCAL_ENDPOI
|
|||||||
use crate::{
|
use crate::{
|
||||||
events::{IoEvents, Observer},
|
events::{IoEvents, Observer},
|
||||||
fs::{file_handle::FileLike, utils::StatusFlags},
|
fs::{file_handle::FileLike, utils::StatusFlags},
|
||||||
|
match_sock_option_mut,
|
||||||
net::{
|
net::{
|
||||||
poll_ifaces,
|
poll_ifaces,
|
||||||
socket::{
|
socket::{
|
||||||
|
options::{Error as SocketError, SocketOption},
|
||||||
util::{
|
util::{
|
||||||
copy_message_from_user, copy_message_to_user, create_message_buffer,
|
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,
|
Socket,
|
||||||
},
|
},
|
||||||
@ -27,7 +30,21 @@ use crate::{
|
|||||||
mod bound;
|
mod bound;
|
||||||
mod unbound;
|
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 {
|
pub struct DatagramSocket {
|
||||||
|
options: RwLock<OptionSet>,
|
||||||
inner: RwLock<Takeable<Inner>>,
|
inner: RwLock<Takeable<Inner>>,
|
||||||
nonblocking: AtomicBool,
|
nonblocking: AtomicBool,
|
||||||
pollee: Pollee,
|
pollee: Pollee,
|
||||||
@ -80,6 +97,7 @@ impl DatagramSocket {
|
|||||||
inner: RwLock::new(Takeable::new(Inner::Unbound(unbound_datagram))),
|
inner: RwLock::new(Takeable::new(Inner::Unbound(unbound_datagram))),
|
||||||
nonblocking: AtomicBool::new(nonblocking),
|
nonblocking: AtomicBool::new(nonblocking),
|
||||||
pollee,
|
pollee,
|
||||||
|
options: RwLock::new(OptionSet::new()),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -352,6 +370,22 @@ impl Socket for DatagramSocket {
|
|||||||
|
|
||||||
Ok((copied_bytes, message_header))
|
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 {
|
impl Observer<()> for DatagramSocket {
|
||||||
|
@ -19,16 +19,11 @@ use crate::{
|
|||||||
net::{
|
net::{
|
||||||
poll_ifaces,
|
poll_ifaces,
|
||||||
socket::{
|
socket::{
|
||||||
options::{
|
options::{Error as SocketError, SocketOption},
|
||||||
Error as SocketError, Linger, RecvBuf, ReuseAddr, ReusePort, SendBuf, SocketOption,
|
|
||||||
},
|
|
||||||
util::{
|
util::{
|
||||||
copy_message_from_user, copy_message_to_user, create_message_buffer,
|
copy_message_from_user, copy_message_to_user, create_message_buffer,
|
||||||
options::{SocketOptionSet, MIN_RECVBUF, MIN_SENDBUF},
|
options::SocketOptionSet, send_recv_flags::SendRecvFlags,
|
||||||
send_recv_flags::SendRecvFlags,
|
shutdown_cmd::SockShutdownCmd, socket_addr::SocketAddr, MessageHeader,
|
||||||
shutdown_cmd::SockShutdownCmd,
|
|
||||||
socket_addr::SocketAddr,
|
|
||||||
MessageHeader,
|
|
||||||
},
|
},
|
||||||
Socket,
|
Socket,
|
||||||
},
|
},
|
||||||
@ -561,15 +556,9 @@ impl Socket for StreamSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_option(&self, option: &mut dyn SocketOption) -> Result<()> {
|
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, {
|
match_sock_option_mut!(option, {
|
||||||
socket_errors: SocketError => {
|
socket_errors: SocketError => {
|
||||||
let mut options = self.options.write();
|
self.options.write().socket.get_and_clear_sock_errors(socket_errors);
|
||||||
let sock_errors = options.socket.sock_errors();
|
|
||||||
socket_errors.set(sock_errors);
|
|
||||||
options.socket.set_sock_errors(None);
|
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
},
|
},
|
||||||
_ => ()
|
_ => ()
|
||||||
@ -577,25 +566,12 @@ impl Socket for StreamSocket {
|
|||||||
|
|
||||||
let options = self.options.read();
|
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, {
|
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 => {
|
tcp_no_delay: NoDelay => {
|
||||||
let no_delay = options.tcp.no_delay();
|
let no_delay = options.tcp.no_delay();
|
||||||
tcp_no_delay.set(no_delay);
|
tcp_no_delay.set(no_delay);
|
||||||
@ -628,39 +604,14 @@ impl Socket for StreamSocket {
|
|||||||
fn set_option(&self, option: &dyn SocketOption) -> Result<()> {
|
fn set_option(&self, option: &dyn SocketOption) -> Result<()> {
|
||||||
let mut options = self.options.write();
|
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
|
// FIXME: here we have only set the value of the option, without actually
|
||||||
// making any real modifications.
|
// making any real modifications.
|
||||||
match_sock_option_ref!(option, {
|
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 => {
|
tcp_no_delay: NoDelay => {
|
||||||
let no_delay = tcp_no_delay.get().unwrap();
|
let no_delay = tcp_no_delay.get().unwrap();
|
||||||
options.tcp.set_no_delay(*no_delay);
|
options.tcp.set_no_delay(*no_delay);
|
||||||
|
@ -3,7 +3,13 @@
|
|||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
|
||||||
use crate::{
|
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::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -26,11 +32,101 @@ impl SocketOptionSet {
|
|||||||
sock_errors: None,
|
sock_errors: None,
|
||||||
reuse_addr: false,
|
reuse_addr: false,
|
||||||
reuse_port: false,
|
reuse_port: false,
|
||||||
send_buf: SEND_BUF_LEN as u32,
|
send_buf: TCP_SEND_BUF_LEN as u32,
|
||||||
recv_buf: RECV_BUF_LEN as u32,
|
recv_buf: TCP_RECV_BUF_LEN as u32,
|
||||||
linger: LingerOption::default(),
|
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;
|
pub const MIN_SENDBUF: u32 = 2304;
|
||||||
|
Reference in New Issue
Block a user