Skip to content

Commit

Permalink
Rollup merge of #94094 - chrisnc:tcp-nodelay-windows-bool, r=dtolnay
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Dylan-DPC committed Mar 1, 2022
2 parents daed864 + b02698c commit 06d47a4
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 11 deletions.
4 changes: 2 additions & 2 deletions library/std/src/sys/windows/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,11 +407,11 @@ impl Socket {
}

pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BYTE)
net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL)
}

pub fn nodelay(&self) -> io::Result<bool> {
let raw: c::BYTE = net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?;
let raw: c::BOOL = net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?;
Ok(raw != 0)
}

Expand Down
33 changes: 24 additions & 9 deletions library/std/src/sys_common/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,36 @@ cfg_if::cfg_if! {
// sockaddr and misc bindings
////////////////////////////////////////////////////////////////////////////////

pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int, payload: T) -> io::Result<()> {
pub fn setsockopt<T>(
sock: &Socket,
level: c_int,
option_name: c_int,
option_value: T,
) -> io::Result<()> {
unsafe {
let payload = &payload as *const T as *const c_void;
cvt(c::setsockopt(sock.as_raw(), opt, val, payload, mem::size_of::<T>() as c::socklen_t))?;
cvt(c::setsockopt(
sock.as_raw(),
level,
option_name,
&option_value as *const T as *const _,
mem::size_of::<T>() as c::socklen_t,
))?;
Ok(())
}
}

pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int, val: c_int) -> io::Result<T> {
pub fn getsockopt<T: Copy>(sock: &Socket, level: c_int, option_name: c_int) -> io::Result<T> {
unsafe {
let mut slot: T = mem::zeroed();
let mut len = mem::size_of::<T>() as c::socklen_t;
cvt(c::getsockopt(sock.as_raw(), opt, val, &mut slot as *mut _ as *mut _, &mut len))?;
assert_eq!(len as usize, mem::size_of::<T>());
Ok(slot)
let mut option_value: T = mem::zeroed();
let mut option_len = mem::size_of::<T>() as c::socklen_t;
cvt(c::getsockopt(
sock.as_raw(),
level,
option_name,
&mut option_value as *mut T as *mut _,
&mut option_len,
))?;
Ok(option_value)
}
}

Expand Down

0 comments on commit 06d47a4

Please sign in to comment.