From 3eb983ed9916147ad4f2d93679cbff5276ca87ca Mon Sep 17 00:00:00 2001 From: Chris Copeland Date: Sat, 19 Feb 2022 12:05:51 -0800 Subject: [PATCH 1/3] Fix `setsockopt` and `getsockopt` parameter names. 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`. --- library/std/src/sys_common/net.rs | 34 +++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 70b29d4a92ed5..ede34c832e72f 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -58,21 +58,37 @@ cfg_if::cfg_if! { // sockaddr and misc bindings //////////////////////////////////////////////////////////////////////////////// -pub fn setsockopt(sock: &Socket, opt: c_int, val: c_int, payload: T) -> io::Result<()> { +pub fn setsockopt( + 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::() as c::socklen_t))?; + cvt(c::setsockopt( + sock.as_raw(), + level, + option_name, + &option_value as *const T as *const _, + mem::size_of::() as c::socklen_t, + ))?; Ok(()) } } -pub fn getsockopt(sock: &Socket, opt: c_int, val: c_int) -> io::Result { +pub fn getsockopt(sock: &Socket, level: c_int, option_name: c_int) -> io::Result { unsafe { - let mut slot: T = mem::zeroed(); - let mut len = mem::size_of::() 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::()); - Ok(slot) + let mut option_value: T = mem::zeroed(); + let mut option_len = mem::size_of::() as c::socklen_t; + cvt(c::getsockopt( + sock.as_raw(), + level, + option_name, + &mut option_value as *mut T as *mut _, + &mut option_len, + ))?; + assert_eq!(option_len as usize, mem::size_of::()); + Ok(option_value) } } From f2ebd0a11fd7ed131d669fcac20fa3b8df642f39 Mon Sep 17 00:00:00 2001 From: Chris Copeland Date: Sat, 19 Feb 2022 12:08:06 -0800 Subject: [PATCH 2/3] Remove assertion on output length for `getsockopt`. 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. --- library/std/src/sys_common/net.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index ede34c832e72f..3b7cdd55a081c 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -87,7 +87,6 @@ pub fn getsockopt(sock: &Socket, level: c_int, option_name: c_int) -> i &mut option_value as *mut T as *mut _, &mut option_len, ))?; - assert_eq!(option_len as usize, mem::size_of::()); Ok(option_value) } } From b02698c7e6843d6feacc394cb7f83f3fc347c3e2 Mon Sep 17 00:00:00 2001 From: Chris Copeland Date: Wed, 16 Feb 2022 22:02:58 -0800 Subject: [PATCH 3/3] use `BOOL` for `TCP_NODELAY` `setsockopt` value on Windows 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 --- library/std/src/sys/windows/net.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index aa6400aeefa0d..5de1231378488 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -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 { - 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) }