mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-20 23:36:34 +00:00
Fix error codes in UDP sendto
and recvfrom
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
00cfdf86c8
commit
346887ace5
@ -1,4 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
use smoltcp::socket::udp::{RecvError, SendError};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
events::IoEvents,
|
events::IoEvents,
|
||||||
@ -40,24 +41,39 @@ impl BoundDatagram {
|
|||||||
buf: &mut [u8],
|
buf: &mut [u8],
|
||||||
flags: SendRecvFlags,
|
flags: SendRecvFlags,
|
||||||
) -> Result<(usize, IpEndpoint)> {
|
) -> Result<(usize, IpEndpoint)> {
|
||||||
self.bound_socket
|
let result = self
|
||||||
.raw_with(|socket: &mut RawUdpSocket| socket.recv_slice(buf))
|
.bound_socket
|
||||||
.map_err(|_| Error::with_message(Errno::EAGAIN, "recv buf is empty"))
|
.raw_with(|socket: &mut RawUdpSocket| socket.recv_slice(buf));
|
||||||
|
match result {
|
||||||
|
Ok((recv_len, endpoint)) => Ok((recv_len, endpoint)),
|
||||||
|
Err(RecvError::Exhausted) => {
|
||||||
|
return_errno_with_message!(Errno::EAGAIN, "the receive buffer is empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_sendto(
|
pub fn try_sendto(
|
||||||
&self,
|
&self,
|
||||||
buf: &[u8],
|
buf: &[u8],
|
||||||
remote: Option<IpEndpoint>,
|
remote: &IpEndpoint,
|
||||||
flags: SendRecvFlags,
|
flags: SendRecvFlags,
|
||||||
) -> Result<usize> {
|
) -> Result<usize> {
|
||||||
let remote_endpoint = remote
|
let result = self.bound_socket.raw_with(|socket: &mut RawUdpSocket| {
|
||||||
.or(self.remote_endpoint)
|
if socket.payload_send_capacity() < buf.len() {
|
||||||
.ok_or_else(|| Error::with_message(Errno::EINVAL, "udp should provide remote addr"))?;
|
return None;
|
||||||
self.bound_socket
|
}
|
||||||
.raw_with(|socket: &mut RawUdpSocket| socket.send_slice(buf, remote_endpoint))
|
Some(socket.send_slice(buf, *remote))
|
||||||
.map(|_| buf.len())
|
});
|
||||||
.map_err(|_| Error::with_message(Errno::EAGAIN, "send udp packet fails"))
|
match result {
|
||||||
|
Some(Ok(())) => Ok(buf.len()),
|
||||||
|
Some(Err(SendError::BufferFull)) => {
|
||||||
|
return_errno_with_message!(Errno::EAGAIN, "the send buffer is full")
|
||||||
|
}
|
||||||
|
Some(Err(SendError::Unaddressable)) => {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "the destionation address is invalid")
|
||||||
|
}
|
||||||
|
None => return_errno_with_message!(Errno::EMSGSIZE, "the message is too large"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn init_pollee(&self, pollee: &Pollee) {
|
pub(super) fn init_pollee(&self, pollee: &Pollee) {
|
||||||
|
@ -88,6 +88,15 @@ impl DatagramSocket {
|
|||||||
self.nonblocking.store(nonblocking, Ordering::SeqCst);
|
self.nonblocking.store(nonblocking, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remote_endpoint(&self) -> Option<IpEndpoint> {
|
||||||
|
let inner = self.inner.read();
|
||||||
|
|
||||||
|
match inner.as_ref() {
|
||||||
|
Inner::Bound(bound_datagram) => bound_datagram.remote_endpoint(),
|
||||||
|
Inner::Unbound(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn try_bind_empheral(&self, remote_endpoint: &IpEndpoint) -> Result<()> {
|
fn try_bind_empheral(&self, remote_endpoint: &IpEndpoint) -> Result<()> {
|
||||||
// Fast path
|
// Fast path
|
||||||
if let Inner::Bound(_) = self.inner.read().as_ref() {
|
if let Inner::Bound(_) = self.inner.read().as_ref() {
|
||||||
@ -110,24 +119,23 @@ impl DatagramSocket {
|
|||||||
|
|
||||||
fn try_recvfrom(&self, buf: &mut [u8], flags: SendRecvFlags) -> Result<(usize, SocketAddr)> {
|
fn try_recvfrom(&self, buf: &mut [u8], flags: SendRecvFlags) -> Result<(usize, SocketAddr)> {
|
||||||
let inner = self.inner.read();
|
let inner = self.inner.read();
|
||||||
|
|
||||||
let Inner::Bound(bound_datagram) = inner.as_ref() else {
|
let Inner::Bound(bound_datagram) = inner.as_ref() else {
|
||||||
return_errno_with_message!(Errno::EINVAL, "the socket is not bound");
|
return_errno_with_message!(Errno::EAGAIN, "the socket is not bound");
|
||||||
};
|
};
|
||||||
|
|
||||||
let (recv_bytes, remote_endpoint) = bound_datagram.try_recvfrom(buf, flags)?;
|
let (recv_bytes, remote_endpoint) = bound_datagram.try_recvfrom(buf, flags)?;
|
||||||
bound_datagram.update_io_events(&self.pollee);
|
bound_datagram.update_io_events(&self.pollee);
|
||||||
Ok((recv_bytes, remote_endpoint.into()))
|
Ok((recv_bytes, remote_endpoint.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_sendto(
|
fn try_sendto(&self, buf: &[u8], remote: &IpEndpoint, flags: SendRecvFlags) -> Result<usize> {
|
||||||
&self,
|
|
||||||
buf: &[u8],
|
|
||||||
remote: Option<IpEndpoint>,
|
|
||||||
flags: SendRecvFlags,
|
|
||||||
) -> Result<usize> {
|
|
||||||
let inner = self.inner.read();
|
let inner = self.inner.read();
|
||||||
|
|
||||||
let Inner::Bound(bound_datagram) = inner.as_ref() else {
|
let Inner::Bound(bound_datagram) = inner.as_ref() else {
|
||||||
return_errno_with_message!(Errno::EINVAL, "the socket is not bound");
|
return_errno_with_message!(Errno::EAGAIN, "the socket is not bound")
|
||||||
};
|
};
|
||||||
|
|
||||||
let sent_bytes = bound_datagram.try_sendto(buf, remote, flags)?;
|
let sent_bytes = bound_datagram.try_sendto(buf, remote, flags)?;
|
||||||
bound_datagram.update_io_events(&self.pollee);
|
bound_datagram.update_io_events(&self.pollee);
|
||||||
Ok(sent_bytes)
|
Ok(sent_bytes)
|
||||||
@ -244,12 +252,7 @@ impl Socket for DatagramSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn peer_addr(&self) -> Result<SocketAddr> {
|
fn peer_addr(&self) -> Result<SocketAddr> {
|
||||||
let inner = self.inner.read();
|
self.remote_endpoint()
|
||||||
let Inner::Bound(bound_datagram) = inner.as_ref() else {
|
|
||||||
return_errno_with_message!(Errno::ENOTCONN, "the socket is not connected")
|
|
||||||
};
|
|
||||||
bound_datagram
|
|
||||||
.remote_endpoint()
|
|
||||||
.map(|endpoint| endpoint.into())
|
.map(|endpoint| endpoint.into())
|
||||||
.ok_or_else(|| Error::with_message(Errno::ENOTCONN, "the socket is not connected"))
|
.ok_or_else(|| Error::with_message(Errno::ENOTCONN, "the socket is not connected"))
|
||||||
}
|
}
|
||||||
@ -275,15 +278,21 @@ impl Socket for DatagramSocket {
|
|||||||
debug_assert!(flags.is_all_supported());
|
debug_assert!(flags.is_all_supported());
|
||||||
|
|
||||||
let remote_endpoint = match remote {
|
let remote_endpoint = match remote {
|
||||||
Some(remote_addr) => Some(remote_addr.try_into()?),
|
Some(remote_addr) => {
|
||||||
None => None,
|
let endpoint = remote_addr.try_into()?;
|
||||||
|
self.try_bind_empheral(&endpoint)?;
|
||||||
|
endpoint
|
||||||
|
}
|
||||||
|
None => self.remote_endpoint().ok_or_else(|| {
|
||||||
|
Error::with_message(
|
||||||
|
Errno::EDESTADDRREQ,
|
||||||
|
"the destination address is not specified",
|
||||||
|
)
|
||||||
|
})?,
|
||||||
};
|
};
|
||||||
if let Some(endpoint) = remote_endpoint {
|
|
||||||
self.try_bind_empheral(&endpoint)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Block if the send buffer is full
|
// TODO: Block if the send buffer is full
|
||||||
let sent_bytes = self.try_sendto(buf, remote_endpoint, flags)?;
|
let sent_bytes = self.try_sendto(buf, &remote_endpoint, flags)?;
|
||||||
poll_ifaces();
|
poll_ifaces();
|
||||||
Ok(sent_bytes)
|
Ok(sent_bytes)
|
||||||
}
|
}
|
||||||
|
@ -82,3 +82,56 @@ FN_TEST(getpeername)
|
|||||||
addrlen == sizeof(saddr) && saddr.sin_port == C_PORT);
|
addrlen == sizeof(saddr) && saddr.sin_port == C_PORT);
|
||||||
}
|
}
|
||||||
END_TEST()
|
END_TEST()
|
||||||
|
|
||||||
|
FN_TEST(send)
|
||||||
|
{
|
||||||
|
char buf[1] = { 'z' };
|
||||||
|
|
||||||
|
TEST_ERRNO(send(sk_unbound, buf, 1, 0), EDESTADDRREQ);
|
||||||
|
|
||||||
|
TEST_ERRNO(send(sk_bound, buf, 1, 0), EDESTADDRREQ);
|
||||||
|
}
|
||||||
|
END_TEST()
|
||||||
|
|
||||||
|
FN_TEST(recv)
|
||||||
|
{
|
||||||
|
char buf[1] = { 'z' };
|
||||||
|
|
||||||
|
TEST_ERRNO(recv(sk_unbound, buf, 1, 0), EAGAIN);
|
||||||
|
|
||||||
|
TEST_ERRNO(recv(sk_bound, buf, 1, 0), EAGAIN);
|
||||||
|
|
||||||
|
TEST_ERRNO(recv(sk_connected, buf, 1, 0), EAGAIN);
|
||||||
|
}
|
||||||
|
END_TEST()
|
||||||
|
|
||||||
|
FN_TEST(send_and_recv)
|
||||||
|
{
|
||||||
|
char buf[1];
|
||||||
|
struct sockaddr_in saddr;
|
||||||
|
socklen_t addrlen = sizeof(saddr);
|
||||||
|
|
||||||
|
sk_addr.sin_port = C_PORT;
|
||||||
|
buf[0] = 'a';
|
||||||
|
TEST_RES(sendto(sk_bound, buf, 1, 0, (struct sockaddr *)&sk_addr,
|
||||||
|
sizeof(sk_addr)),
|
||||||
|
_ret == 1);
|
||||||
|
|
||||||
|
buf[0] = 'b';
|
||||||
|
TEST_RES(send(sk_connected, buf, 1, 0), _ret == 1);
|
||||||
|
|
||||||
|
saddr.sin_port = 0;
|
||||||
|
buf[0] = 0;
|
||||||
|
TEST_RES(recvfrom(sk_bound, buf, 1, 0, (struct sockaddr *)&saddr,
|
||||||
|
&addrlen),
|
||||||
|
_ret == 1 && addrlen == sizeof(sk_addr) &&
|
||||||
|
saddr.sin_port == C_PORT && buf[0] == 'a');
|
||||||
|
|
||||||
|
saddr.sin_port = 0;
|
||||||
|
buf[0] = 0;
|
||||||
|
TEST_RES(recvfrom(sk_bound, buf, 1, 0, (struct sockaddr *)&saddr,
|
||||||
|
&addrlen),
|
||||||
|
_ret == 1 && addrlen == sizeof(sk_addr) &&
|
||||||
|
saddr.sin_port != C_PORT && buf[0] == 'b');
|
||||||
|
}
|
||||||
|
END_TEST()
|
||||||
|
Reference in New Issue
Block a user