1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-28 09:05:09 +00:00

Kernel: Fix race between accept() and connect().

We had a bug where an accepted socket would appear to be EOF/disconnected
on the accepting side until the connecting side had called attach_fd().

Fix this by adding a new SocketRole::Connecting state.
This commit is contained in:
Andreas Kling 2019-03-20 02:33:51 +01:00
parent 31d3616027
commit 4aa0ab4e08
5 changed files with 14 additions and 4 deletions

View file

@ -106,6 +106,8 @@ void LocalSocket::attach_fd(SocketRole role)
++m_accepted_fds_open;
} else if (role == SocketRole::Connected) {
++m_connected_fds_open;
} else if (role == SocketRole::Connecting) {
++m_connecting_fds_open;
}
}
@ -117,6 +119,9 @@ void LocalSocket::detach_fd(SocketRole role)
} else if (role == SocketRole::Connected) {
ASSERT(m_connected_fds_open);
--m_connected_fds_open;
} else if (role == SocketRole::Connecting) {
ASSERT(m_connecting_fds_open);
--m_connecting_fds_open;
}
}
@ -125,7 +130,7 @@ bool LocalSocket::can_read(SocketRole role) const
if (role == SocketRole::Listener)
return can_accept();
if (role == SocketRole::Accepted)
return !m_connected_fds_open || !m_for_server.is_empty();
return (!m_connected_fds_open && !m_connecting_fds_open) || !m_for_server.is_empty();
if (role == SocketRole::Connected)
return !m_accepted_fds_open || !m_for_client.is_empty();
ASSERT_NOT_REACHED();
@ -148,7 +153,7 @@ ssize_t LocalSocket::write(SocketRole role, const byte* data, ssize_t size)
return m_for_client.write(data, size);
}
if (role == SocketRole::Connected) {
if (!m_connected_fds_open)
if (!m_connected_fds_open && !m_connecting_fds_open)
return -EPIPE;
return m_for_server.write(data, size);
}
@ -158,7 +163,7 @@ ssize_t LocalSocket::write(SocketRole role, const byte* data, ssize_t size)
bool LocalSocket::can_write(SocketRole role) const
{
if (role == SocketRole::Accepted)
return !m_connected_fds_open || m_for_client.bytes_in_write_buffer() < 4096;
return (!m_connected_fds_open && !m_connecting_fds_open) || m_for_client.bytes_in_write_buffer() < 4096;
if (role == SocketRole::Connected)
return !m_accepted_fds_open || m_for_server.bytes_in_write_buffer() < 4096;
ASSERT_NOT_REACHED();