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

use BOOL for TCP_NODELAY setsockopt value on Windows #94094

Merged
merged 3 commits into from
Mar 1, 2022

Conversation

chrisnc
Copy link
Contributor

@chrisnc chrisnc commented Feb 17, 2022

This issue was found by the Wine project and mitigated there 1.

Windows' setsockopt expects a BOOL (a typedef for int) for TCP_NODELAY
2. Windows itself is forgiving and will accept any positive optlen and
interpret the first byte of *optval as the value, so this bug does not
affect Windows itself, but does affect systems implementing Windows'
interface more strictly, such as Wine. Wine was previously passing this
through to the host's setsockopt, where, e.g., Linux requires that
optlen be correct for the chosen option, and TCP_NODELAY expects an int.

Footnotes

  1. https://source.winehq.org/git/wine.git/commit/d6ea38f32dfd3edbe107a255c37e9f7f3da06ae7

  2. https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-setsockopt

@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @dtolnay (or someone else) soon.

Please see the contribution instructions for more information.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Feb 17, 2022
@chrisnc
Copy link
Contributor Author

chrisnc commented Feb 17, 2022

Fixed footnote index in commit message...

Copy link
Member

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@dtolnay
Copy link
Member

dtolnay commented Feb 17, 2022

@bors r+

@bors
Copy link
Contributor

bors commented Feb 17, 2022

📌 Commit e5f7239 has been approved by dtolnay

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 17, 2022
@dtolnay dtolnay added O-windows Operating system: Windows T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Feb 17, 2022
@chrisnc
Copy link
Contributor Author

chrisnc commented Feb 17, 2022

I guess I didn't properly link this commit to #94092, since I made the commit before creating the issue. Should I update the commit message again to do so, or can someone with write perms link it for me? https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#manually-linking-a-pull-request-to-an-issue

Edit: never mind; I just updated the PR description. I think that should do it.

Edit the second: thanks!

