Skip to content

Commit ccc1434

Browse files
bors[bot]eaonasomers
authored
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 <[email protected]> Co-authored-by: Alan Somers <[email protected]>
2 parents 53fea96 + b06c26f commit ccc1434

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
3434
(#[1503](https://github.com/nix-rust/nix/pull/1503))
3535
- Enabled `pwritev` and `preadv` for more operating systems.
3636
(#[1511](https://github.com/nix-rust/nix/pull/1511))
37+
Added support for `TCP_MAXSEG` TCP Maximum Segment Size socket options
38+
(#[1292](https://github.com/nix-rust/nix/pull/1292))
3739
- Added `Ipv4RecvErr` and `Ipv6RecvErr` sockopts and associated control messages.
3840
(#[1514](https://github.com/nix-rust/nix/pull/1514))
3941
- Added `AsRawFd` implementation on `PollFd`.

src/sys/socket/sockopt.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,13 @@ sockopt_impl!(Both, TcpKeepAlive, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32);
265265
target_os = "linux",
266266
target_os = "nacl"))]
267267
sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
268+
cfg_if! {
269+
if #[cfg(any(target_os = "android", target_os = "linux"))] {
270+
sockopt_impl!(Both, TcpMaxSeg, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
271+
} else {
272+
sockopt_impl!(GetOnly, TcpMaxSeg, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
273+
}
274+
}
268275
#[cfg(not(target_os = "openbsd"))]
269276
sockopt_impl!(Both, TcpKeepCount, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32);
270277
#[cfg(any(target_os = "android",

test/sys/test_sockopt.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,57 @@ fn test_so_buf() {
7070
assert!(actual >= bufsize);
7171
}
7272

73+
#[test]
74+
fn test_so_tcp_maxseg() {
75+
use std::net::SocketAddr;
76+
use std::str::FromStr;
77+
use nix::sys::socket::{accept, bind, connect, listen, InetAddr, SockAddr};
78+
use nix::unistd::{close, write};
79+
80+
let std_sa = SocketAddr::from_str("127.0.0.1:4001").unwrap();
81+
let inet_addr = InetAddr::from_std(&std_sa);
82+
let sock_addr = SockAddr::new_inet(inet_addr);
83+
84+
let rsock = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp)
85+
.unwrap();
86+
bind(rsock, &sock_addr).unwrap();
87+
listen(rsock, 10).unwrap();
88+
let initial = getsockopt(rsock, sockopt::TcpMaxSeg).unwrap();
89+
// Initial MSS is expected to be 536 (https://tools.ietf.org/html/rfc879#section-1) but some
90+
// platforms keep it even lower. This might fail if you've tuned your initial MSS to be larger
91+
// than 700
92+
cfg_if! {
93+
if #[cfg(any(target_os = "android", target_os = "linux"))] {
94+
let segsize: u32 = 873;
95+
assert!(initial < segsize);
96+
setsockopt(rsock, sockopt::TcpMaxSeg, &segsize).unwrap();
97+
} else {
98+
assert!(initial < 700);
99+
}
100+
}
101+
102+
// Connect and check the MSS that was advertised
103+
let ssock = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp)
104+
.unwrap();
105+
connect(ssock, &sock_addr).unwrap();
106+
let rsess = accept(rsock).unwrap();
107+
write(rsess, b"hello").unwrap();
108+
let actual = getsockopt(ssock, sockopt::TcpMaxSeg).unwrap();
109+
// Actual max segment size takes header lengths into account, max IPv4 options (60 bytes) + max
110+
// TCP options (40 bytes) are subtracted from the requested maximum as a lower boundary.
111+
cfg_if! {
112+
if #[cfg(any(target_os = "android", target_os = "linux"))] {
113+
assert!((segsize - 100) <= actual);
114+
assert!(actual <= segsize);
115+
} else {
116+
assert!(initial < actual);
117+
assert!(536 < actual);
118+
}
119+
}
120+
close(rsock).unwrap();
121+
close(ssock).unwrap();
122+
}
123+
73124
// The CI doesn't supported getsockopt and setsockopt on emulated processors.
74125
// It's beleived that a QEMU issue, the tests run ok on a fully emulated system.
75126
// Current CI just run the binary with QEMU but the Kernel remains the same as the host.

0 commit comments

Comments
 (0)