-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Kernel/Net: Implement SO_LINGER support in TCPSocket close behavior #25037
Conversation
f05d6e0
to
e365670
Compare
Hello! One or more of the commit messages in this PR do not match the SerenityOS code submission policy, please check the |
(looks like the updated commit description has lines longer than 72 chars, making CI unhappy.) |
Looks like you also need to use "Kernel/Net: " instead of "Net: " as prefix in the commit title. |
e9749c7
to
6cb4b8c
Compare
Nice work! This was one of the (many) blockers needed to make my asynchronous sockets work on Serenity. I would love to see a test for this though, something like: create a TCP socket pair, make one of the ends non-blocking with {0,x} second lingering, sends a ton of data to overflow receive/send buffers, close that end, poll the other end and see how fast POLLERR arrives. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, I’m not even sure whether data can be properly acked int the background while the socket is almost closed (you never change the state after linger was detected), so... the TCP logic here is very dubious.
} | ||
} else { | ||
dbgln_if(TCP_SOCKET_DEBUG, "SO_LINGER without timeout, closing immediately"); | ||
(void)send_tcp_packet(TCPFlags::RST); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where are these reset packets coming from, that doesn’t look very state-machine correct? see the code below that follows TCP state machine behavior.
(void)Thread::current()->sleep(Duration::from_milliseconds(1)); | ||
} while (TimeManagement::the().monotonic_time() < deadline); | ||
|
||
if (has_unacked_data) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you never re-check the unacked data, meaning this variable will likely not correctly reflect the current state of things at this point (likely, most data was acked by now, but that’s not checked).
Kernel/Net/TCPSocket.cpp
Outdated
if (!has_unacked_data) | ||
break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this check seems pointless and can just be part of the while instead
|
||
if (has_unacked_data) { | ||
dbgln_if(TCP_SOCKET_DEBUG, "SO_LINGER timeout. Some data couldn't do it :("); | ||
(void)send_tcp_packet(TCPFlags::RST); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m also not sure whether this is state-machine-correct behavior? are we not supposed to send just a FIN in this case?
SO_LINGER allows specifying a timeout interval during which the socket attempts to send any remaining data before closing. If all data is acknowledged within the specified timeout, the connection is closed gracefully using a FIN/ACK exchange. If the timeout expires with unacknowledged data or l_linger set to 0, the socket is forcefully closed using RST.
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions! |
This PR introduces a simple option that changes the behavior of
close()
for connection-oriented protocols, allowing us to specify a timeout interval for packets to be acknowledged or let us forcefully close the socket with a RST.This feature is particularly useful for the Dropbear and libuv ports and enables more advanced socket operations. I specifically need this for porting a mainframe emulator.