mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-20 13:06:33 +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
|
||||
use smoltcp::socket::udp::{RecvError, SendError};
|
||||
|
||||
use crate::{
|
||||
events::IoEvents,
|
||||
@ -40,24 +41,39 @@ impl BoundDatagram {
|
||||
buf: &mut [u8],
|
||||
flags: SendRecvFlags,
|
||||
) -> Result<(usize, IpEndpoint)> {
|
||||
self.bound_socket
|
||||
.raw_with(|socket: &mut RawUdpSocket| socket.recv_slice(buf))
|
||||
.map_err(|_| Error::with_message(Errno::EAGAIN, "recv buf is empty"))
|
||||
let result = self
|
||||
.bound_socket
|
||||
.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(
|
||||
&self,
|
||||
buf: &[u8],
|
||||
remote: Option<IpEndpoint>,
|
||||
remote: &IpEndpoint,
|
||||
flags: SendRecvFlags,
|
||||
) -> Result<usize> {
|
||||
let remote_endpoint = remote
|
||||
.or(self.remote_endpoint)
|
||||
.ok_or_else(|| Error::with_message(Errno::EINVAL, "udp should provide remote addr"))?;
|
||||
self.bound_socket
|
||||
.raw_with(|socket: &mut RawUdpSocket| socket.send_slice(buf, remote_endpoint))
|
||||
.map(|_| buf.len())
|
||||
.map_err(|_| Error::with_message(Errno::EAGAIN, "send udp packet fails"))
|
||||
let result = self.bound_socket.raw_with(|socket: &mut RawUdpSocket| {
|
||||
if socket.payload_send_capacity() < buf.len() {
|
||||
return None;
|
||||
}
|
||||
Some(socket.send_slice(buf, *remote))
|
||||
});
|
||||
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) {
|
||||
|
@ -88,6 +88,15 @@ impl DatagramSocket {
|
||||
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<()> {
|
||||
// Fast path
|
||||
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)> {
|
||||
let inner = self.inner.read();
|
||||
|
||||
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)?;
|
||||
bound_datagram.update_io_events(&self.pollee);
|
||||
Ok((recv_bytes, remote_endpoint.into()))
|
||||
}
|
||||
|
||||
fn try_sendto(
|
||||
&self,
|
||||
buf: &[u8],
|
||||
remote: Option<IpEndpoint>,
|
||||
flags: SendRecvFlags,
|
||||
) -> Result<usize> {
|
||||
fn try_sendto(&self, buf: &[u8], remote: &IpEndpoint, flags: SendRecvFlags) -> Result<usize> {
|
||||
let inner = self.inner.read();
|
||||
|
||||
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)?;
|
||||
bound_datagram.update_io_events(&self.pollee);
|
||||
Ok(sent_bytes)
|
||||
@ -244,12 +252,7 @@ impl Socket for DatagramSocket {
|
||||
}
|
||||
|
||||
fn peer_addr(&self) -> Result<SocketAddr> {
|
||||
let inner = self.inner.read();
|
||||
let Inner::Bound(bound_datagram) = inner.as_ref() else {
|
||||
return_errno_with_message!(Errno::ENOTCONN, "the socket is not connected")
|
||||
};
|
||||
bound_datagram
|
||||
.remote_endpoint()
|
||||
self.remote_endpoint()
|
||||
.map(|endpoint| endpoint.into())
|
||||
.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());
|
||||
|
||||
let remote_endpoint = match remote {
|
||||
Some(remote_addr) => Some(remote_addr.try_into()?),
|
||||
None => None,
|
||||
Some(remote_addr) => {
|
||||
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
|
||||
let sent_bytes = self.try_sendto(buf, remote_endpoint, flags)?;
|
||||
let sent_bytes = self.try_sendto(buf, &remote_endpoint, flags)?;
|
||||
poll_ifaces();
|
||||
Ok(sent_bytes)
|
||||
}
|
||||
|
@ -82,3 +82,56 @@ FN_TEST(getpeername)
|
||||
addrlen == sizeof(saddr) && saddr.sin_port == C_PORT);
|
||||
}
|
||||
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