Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/2603.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added the TcpMaxSeg `setsockopt` option for apple targets
2 changes: 1 addition & 1 deletion src/sys/socket/sockopt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ sockopt_impl!(
u32
);
cfg_if! {
if #[cfg(linux_android)] {
if #[cfg(any(linux_android, apple_targets))] {
sockopt_impl!(
/// The maximum segment size for outgoing TCP packets.
TcpMaxSeg, Both, libc::IPPROTO_TCP, libc::TCP_MAXSEG, u32);
Expand Down
45 changes: 30 additions & 15 deletions test/sys/test_sockopt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ fn test_so_tcp_maxseg() {
use nix::sys::socket::{
accept, bind, connect, getsockname, listen, Backlog, SockaddrIn,
};
use nix::unistd::write;
use std::net::SocketAddrV4;
use std::str::FromStr;

Expand All @@ -184,14 +183,12 @@ fn test_so_tcp_maxseg() {
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
// than `segsize`
let segsize: u32 = 873;
assert!(initial < segsize);
cfg_if! {
if #[cfg(linux_android)] {
let segsize: u32 = 873;
assert!(initial < segsize);
setsockopt(&rsock, sockopt::TcpMaxSeg, &segsize).unwrap();
} else {
assert!(initial < 700);
}
}

Expand All @@ -203,20 +200,38 @@ fn test_so_tcp_maxseg() {
SockProtocol::Tcp,
)
.unwrap();

connect(ssock.as_raw_fd(), &sock_addr).unwrap();

let rsess = accept(rsock.as_raw_fd()).unwrap();
let rsess = unsafe { OwnedFd::from_raw_fd(rsess) };
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(linux_android)] {
assert!((segsize - 100) <= actual);
assert!(actual <= segsize);
if #[cfg(apple_targets)] {
// on apple targets (and unlike linux), we can only set the MSS on a *connected*
// socket. Also, the same MSS can't be read using getsockopt from the other end.

assert_ne!(segsize, getsockopt(&rsess, sockopt::TcpMaxSeg).unwrap());
setsockopt(&rsess, sockopt::TcpMaxSeg, &segsize).unwrap();
assert_eq!(segsize, getsockopt(&rsess, sockopt::TcpMaxSeg).unwrap());

assert_ne!(segsize, getsockopt(&ssock, sockopt::TcpMaxSeg).unwrap());
setsockopt(&ssock, sockopt::TcpMaxSeg, &segsize).unwrap();
assert_eq!(segsize, getsockopt(&ssock, sockopt::TcpMaxSeg).unwrap());
} else {
assert!(initial < actual);
assert!(536 < actual);
use nix::unistd::write;

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.
if cfg!(linux_android) {
assert!((segsize - 100) <= actual);
assert!(actual <= segsize);
} else {
assert!(initial < actual);
assert!(536 < actual);
}
}
}
}
Expand Down