summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-09-08 00:23:26 +0000
committerGitHub <noreply@github.com>2021-09-08 00:23:26 +0000
commitccc1434960740dd0cb54e8141a22dd2ae920b956 (patch)
tree99ca384e66c39e5457c579190372b2018d3314f8
parent53fea96dd41926fb8527ac1ad35ada2ba106e454 (diff)
parentb06c26f16ff503523aa55adc7588bd3ff8088564 (diff)
downloadnix-ccc1434960740dd0cb54e8141a22dd2ae920b956.zip
Merge #1292
1292: Support `TCP_MAXSEG` TCP Maximum Segment Size socket options r=asomers a=eaon Found myself in a situation where I needed to advertise a specific MSS. Thought this crate is the appropriate place for this feature (especially since the `TCP_MAXSEG` const was exposed through it before), so here goes. Actual change is of course tiny but it comes with a test. Happy to make changes, especially since I need to do more research on which platforms this works. Co-authored-by: eaon <eaon@posteo.net> Co-authored-by: Alan Somers <asomers@gmail.com>
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/sys/socket/sockopt.rs7
-rw-r--r--test/sys/test_sockopt.rs51
3 files changed, 60 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a3b5b82a..04e37d28 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -34,6 +34,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
(#[1503](https://github.com/nix-rust/nix/pull/1503))
- Enabled `pwritev` and `preadv` for more operating systems.
(#[1511](https://github.com/nix-rust/nix/pull/1511))
+ Added support for `TCP_MAXSEG` TCP Maximum Segment Size socket options
+ (#[1292](https://github.com/nix-rust/nix/pull/1292))
- Added `Ipv4RecvErr` and `Ipv6RecvErr` sockopts and associated control messages.
(#[1514](https://github.com/nix-rust/nix/pull/1514))
- Added `AsRawFd` implementation on `PollFd`.
diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs
index 195479b6..17dd7568 100644
--- a/src/sys/socket/sockopt.rs
+++ b/src/sys/socket/sockopt.rs
@@ -265,6 +265,13 @@ sockopt_impl!(Both, TcpKeepAlive, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32);
target_os = "linux",
target_os = "nacl"))]
sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
+cfg_if! {
+ if #[cfg(any(target_os = "android", target_os = "linux"))] {
+ sockopt_impl!(Both, TcpMaxSeg, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
+ } else {
+ sockopt_impl!(GetOnly, TcpMaxSeg, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
+ }
+}
#[cfg(not(target_os = "openbsd"))]
sockopt_impl!(Both, TcpKeepCount, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32);
#[cfg(any(target_os = "android",
diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs
index 00514a84..45e969f4 100644
--- a/test/sys/test_sockopt.rs
+++ b/test/sys/test_sockopt.rs
@@ -70,6 +70,57 @@ fn test_so_buf() {
assert!(actual >= bufsize);
}
+#[test]
+fn test_so_tcp_maxseg() {
+ use std::net::SocketAddr;
+ use std::str::FromStr;
+ use nix::sys::socket::{accept, bind, connect, listen, InetAddr, SockAddr};
+ use nix::unistd::{close, write};
+
+ let std_sa = SocketAddr::from_str("127.0.0.1:4001").unwrap();
+ let inet_addr = InetAddr::from_std(&std_sa);
+ let sock_addr = SockAddr::new_inet(inet_addr);
+
+ let rsock = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp)
+ .unwrap();
+ bind(rsock, &sock_addr).unwrap();
+ listen(rsock, 10).unwrap();
+ let initial = getsockopt(rsock, sockopt::TcpMaxSeg).unwrap();
+ // Initial MSS is expected to be 536 (https://tools.ietf.org/html/rfc879#section-1) but some
+ // platforms keep it even lower. This might fail if you've tuned your initial MSS to be larger
+ // than 700
+ cfg_if! {
+ if #[cfg(any(target_os = "android", target_os = "linux"))] {
+ let segsize: u32 = 873;
+ assert!(initial < segsize);
+ setsockopt(rsock, sockopt::TcpMaxSeg, &segsize).unwrap();
+ } else {
+ assert!(initial < 700);
+ }
+ }
+
+ // Connect and check the MSS that was advertised
+ let ssock = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp)
+ .unwrap();
+ connect(ssock, &sock_addr).unwrap();
+ let rsess = accept(rsock).unwrap();
+ write(rsess, b"hello").unwrap();
+ let actual = getsockopt(ssock, sockopt::TcpMaxSeg).unwrap();
+ // Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max
+ // TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary.
+ cfg_if! {
+ if #[cfg(any(target_os = "android", target_os = "linux"))] {
+ assert!((segsize - 100) <= actual);
+ assert!(actual <= segsize);
+ } else {
+ assert!(initial < actual);
+ assert!(536 < actual);
+ }
+ }
+ close(rsock).unwrap();
+ close(ssock).unwrap();
+}
+
// The CI doesn't supported getsockopt and setsockopt on emulated processors.
// It's beleived that a QEMU issue, the tests run ok on a fully emulated system.
// Current CI just run the binary with QEMU but the Kernel remains the same as the host.