Receive RST packets as ECONNRESET errors

This commit is contained in:
Ruihan Li
2025-02-24 23:07:58 +08:00
committed by Tate, Hongliang Tian
parent aa29640ed7
commit d40d452e9d
6 changed files with 256 additions and 31 deletions

View File

@ -94,8 +94,12 @@ impl ConnectedStream {
debug_assert!(!*need_poll);
Err(e)
}
Err(RecvError::Finished) => Ok((0, NeedIfacePoll::FALSE)),
Err(RecvError::InvalidState) => {
Err(RecvError::Finished) | Err(RecvError::InvalidState) => {
// `InvalidState` occurs when the connection is reset but `ECONNRESET` was reported
// earlier. Linux returns EOF in this case, so we follow it.
Ok((0, NeedIfacePoll::FALSE))
}
Err(RecvError::ConnReset) => {
return_errno_with_message!(Errno::ECONNRESET, "the connection is reset")
}
}
@ -106,10 +110,6 @@ impl ConnectedStream {
reader: &mut dyn MultiRead,
_flags: SendRecvFlags,
) -> Result<(usize, NeedIfacePoll)> {
if reader.is_empty() {
return Ok((0, NeedIfacePoll::FALSE));
}
let result = self.tcp_conn.send(|socket_buffer| {
match reader.read(&mut VmWriter::from(socket_buffer)) {
Ok(len) => (len, Ok(len)),
@ -128,9 +128,9 @@ impl ConnectedStream {
Err(e)
}
Err(SendError::InvalidState) => {
// FIXME: `EPIPE` is another possibility, which means that the socket is shut down
// for writing. In that case, we should also trigger a `SIGPIPE` if `MSG_NOSIGNAL`
// is not specified.
return_errno_with_message!(Errno::EPIPE, "the connection is closed");
}
Err(SendError::ConnReset) => {
return_errno_with_message!(Errno::ECONNRESET, "the connection is reset");
}
}
@ -187,10 +187,26 @@ impl ConnectedStream {
events |= IoEvents::HUP;
}
// If the connection is reset, add an ERR event.
if socket.is_rst_closed() {
events |= IoEvents::ERR;
}
events
})
}
pub(super) fn test_and_clear_error(&self) -> Option<Error> {
if self.tcp_conn.clear_rst_closed() {
Some(Error::with_message(
Errno::ECONNRESET,
"the connection is reset",
))
} else {
None
}
}
pub(super) fn set_raw_option<R>(
&self,
set_option: impl FnOnce(&dyn RawTcpSetOption) -> R,

View File

@ -331,7 +331,10 @@ impl StreamSocket {
}
};
let (recv_bytes, need_poll) = connected_stream.try_recv(writer, flags)?;
let result = connected_stream.try_recv(writer, flags);
self.pollee.invalidate();
let (recv_bytes, need_poll) = result?;
let iface_to_poll = need_poll.then(|| connected_stream.iface().clone());
let remote_endpoint = connected_stream.remote_endpoint();
@ -355,7 +358,6 @@ impl StreamSocket {
return result;
}
State::Listen(_) => {
// TODO: Trigger `SIGPIPE` if `MSG_NOSIGNAL` is not specified
return_errno_with_message!(Errno::EPIPE, "the socket is not connected");
}
State::Connecting(_) => {
@ -365,11 +367,13 @@ impl StreamSocket {
}
};
let (sent_bytes, need_poll) = connected_stream.try_send(reader, flags)?;
let result = connected_stream.try_send(reader, flags);
self.pollee.invalidate();
let (sent_bytes, need_poll) = result?;
let iface_to_poll = need_poll.then(|| connected_stream.iface().clone());
drop(state);
self.pollee.invalidate();
if let Some(iface) = iface_to_poll {
iface.poll();
}
@ -393,7 +397,8 @@ impl StreamSocket {
let error = match state.as_ref() {
State::Init(init_stream) => init_stream.test_and_clear_error(),
State::Connecting(_) | State::Listen(_) | State::Connected(_) => None,
State::Connected(connected_stream) => connected_stream.test_and_clear_error(),
State::Connecting(_) | State::Listen(_) => None,
};
self.pollee.invalidate();
error
@ -553,6 +558,8 @@ impl Socket for StreamSocket {
}
self.block_on(IoEvents::OUT, || self.try_send(reader, flags))
// TODO: Trigger `SIGPIPE` if the error code is `EPIPE` and `MSG_NOSIGNAL` is not specified
}
fn recvmsg(