-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
gh-123476: Add support for existing TCP_QUICKACK socket setting to Windows #123478
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
Conversation
On Windows, sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_QUICKACK, 1) throws AttributeError: module 'socket' has no attribute 'TCP_QUICKACK' TCP_QUICKACK already exists and has support on the Linux side, this change just adds support when running on Windows as well.
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
Misc/NEWS.d/next/Windows/2024-08-29-16-13-45.gh-issue-123476.m2DFS4.rst
Outdated
Show resolved
Hide resolved
Co-authored-by: Kirill Podoprigora <[email protected]>
Update: disregard this comment, I found a good way to add the unit test. I had to remove the (new) unit tests for QUICKACK:
For all of those reasons I believe it is reasonable to omit the unit tests from the PR. |
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 PR is windows specific, the change was not even being exercised in the CI workflow.
Actually, we have build bots for that so we can test it. So tests are required. You can make them conditioned on some information.
I'm surprised that you need a special casing for TCP_QUICKACK
by the way and an additional structure field. Can't you just use get/setsockopt
as with other constants?
Misc/NEWS.d/next/Windows/2024-08-29-16-13-45.gh-issue-123476.m2DFS4.rst
Outdated
Show resolved
Hide resolved
#ifdef MS_WINDOWS | ||
if (optname == SIO_TCP_SET_ACK_FREQUENCY) { | ||
int dummy; | ||
res = WSAIoctl(s->sock_fd, SIO_TCP_SET_ACK_FREQUENCY, &flag, |
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.
Should I understand that this constant cannot be used by setsockopt
and that you need this special path?
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.
Yes, on windows platform, QUICKACK can only be set through WSAIoctl() and is not supported through setsockopt()
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.
Another quick note to help with review:
On Windows, the only values accepted for SIO_TCP_SET_ACK_FREQUENCY is 0 and 1, with 1 meaning "ack every 1 packets" aka TCP_QUICKACK is on, and 0 meaning "use default value" aka TCP_QUICKACK is off. So there's no need to translate the value set by the user. 1 is on, 0 is off, just like TCP_NODELAY and other socket flags. A convenient coincidence.
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 see. I un-resolved this conversation so that future reviewers can see it (otherwise GH hides it).
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'll throw another note in here for future reviewers then: there is no equivalent SIO_TCP_GET_ACK_FREQUENCY, so the value must be saved in the socket object. On Windows SIO_TCP_SET_ACK_FREQUENCY is always 0 for a new socket, and the socket->quickack variable is always initialized to 0, so the response value from socket.getsockopt for TCP_QUICKACK will always be correct on Windows even if not previously set.
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.
another explanation of behavior for future reviewers, please see this comment: #123478 (comment)
if statement brackets Co-authored-by: Bénédikt Tran <[email protected]>
edit: realized a better way, TC added, I'll look for examples of how to do that in other tests so that I can re-add them. If you have any quick pointers that might help as I am unfamiliar with this codebase. I would note that QUICKACK isn't being tested at all right now, not even the existing support for Linux, but test cases are a good thing so I'll make the effort ;)
Unfortunately not for this platform, please see the code review comment replies. |
…2DFS4.rst Improve phrasing Co-authored-by: Bénédikt Tran <[email protected]>
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.
Change overall looks fine to me (apart from the apparent dead code), but I can only assume that this is the right way to enable TCP_QUICKACK
. If someone more knowledgeable can confirm there are no unintended tricks or incompatibilities (that is, it does on Windows precisely what code written for POSIX will expect it to do), then it seems fine.
edit: Realized what this meant after, will move that func.
Discussion between myself and picnixz on specific behavior: https://github.com/python/cpython/pull/123478/files#r1738786292 SIO_TCP_SET_ACK_FREQUENCY is not well documented on Windows but its behavior is confirmed, here is some discussion from folks at MS about adding this same support to the .NET runtime.
That "workaround exist" refers to this: dotnet/runtime#798 (comment) Note that the value 12 passed for linux is the linux header defined TCP_QUICKACK value which was already implemented in cpython. Note that on Windows, IOControl is the .NET equivalent to WSAIoctl (what this PR calls). And when they say "no consistent cross platform support" that might mean the lack of Mac support (fair enough) or the fact that the flag isn't persistent on Linux. Lack of Mac support: dotnet/runtime#798 (comment) As to the lack of persistency on Linux, this flag was already exposed in cpython on Linux, my PR is only to add support for Windows which doesn't have that flaw. So that quirk of behavior on Linux is already there and "accounted for". It literally does the same thing, Linux just decides "maybe you changed your mind" and turs it off after every receive whereas windows respects your intent. Part of the reason they didn't add it to .NET is they didn't want to have to keep turning it back on when running on Linux if the user selected QUICKACK behavior. I suspect this "resetting flag" issue is also why many linux distros are forcing QUICKACK permanently on across the whole system nowadays so the flag doesn't even need to be set (over and over again) and because the alternative is unnecessary with modern networking systems and detrimental to latency sensitive applications. |
Thanks, that .NET thread is convincing. Once you've moved out the asyncio changes, I'll merge. |
formatting style oops Co-authored-by: Steve Dower <[email protected]>
Maybe it makes sense to set TCP_QUICKACK flag by default on asyncio sockets, similar to what's done with TCP_NODELAY. But I would prefer to have a separated PR for that and have an asyncio expert to say if it makes sense or not. |
Agree on leaving it to an expert (my gut says yes) but if that ends up happening it may be worth looking into |
Thank you. I believe I've moved them to the right place but am unfamiliar with cpython's test setup so please let me know if any further tweaks are required. I want to quickly point out that I wasn't sure what version number to put into Doc/library/socket.rst so that may need changing before merge. |
There was an unrelated failure in the CI workflow, but pulling main seems to have fixed it. |
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.
LGTM. I just have a remark/question on the test.
Merged, thanks for your contribution. |
On Windows,
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_QUICKACK, 1)
throwsAttributeError: module 'socket' has no attribute 'TCP_QUICKACK'
TCP_QUICKACK already exists and has support on the Linux side, this change just adds support when running on Windows as well.