@chrisnc chrisnc changed the title use BOOL for TCP_NODELAY setsockopt value on Windows use BOOL for TCP_NODELAY setsockopt value on Windows (fixes #94092) Feb 17, 2022
@dtolnay dtolnay linked an issue Feb 17, 2022 that may be closed by this pull request
@dtolnay dtolnay changed the title use BOOL for TCP_NODELAY setsockopt value on Windows (fixes #94092) use BOOL for TCP_NODELAY setsockopt value on Windows Feb 17, 2022
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Feb 19, 2022
…=dtolnay

use BOOL for TCP_NODELAY setsockopt value on Windows

This issue was found by the Wine project and mitigated there [^1].

Windows' setsockopt expects a BOOL (a typedef for int) for TCP_NODELAY
[^2]. Windows itself is forgiving and will accept any positive optlen and
interpret the first byte of *optval as the value, so this bug does not
affect Windows itself, but does affect systems implementing Windows'
interface more strictly, such as Wine. Wine was previously passing this
through to the host's setsockopt, where, e.g., Linux requires that
optlen be correct for the chosen option, and TCP_NODELAY expects an int.

[^1]: https://source.winehq.org/git/wine.git/commit/d6ea38f32dfd3edbe107a255c37e9f7f3da06ae7
[^2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-setsockopt
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Feb 19, 2022
…=dtolnay

use BOOL for TCP_NODELAY setsockopt value on Windows

This issue was found by the Wine project and mitigated there [^1].

Windows' setsockopt expects a BOOL (a typedef for int) for TCP_NODELAY
[^2]. Windows itself is forgiving and will accept any positive optlen and
interpret the first byte of *optval as the value, so this bug does not
affect Windows itself, but does affect systems implementing Windows'
interface more strictly, such as Wine. Wine was previously passing this
through to the host's setsockopt, where, e.g., Linux requires that
optlen be correct for the chosen option, and TCP_NODELAY expects an int.

[^1]: https://source.winehq.org/git/wine.git/commit/d6ea38f32dfd3edbe107a255c37e9f7f3da06ae7
[^2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-setsockopt
@matthiaskrgr
Copy link
Member

@bors r-
looks like this causes problems on ci: #94152 (comment)

@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Feb 19, 2022
@chrisnc
Copy link
Contributor Author

chrisnc commented Feb 19, 2022

Agh, looks like the assertion in the getsockopt wrapper is complaining about the size. The docs say that the optval for TCP_NODELAY on getsockopt should also be BOOL (int), but this test failure suggests that getsockopt is setting *optlen to 1... I will investigate.

@chrisnc chrisnc marked this pull request as draft February 19, 2022 22:24
@chrisnc
Copy link
Contributor Author

chrisnc commented Feb 20, 2022

So, I had tested the getsockopt change previously, but I was only testing on Wine, which does not modify *optlen and hence doesn't trigger this assert_eq... This makes me think that this assertion is too strict. POSIX allows for *optlen to be set to a lower value than what is passed in, and Windows is clearly doing this in reality (setting it to 1 after 4 is passed in). It worked before because Rust was always passing in 1, which strictly speaking is not correct but Windows accepts anyway. What do you think @dtolnay?

@chrisnc
Copy link
Contributor Author

chrisnc commented Feb 20, 2022

Somewhat related, I noticed that the getsockopt and setsockopt wrappers in sys_common/net.rs have incorrect argument names, compared with the corresponding names on the C interface. What the wrapper calls opt is actually level, val is actually option_name, and then because it already used val for the wrong thing, it calls the option value payload in setsockopt and slot in getsockopt. I'd like to change these.

@ChrisDenton
Copy link
Member

ChrisDenton commented Feb 20, 2022

So to sum up the issue:

  • The data for TCP_NODELAY is documented as being a BOOL (a 32 bit signed integer)
  • Microsoft Windows will only actually read or write the first byte.
  • WINE used the full 4 bytes.
  • The specification for getsockopt/setsockopt is flexible and allows for either implementation.

Is that about right?

@chrisnc
Copy link
Contributor Author

chrisnc commented Feb 20, 2022

@ChrisDenton yes that's most of it. I believe that this patch as-is does fix setsockopt on all versions of Wine while still working correctly for Windows, but now the problem is getsockopt, where Rust asserts that the output value of *option_len (the POSIX name for it) does not change.

Windows will accept >= 1 byte for setsockopt and getsockopt, and then for getsockopt, it will set *optlen (the Windows name for it) to 1, even if it was passed in as 4. (This is evident from the failing assertion in the test, but I'm still working on getting my Windows environment set up and getting a working example to reproduce this.) I've been in contact with the Wine maintainers who made the recent change, and they're also interested in matching the behavior of Windows on the final value of *optlen for getsockopt.

I have patches to fix up the parameter names and to remove the assertion, but I wanted to get some feedback on whether this is the right path. I can push them here for review shortly. I'm not sure if there's a better way to check for mismatched sizes in a way that is more permissive but still useful; the getsockopt interface is pretty cavalier about what happens when the sizes don't match. POSIX says that if *option_len is smaller than the size of the value, for example, that the value will just be truncated, and then if it's larger, that *option_len will be set to the actual (smaller) size, which is what Windows is doing here, even though Windows documents that the type is BOOL (int). Kind of a mess.

Previously `level` was named `opt` and `option_name` was named `val`,
then extra names of `payload` or `slot` were used for the option value.
This change aligns the wrapper parameters with their names in POSIX.
Winsock uses similar but more abbreviated names: `level`, `optname`,
`optval`, `optlen`.
POSIX allows `getsockopt` to set `*option_len` to a smaller value if
necessary. Windows will set `*option_len` to 1 for boolean options even
when the caller passes a `BOOL` (`int`) with `*option_len` as 4.
This issue was found by the Wine project and mitigated there [1].

Windows' documented interface for `setsockopt` expects a `BOOL` (a
`typedef` for `int`) for `TCP_NODELAY` [2]. Windows is forgiving and
will accept any positive length and interpret the first byte of
`*option_value` as the value, so this bug does not affect Windows
itself, but does affect systems implementing Windows' interface more
strictly, such as Wine. Wine was previously passing this through to the
host's `setsockopt`, where, e.g., Linux requires that `option_len` be
correct for the chosen option, and `TCP_NODELAY` expects an `int`.

[1]: https://source.winehq.org/git/wine.git/commit/d6ea38f32dfd3edbe107a255c37e9f7f3da06ae7
[2]: https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-setsockopt
@chrisnc
Copy link
Contributor Author

chrisnc commented Feb 21, 2022

I've put two commits ahead of the original one. Appreciate any feedback, particularly on removing the assert.

@chrisnc chrisnc marked this pull request as ready for review February 21, 2022 06:42
@chrisnc chrisnc requested a review from dtolnay February 21, 2022 06:42
@chrisnc
Copy link
Contributor Author

chrisnc commented Feb 25, 2022

r? rust-lang/libs

@rust-highfive rust-highfive assigned kennytm and unassigned dtolnay Feb 25, 2022
@dtolnay
Copy link
Member

dtolnay commented Feb 28, 2022

@bors r+

@bors
Copy link
Contributor

bors commented Feb 28, 2022

📌 Commit b02698c has been approved by dtolnay

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Feb 28, 2022
@dtolnay dtolnay assigned dtolnay and unassigned kennytm Feb 28, 2022
bors added a commit to rust-lang-ci/rust that referenced this pull request Mar 1, 2022
Rollup of 7 pull requests

Successful merges:

 - rust-lang#91545 (Generalize "remove `&`"  and "add `*`" suggestions to more than one deref)
 - rust-lang#93385 (Rustdoc ty consistency fixes)
 - rust-lang#93926 (Lint against more useless `#[must_use]` attributes)
 - rust-lang#94094 (use BOOL for TCP_NODELAY setsockopt value on Windows)
 - rust-lang#94384 (Add Atomic*::from_mut_slice)
 - rust-lang#94448 (5 - Make more use of `let_chains`)
 - rust-lang#94452 (Sync portable-simd for bitmasks &c.)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 06d47a4 into rust-lang:master Mar 1, 2022
@rustbot rustbot added this to the 1.61.0 milestone Mar 1, 2022
@chrisnc chrisnc deleted the tcp-nodelay-windows-bool branch April 20, 2023 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
O-windows Operating system: Windows S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TCP_NODELAY setsockopt uses BYTE on Windows when it should use BOOL
8 participants