Fix the get/set-timeout getsockopt/getsockopt calls.

Qemu doesn't yet support `SO_RCVTIMEO_NEW`/`SO_SENDTIMEO_NEW`, and it
unfortunately returns a bogus int instead of properly failing. For now,
patch qemu to fail in this case. The qemu bug is now reported
upstream [here].

[here]: https://gitlab.com/qemu-project/qemu/-/issues/885

And, when converting from nanoseconds to microseconds for the `*_OLD`
calls, round up rather than rounding down, so that the resulting timeout
is at least as long as requested.

Make the time conversion in `set_socket_linger` round up.

And, add tests for `set_socket_linger` and several other sockopt calls.
This commit is contained in:
Dan Gohman
2022-02-28 09:03:31 -08:00
committed by GitHub
parent 483f3c7e59
commit 5cda795470
7 changed files with 365 additions and 33 deletions
+13 -7
View File
@@ -98,7 +98,7 @@ jobs:
- run: cargo check --workspace --release -vv --target=armv5te-unknown-linux-gnueabi
check_no_default_features:
name: Check
name: Check --no-default-features
runs-on: ${{ matrix.os }}
strategy:
matrix:
@@ -124,7 +124,7 @@ jobs:
- run: cargo check --workspace --release --no-default-features --features itoa -vv
check_nightly:
name: Check on Rust nightly
name: Check nightly-only targets
runs-on: ${{ matrix.os }}
strategy:
matrix:
@@ -340,7 +340,7 @@ jobs:
- uses: actions/cache@v2
with:
path: ${{ runner.tool_cache }}/qemu
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patched
if: matrix.target != '' && matrix.os == 'ubuntu-latest'
- name: Install cross-compilation tools
@@ -378,6 +378,8 @@ jobs:
cd
curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf -
cd qemu-$QEMU_BUILD_VERSION
patch -p1 < $GITHUB_WORKSPACE/ci/translate-errno.patch
patch -p1 < $GITHUB_WORKSPACE/ci/getsockopt-timeouts.patch
./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache }}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
ninja -C build install
if: matrix.qemu != '' && matrix.os == 'ubuntu-latest'
@@ -392,8 +394,8 @@ jobs:
# Check the prebuilt debug libraries too.
cargo check --features=cc
test_rustix_use_libc:
name: Test rustix_use_libc
test_use_libc:
name: Test use-libc
runs-on: ${{ matrix.os }}
strategy:
matrix:
@@ -482,7 +484,7 @@ jobs:
- uses: actions/cache@v2
with:
path: ${{ runner.tool_cache }}/qemu
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patched
if: matrix.target != '' && matrix.os == 'ubuntu-latest'
- name: Install cross-compilation tools
@@ -520,6 +522,8 @@ jobs:
cd
curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf -
cd qemu-$QEMU_BUILD_VERSION
patch -p1 < $GITHUB_WORKSPACE/ci/translate-errno.patch
patch -p1 < $GITHUB_WORKSPACE/ci/getsockopt-timeouts.patch
./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache }}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
ninja -C build install
if: matrix.qemu != '' && matrix.os == 'ubuntu-latest'
@@ -586,7 +590,7 @@ jobs:
- uses: actions/cache@v2
with:
path: ${{ runner.tool_cache }}/qemu
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patched
if: matrix.target != '' && matrix.os == 'ubuntu-latest'
- name: Install cross-compilation tools
@@ -624,6 +628,8 @@ jobs:
cd
curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf -
cd qemu-$QEMU_BUILD_VERSION
patch -p1 < $GITHUB_WORKSPACE/ci/translate-errno.patch
patch -p1 < $GITHUB_WORKSPACE/ci/getsockopt-timeouts.patch
./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache }}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
ninja -C build install
if: matrix.qemu != '' && matrix.os == 'ubuntu-latest'
+20 -7
View File
@@ -102,7 +102,7 @@ jobs:
- uses: actions/cache@v2
with:
path: ${{ runner.tool_cache }}/qemu
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patched
if: matrix.target != '' && matrix.os == 'ubuntu-latest'
- name: Install cross-compilation tools
@@ -141,6 +141,8 @@ jobs:
cd
curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf -
cd qemu-$QEMU_BUILD_VERSION
patch -p1 < $GITHUB_WORKSPACE/ci/translate-errno.patch
patch -p1 < $GITHUB_WORKSPACE/ci/getsockopt-timeouts.patch
./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache }}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
ninja -C build install
if: matrix.qemu != '' && matrix.os == 'ubuntu-latest'
@@ -256,7 +258,7 @@ jobs:
- uses: actions/cache@v2
with:
path: ${{ runner.tool_cache }}/qemu
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patcherrno
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patched
if: matrix.target != '' && matrix.os == 'ubuntu-latest'
- name: Install cross-compilation tools
@@ -295,6 +297,7 @@ jobs:
curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf -
cd qemu-$QEMU_BUILD_VERSION
patch -p1 < $GITHUB_WORKSPACE/ci/translate-errno.patch
patch -p1 < $GITHUB_WORKSPACE/ci/getsockopt-timeouts.patch
./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache }}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
ninja -C build install
if: matrix.qemu != '' && matrix.os == 'ubuntu-latest'
@@ -398,7 +401,7 @@ jobs:
- uses: actions/cache@v2
with:
path: ${{ runner.tool_cache }}/qemu
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patched
if: matrix.target != '' && matrix.os == 'ubuntu-latest'
- name: Install cross-compilation tools
@@ -436,6 +439,8 @@ jobs:
cd
curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf -
cd qemu-$QEMU_BUILD_VERSION
patch -p1 < $GITHUB_WORKSPACE/ci/translate-errno.patch
patch -p1 < $GITHUB_WORKSPACE/ci/getsockopt-timeouts.patch
./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache }}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
ninja -C build install
if: matrix.qemu != '' && matrix.os == 'ubuntu-latest'
@@ -568,7 +573,7 @@ jobs:
- uses: actions/cache@v2
with:
path: ${{ runner.tool_cache }}/qemu
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patched
if: matrix.target != '' && matrix.os == 'ubuntu-latest'
- name: Install cross-compilation tools
@@ -606,6 +611,8 @@ jobs:
cd
curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf -
cd qemu-$QEMU_BUILD_VERSION
patch -p1 < $GITHUB_WORKSPACE/ci/translate-errno.patch
patch -p1 < $GITHUB_WORKSPACE/ci/getsockopt-timeouts.patch
./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache }}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
ninja -C build install
if: matrix.qemu != '' && matrix.os == 'ubuntu-latest'
@@ -709,7 +716,7 @@ jobs:
- uses: actions/cache@v2
with:
path: ${{ runner.tool_cache }}/qemu
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patched
if: matrix.target != '' && matrix.os == 'ubuntu-latest'
- name: Install cross-compilation tools
@@ -747,6 +754,8 @@ jobs:
cd
curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf -
cd qemu-$QEMU_BUILD_VERSION
patch -p1 < $GITHUB_WORKSPACE/ci/translate-errno.patch
patch -p1 < $GITHUB_WORKSPACE/ci/getsockopt-timeouts.patch
./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache }}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
ninja -C build install
if: matrix.qemu != '' && matrix.os == 'ubuntu-latest'
@@ -850,7 +859,7 @@ jobs:
- uses: actions/cache@v2
with:
path: ${{ runner.tool_cache }}/qemu
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patched
if: matrix.target != '' && matrix.os == 'ubuntu-latest'
- name: Install cross-compilation tools
@@ -888,6 +897,8 @@ jobs:
cd
curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf -
cd qemu-$QEMU_BUILD_VERSION
patch -p1 < $GITHUB_WORKSPACE/ci/translate-errno.patch
patch -p1 < $GITHUB_WORKSPACE/ci/getsockopt-timeouts.patch
./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache }}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
ninja -C build install
if: matrix.qemu != '' && matrix.os == 'ubuntu-latest'
@@ -1054,7 +1065,7 @@ jobs:
- uses: actions/cache@v2
with:
path: ${{ runner.tool_cache }}/qemu
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}
key: qemu-${{ matrix.target }}-${{ env.QEMU_BUILD_VERSION }}-patched
if: matrix.target != '' && matrix.os == 'ubuntu-latest'
- name: Install cross-compilation tools
@@ -1092,6 +1103,8 @@ jobs:
cd
curl https://download.qemu.org/qemu-$QEMU_BUILD_VERSION.tar.xz | tar xJf -
cd qemu-$QEMU_BUILD_VERSION
patch -p1 < $GITHUB_WORKSPACE/ci/translate-errno.patch
patch -p1 < $GITHUB_WORKSPACE/ci/getsockopt-timeouts.patch
./configure --target-list=${{ matrix.qemu_target }} --prefix=${{ runner.tool_cache }}/qemu --disable-tools --disable-slirp --disable-fdt --disable-capstone --disable-docs
ninja -C build install
if: matrix.qemu != '' && matrix.os == 'ubuntu-latest'
+80
View File
@@ -0,0 +1,80 @@
From: Dan Gohman <dev@sunfishcode.online>
Subject: [PATCH] Avoid storing unexpected values for `SO_RCVTIMEO_NEW` etc.
This issue is reported upstream [here].
[here]: https://gitlab.com/qemu-project/qemu/-/issues/885
---
linux-user/generic/sockbits.h | 2 ++
linux-user/mips/sockbits.h | 2 ++
linux-user/sparc/sockbits.h | 2 ++
linux-user/syscall.c | 6 ++++++
4 files changed, 12 insertions(+)
diff --git a/linux-user/generic/sockbits.h b/linux-user/generic/sockbits.h
index b3b4a8e44c..f95747e3cc 100644
--- a/linux-user/generic/sockbits.h
+++ b/linux-user/generic/sockbits.h
@@ -36,6 +36,8 @@
#define TARGET_SO_SNDLOWAT 19
#define TARGET_SO_RCVTIMEO 20
#define TARGET_SO_SNDTIMEO 21
+#define TARGET_SO_RCVTIMEO_NEW 66
+#define TARGET_SO_SNDTIMEO_NEW 67
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define TARGET_SO_SECURITY_AUTHENTICATION 22
diff --git a/linux-user/mips/sockbits.h b/linux-user/mips/sockbits.h
index 562cad88e2..4d411f7b61 100644
--- a/linux-user/mips/sockbits.h
+++ b/linux-user/mips/sockbits.h
@@ -39,6 +39,8 @@
#define TARGET_SO_RCVLOWAT 0x1004 /* receive low-water mark */
#define TARGET_SO_SNDTIMEO 0x1005 /* send timeout */
#define TARGET_SO_RCVTIMEO 0x1006 /* receive timeout */
+#define TARGET_SO_RCVTIMEO_NEW 66
+#define TARGET_SO_SNDTIMEO_NEW 67
#define TARGET_SO_ACCEPTCONN 0x1009
#define TARGET_SO_PROTOCOL 0x1028 /* protocol type */
#define TARGET_SO_DOMAIN 0x1029 /* domain/socket family */
diff --git a/linux-user/sparc/sockbits.h b/linux-user/sparc/sockbits.h
index 0a822e3e1f..8420ef9953 100644
--- a/linux-user/sparc/sockbits.h
+++ b/linux-user/sparc/sockbits.h
@@ -26,6 +26,8 @@
#define TARGET_SO_SNDLOWAT 0x1000
#define TARGET_SO_RCVTIMEO 0x2000
#define TARGET_SO_SNDTIMEO 0x4000
+#define TARGET_SO_RCVTIMEO_NEW 68
+#define TARGET_SO_SNDTIMEO_NEW 69
#define TARGET_SO_ACCEPTCONN 0x8000
#define TARGET_SO_SNDBUF 0x1001
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index a8eae3c4ac..8326e03a19 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2348,6 +2348,9 @@ set_timeout:
case TARGET_SO_SNDTIMEO:
optname = SO_SNDTIMEO;
goto set_timeout;
+ case TARGET_SO_RCVTIMEO_NEW:
+ case TARGET_SO_SNDTIMEO_NEW:
+ return -TARGET_ENOPROTOOPT;
case TARGET_SO_ATTACH_FILTER:
{
struct target_sock_fprog *tfprog;
@@ -2595,6 +2598,9 @@ get_timeout:
case TARGET_SO_SNDTIMEO:
optname = SO_SNDTIMEO;
goto get_timeout;
+ case TARGET_SO_RCVTIMEO_NEW:
+ case TARGET_SO_SNDTIMEO_NEW:
+ return -TARGET_ENOPROTOOPT;
case TARGET_SO_PEERCRED: {
struct ucred cr;
socklen_t crlen;
--
2.32.0
+66 -17
View File
@@ -391,6 +391,8 @@ pub(crate) mod sockopt {
use crate::{as_mut_ptr, io};
use core::convert::TryInto;
use core::time::Duration;
#[cfg(windows)]
use winapi::shared::minwindef::DWORD;
// TODO: With Rust 1.53 we can use `Duration::ZERO` instead.
const DURATION_ZERO: Duration = Duration::from_secs(0);
@@ -467,13 +469,19 @@ pub(crate) mod sockopt {
fd: BorrowedFd<'_>,
linger: Option<Duration>,
) -> io::Result<()> {
// Convert `linger` to seconds, rounding up.
let l_linger = if let Some(linger) = linger {
let mut l_linger = linger.as_secs();
if linger.subsec_nanos() != 0 {
l_linger = l_linger.checked_add(1).ok_or(io::Error::INVAL)?;
}
l_linger.try_into().map_err(|_| io::Error::INVAL)?
} else {
0
};
let linger = c::linger {
l_onoff: linger.is_some() as _,
l_linger: linger
.unwrap_or_default()
.as_secs()
.try_into()
.map_err(|_convert_err| io::Error::INVAL)?,
l_linger,
};
setsockopt(fd, c::SOL_SOCKET as _, c::SO_LINGER, linger)
}
@@ -507,6 +515,12 @@ pub(crate) mod sockopt {
id: Timeout,
timeout: Option<Duration>,
) -> io::Result<()> {
let optname = match id {
Timeout::Recv => c::SO_RCVTIMEO,
Timeout::Send => c::SO_SNDTIMEO,
};
#[cfg(not(windows))]
let timeout = match timeout {
Some(timeout) => {
if timeout == DURATION_ZERO {
@@ -519,9 +533,11 @@ pub(crate) mod sockopt {
#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
let tv_sec = tv_sec.unwrap_or(i64::MAX);
// `subsec_micros` rounds down, so we use `subsec_nanos` and
// manually round up.
let mut timeout = c::timeval {
tv_sec,
tv_usec: timeout.subsec_micros() as _,
tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _,
};
if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
timeout.tv_usec = 1;
@@ -533,10 +549,29 @@ pub(crate) mod sockopt {
tv_usec: 0,
},
};
let optname = match id {
Timeout::Recv => c::SO_RCVTIMEO,
Timeout::Send => c::SO_SNDTIMEO,
#[cfg(windows)]
let timeout: DWORD = match timeout {
Some(timeout) => {
if timeout == DURATION_ZERO {
return Err(io::Error::INVAL);
}
let millis = timeout.as_millis();
// `as_millis` rounds down, so we use `as_nanos` and
// manually round up.
let mut timeout: DWORD = ((timeout.as_nanos() + 999999) / 1000000)
.try_into()
.map_err(|_convert_err| io::Error::INVAL)?;
if timeout == 0 {
timeout = 1;
}
timeout
}
None => 0,
};
setsockopt(fd, c::SOL_SOCKET, optname, timeout)
}
@@ -549,14 +584,28 @@ pub(crate) mod sockopt {
Timeout::Recv => c::SO_RCVTIMEO,
Timeout::Send => c::SO_SNDTIMEO,
};
let timeout: c::timeval = getsockopt(fd, c::SOL_SOCKET, optname)?;
if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
Ok(None)
} else {
Ok(Some(
Duration::from_secs(timeout.tv_sec as u64)
+ Duration::from_micros(timeout.tv_usec as u64),
))
#[cfg(not(windows))]
{
let timeout: c::timeval = getsockopt(fd, c::SOL_SOCKET, optname)?;
if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
Ok(None)
} else {
Ok(Some(
Duration::from_secs(timeout.tv_sec as u64)
+ Duration::from_micros(timeout.tv_usec as u64),
))
}
}
#[cfg(windows)]
{
let timeout: DWORD = getsockopt(fd, c::SOL_SOCKET, optname)?;
if timeout == 0 {
Ok(None)
} else {
Ok(Some(Duration::from_millis(timeout as u64)))
}
}
}
+16 -2
View File
@@ -849,6 +849,7 @@ pub(crate) mod sockopt {
out(&mut value),
by_mut(&mut optlen),
))?;
assert_eq!(
optlen as usize,
core::mem::size_of::<T>(),
@@ -955,9 +956,19 @@ pub(crate) mod sockopt {
fd: BorrowedFd<'_>,
linger: Option<Duration>,
) -> io::Result<()> {
// Convert `linger` to seconds, rounding up.
let l_linger = if let Some(linger) = linger {
let mut l_linger = linger.as_secs();
if linger.subsec_nanos() != 0 {
l_linger = l_linger.checked_add(1).ok_or(io::Error::INVAL)?;
}
l_linger.try_into().map_err(|_| io::Error::INVAL)?
} else {
0
};
let linger = linux_raw_sys::general::linger {
l_onoff: linger.is_some() as c::c_int,
l_linger: linger.unwrap_or_default().as_secs() as c::c_int,
l_linger,
};
setsockopt(
fd,
@@ -1119,9 +1130,12 @@ pub(crate) mod sockopt {
if timeout == DURATION_ZERO {
return Err(io::Error::INVAL);
}
// `subsec_micros` rounds down, so we use `subsec_nanos` and
// manually round up.
let mut timeout = timeval {
tv_sec: timeout.as_secs().try_into().unwrap_or(c::c_long::MAX),
tv_usec: timeout.subsec_micros() as _,
tv_usec: ((timeout.subsec_nanos() + 999) / 1000) as _,
};
if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
timeout.tv_usec = 1;
+1
View File
@@ -7,6 +7,7 @@
mod addr;
mod connect_bind_send;
mod poll;
mod sockopt;
#[cfg(unix)]
mod unix;
mod v4;
+169
View File
@@ -0,0 +1,169 @@
#[test]
fn test_sockopts() {
use rustix::net::{AddressFamily, Protocol, SocketType};
use std::time::Duration;
let s =
rustix::net::socket(AddressFamily::INET, SocketType::STREAM, Protocol::default()).unwrap();
// On a new socket we shouldn't have a timeout yet.
assert!(
rustix::net::sockopt::get_socket_timeout(&s, rustix::net::sockopt::Timeout::Recv)
.unwrap()
.is_none()
);
assert_eq!(
rustix::net::sockopt::get_socket_type(&s).unwrap(),
SocketType::STREAM
);
#[cfg(not(windows))]
assert_eq!(
rustix::net::sockopt::get_socket_broadcast(&s).unwrap(),
false
);
// On a new socket we shouldn't have a linger yet.
assert!(rustix::net::sockopt::get_socket_linger(&s)
.unwrap()
.is_none());
#[cfg(any(target_os = "android", target_os = "linux"))]
assert_eq!(
rustix::net::sockopt::get_socket_passcred(&s).unwrap(),
false
);
assert_ne!(rustix::net::sockopt::get_ip_ttl(&s).unwrap(), 0);
assert_ne!(rustix::net::sockopt::get_ip_ttl(&s).unwrap(), 77);
#[cfg(not(any(
windows,
target_os = "dragonfly",
target_os = "ios",
target_os = "freebsd",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
)))]
assert_eq!(
rustix::net::sockopt::get_ip_multicast_loop(&s).unwrap(),
true
);
#[cfg(not(any(
windows,
target_os = "dragonfly",
target_os = "ios",
target_os = "freebsd",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
)))]
assert_eq!(rustix::net::sockopt::get_ip_multicast_ttl(&s).unwrap(), 1);
assert_eq!(rustix::net::sockopt::get_tcp_nodelay(&s).unwrap(), false);
// Set a timeout.
rustix::net::sockopt::set_socket_timeout(
&s,
rustix::net::sockopt::Timeout::Recv,
Some(Duration::new(1, 1)),
)
.unwrap();
// Check that we have a timeout of at least the time we set.
if cfg!(not(target_os = "freebsd")) {
assert!(
rustix::net::sockopt::get_socket_timeout(&s, rustix::net::sockopt::Timeout::Recv)
.unwrap()
.unwrap()
>= Duration::new(1, 1)
);
} else {
// On FreeBSD <= 12, it appears the system rounds the timeout down.
assert!(
rustix::net::sockopt::get_socket_timeout(&s, rustix::net::sockopt::Timeout::Recv)
.unwrap()
.unwrap()
>= Duration::new(1, 0)
);
}
#[cfg(not(windows))]
{
// Set the broadcast flag;
rustix::net::sockopt::set_socket_broadcast(&s, true).unwrap();
// Check that the broadcast flag is set. This has no effect on stream
// sockets, and not all platforms even remember the value.
#[cfg(not(any(
target_os = "dragonfly",
target_os = "ios",
target_os = "freebsd",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
)))]
assert_eq!(
rustix::net::sockopt::get_socket_broadcast(&s).unwrap(),
true
);
}
// Set a linger.
rustix::net::sockopt::set_socket_linger(&s, Some(Duration::new(1, 1))).unwrap();
// Check that we have a linger of at least the time we set.
assert!(
dbg!(rustix::net::sockopt::get_socket_linger(&s)
.unwrap()
.unwrap())
>= Duration::new(1, 1)
);
#[cfg(any(target_os = "android", target_os = "linux"))]
{
// Set the passcred flag;
rustix::net::sockopt::set_socket_passcred(&s, true).unwrap();
// Check that the passcred flag is set.
assert_eq!(rustix::net::sockopt::get_socket_passcred(&s).unwrap(), true);
}
// Set the ip ttl.
rustix::net::sockopt::set_ip_ttl(&s, 77).unwrap();
// Check the ip ttl.
assert_eq!(rustix::net::sockopt::get_ip_ttl(&s).unwrap(), 77);
#[cfg(not(any(
windows,
target_os = "dragonfly",
target_os = "ios",
target_os = "freebsd",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
)))]
{
// Set the multicast loop flag;
rustix::net::sockopt::set_ip_multicast_loop(&s, false).unwrap();
// Check that the multicast loop flag is set.
assert_eq!(
rustix::net::sockopt::get_ip_multicast_loop(&s).unwrap(),
false
);
}
// Set the nodelay flag;
rustix::net::sockopt::set_tcp_nodelay(&s, true).unwrap();
// Check that the nodelay flag is set.
if cfg!(not(any(
target_os = "dragonfly",
target_os = "ios",
target_os = "freebsd",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
))) {
assert_eq!(rustix::net::sockopt::get_tcp_nodelay(&s).unwrap(), true);
} else {
assert_eq!(rustix::net::sockopt::get_tcp_nodelay(&s).unwrap(), false);
}
}