Skip to content
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

Closed
wants to merge 1 commit into from

Conversation

logkos
Copy link
Contributor

@logkos logkos commented Sep 22, 2024

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.

@logkos logkos force-pushed the lingmyding branch 2 times, most recently from f05d6e0 to e365670 Compare September 26, 2024 17:32
@logkos logkos marked this pull request as ready for review September 26, 2024 17:32
@github-actions github-actions bot added the 👀 pr-needs-review PR needs review from a maintainer or community member label Sep 26, 2024
Kernel/Net/TCPSocket.cpp Outdated Show resolved Hide resolved
@BuggieBot
Copy link
Member

Hello!

One or more of the commit messages in this PR do not match the SerenityOS code submission policy, please check the lint_commits CI job for more details on which commits were flagged and why.
Please do not close this PR and open another, instead modify your commit message(s) with git commit --amend and force push those changes to update this PR.

@nico nico added ⏳ pr-waiting-for-author PR is blocked by feedback / code changes from the author and removed 👀 pr-needs-review PR needs review from a maintainer or community member labels Sep 27, 2024
@nico
Copy link
Contributor

nico commented Sep 27, 2024

(looks like the updated commit description has lines longer than 72 chars, making CI unhappy.)

@github-actions github-actions bot added 👀 pr-needs-review PR needs review from a maintainer or community member and removed ⏳ pr-waiting-for-author PR is blocked by feedback / code changes from the author labels Sep 27, 2024
@logkos logkos requested a review from nico September 27, 2024 20:47
@nico
Copy link
Contributor

nico commented Sep 28, 2024

Looks like you also need to use "Kernel/Net: " instead of "Net: " as prefix in the commit title.

@nico nico added ⏳ pr-waiting-for-author PR is blocked by feedback / code changes from the author and removed 👀 pr-needs-review PR needs review from a maintainer or community member labels Sep 28, 2024
@logkos logkos changed the title Net: Implement SO_LINGER support in TCPSocket close behavior Kernel/Net: Implement SO_LINGER support in TCPSocket close behavior Sep 29, 2024
@github-actions github-actions bot added 👀 pr-needs-review PR needs review from a maintainer or community member and removed ⏳ pr-waiting-for-author PR is blocked by feedback / code changes from the author labels Sep 29, 2024
@logkos logkos force-pushed the lingmyding branch 5 times, most recently from e9749c7 to 6cb4b8c Compare October 1, 2024 18:23
@DanShaders
Copy link
Contributor

DanShaders commented Oct 2, 2024

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.

@DanShaders DanShaders added ⏳ pr-waiting-for-author PR is blocked by feedback / code changes from the author and removed 👀 pr-needs-review PR needs review from a maintainer or community member labels Oct 2, 2024
@github-actions github-actions bot added 👀 pr-needs-review PR needs review from a maintainer or community member and removed ⏳ pr-waiting-for-author PR is blocked by feedback / code changes from the author labels Oct 2, 2024
Copy link
Collaborator

@kleinesfilmroellchen kleinesfilmroellchen left a 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);
Copy link
Collaborator

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) {
Copy link
Collaborator

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).

Comment on lines 673 to 674
if (!has_unacked_data)
break;
Copy link
Collaborator

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);
Copy link
Collaborator

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.
Copy link

stale bot commented Nov 5, 2024

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!

@stale stale bot added the stale label Nov 5, 2024
@logkos logkos closed this Nov 16, 2024
@github-actions github-actions bot removed the 👀 pr-needs-review PR needs review from a maintainer or community member label Nov 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants