Skip to content

Commit 0836e00

Browse files
authored
Rollup merge of rust-lang#94094 - chrisnc:tcp-nodelay-windows-bool, r=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
2 parents bb44c3d + 4e28741 commit 0836e00

File tree

2 files changed

+26
-11
lines changed

2 files changed

+26
-11
lines changed

std/src/sys/windows/net.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -407,11 +407,11 @@ impl Socket {
407407
}
408408

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

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

std/src/sys_common/net.rs

+24-9
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,36 @@ cfg_if::cfg_if! {
5858
// sockaddr and misc bindings
5959
////////////////////////////////////////////////////////////////////////////////
6060

61-
pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int, payload: T) -> io::Result<()> {
61+
pub fn setsockopt<T>(
62+
sock: &Socket,
63+
level: c_int,
64+
option_name: c_int,
65+
option_value: T,
66+
) -> io::Result<()> {
6267
unsafe {
63-
let payload = &payload as *const T as *const c_void;
64-
cvt(c::setsockopt(sock.as_raw(), opt, val, payload, mem::size_of::<T>() as c::socklen_t))?;
68+
cvt(c::setsockopt(
69+
sock.as_raw(),
70+
level,
71+
option_name,
72+
&option_value as *const T as *const _,
73+
mem::size_of::<T>() as c::socklen_t,
74+
))?;
6575
Ok(())
6676
}
6777
}
6878

69-
pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int, val: c_int) -> io::Result<T> {
79+
pub fn getsockopt<T: Copy>(sock: &Socket, level: c_int, option_name: c_int) -> io::Result<T> {
7080
unsafe {
71-
let mut slot: T = mem::zeroed();
72-
let mut len = mem::size_of::<T>() as c::socklen_t;
73-
cvt(c::getsockopt(sock.as_raw(), opt, val, &mut slot as *mut _ as *mut _, &mut len))?;
74-
assert_eq!(len as usize, mem::size_of::<T>());
75-
Ok(slot)
81+
let mut option_value: T = mem::zeroed();
82+
let mut option_len = mem::size_of::<T>() as c::socklen_t;
83+
cvt(c::getsockopt(
84+
sock.as_raw(),
85+
level,
86+
option_name,
87+
&mut option_value as *mut T as *mut _,
88+
&mut option_len,
89+
))?;
90+
Ok(option_value)
7691
}
7792
}
7893

0 commit comments

Comments
 (0)