mirror of
https://github.com/openharmony/third_party_rust_rustix.git
synced 2026-07-01 20:54:01 -04:00
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:
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
mod addr;
|
||||
mod connect_bind_send;
|
||||
mod poll;
|
||||
mod sockopt;
|
||||
#[cfg(unix)]
|
||||
mod unix;
|
||||
mod v4;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user