Skip to content

TCP_FASTOPEN option for Socket #336

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Merge branch 'master' into master
  • Loading branch information
zonyitoo authored Mar 26, 2025
commit 9c448a4c93347e220bd03cd30063a24f9c34c5dc
202 changes: 202 additions & 0 deletions tests/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1585,6 +1585,40 @@ fn header_included() {
assert_eq!(got, true, "set and get values differ");
}

#[test]
#[cfg(all(
feature = "all",
not(any(
target_os = "redox",
target_os = "espidf",
target_os = "openbsd",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd"
))
))]
fn header_included_ipv6() {
let socket = match Socket::new(Domain::IPV6, Type::RAW, None) {
Ok(socket) => socket,
// Need certain permissions to create a raw sockets.
Err(ref err) if err.kind() == io::ErrorKind::PermissionDenied => return,
#[cfg(unix)]
Err(ref err) if err.raw_os_error() == Some(libc::EPROTONOSUPPORT) => return,
Err(err) => panic!("unexpected error creating socket: {}", err),
};

let initial = socket
.header_included_v6()
.expect("failed to get initial value");
assert_eq!(initial, false, "initial value and argument are the same");

socket
.set_header_included_v6(true)
.expect("failed to set option");
let got = socket.header_included_v6().expect("failed to get value");
assert_eq!(got, true, "set and get values differ");
}

#[test]
#[cfg(any(
target_os = "linux",
Expand Down Expand Up @@ -1614,3 +1648,171 @@ fn tcp_fastopen() {
assert_ne!(socket.tcp_fastopen().unwrap(), 0);
}
}

#[test]
#[cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
target_os = "windows"
)
))]
fn original_dst() {
let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
#[cfg(not(target_os = "windows"))]
let expected = Some(libc::ENOENT);
#[cfg(target_os = "windows")]
let expected = Some(windows_sys::Win32::Networking::WinSock::WSAEINVAL);

match socket.original_dst() {
Ok(_) => panic!("original_dst on non-redirected socket should fail"),
Err(err) => assert_eq!(err.raw_os_error(), expected),
}

let socket = Socket::new(Domain::IPV6, Type::STREAM, None).unwrap();
match socket.original_dst() {
Ok(_) => panic!("original_dst on non-redirected socket should fail"),
Err(err) => assert_eq!(err.raw_os_error(), expected),
}
}

#[test]
#[cfg(all(
feature = "all",
any(target_os = "android", target_os = "fuchsia", target_os = "linux")
))]
fn original_dst_ipv6() {
let socket = Socket::new(Domain::IPV6, Type::STREAM, None).unwrap();
#[cfg(not(target_os = "windows"))]
let expected = Some(libc::ENOENT);
#[cfg(target_os = "windows")]
let expected = Some(windows_sys::Win32::Networking::WinSock::WSAEINVAL);
#[cfg(not(target_os = "windows"))]
let expected_v4 = Some(libc::EOPNOTSUPP);
#[cfg(target_os = "windows")]
let expected_v4 = Some(windows_sys::Win32::Networking::WinSock::WSAEINVAL);
match socket.original_dst_ipv6() {
Ok(_) => panic!("original_dst_ipv6 on non-redirected socket should fail"),
Err(err) => assert_eq!(err.raw_os_error(), expected),
}

// Not supported on IPv4 socket.
let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
match socket.original_dst_ipv6() {
Ok(_) => panic!("original_dst_ipv6 on non-redirected socket should fail"),
Err(err) => assert_eq!(err.raw_os_error(), expected_v4),
}
}

#[test]
#[cfg(all(feature = "all", any(target_os = "freebsd", target_os = "linux")))]
fn tcp_congestion() {
let socket: Socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
// Get and set current tcp_ca
let origin_tcp_ca = socket
.tcp_congestion()
.expect("failed to get tcp congestion algorithm");
socket
.set_tcp_congestion(&origin_tcp_ca)
.expect("failed to set tcp congestion algorithm");
// Return a Err when set a non-exist tcp_ca
socket
.set_tcp_congestion(b"tcp_congestion_does_not_exist")
.unwrap_err();
let cur_tcp_ca = socket.tcp_congestion().unwrap();
assert_eq!(
cur_tcp_ca, origin_tcp_ca,
"expected {origin_tcp_ca:?} but get {cur_tcp_ca:?}"
);
let cur_tcp_ca = cur_tcp_ca.splitn(2, |num| *num == 0).next().unwrap();
const OPTIONS: [&[u8]; 2] = [
b"cubic",
#[cfg(target_os = "linux")]
b"reno",
#[cfg(target_os = "freebsd")]
b"newreno",
];
// Set a new tcp ca
#[cfg(target_os = "linux")]
let new_tcp_ca = if cur_tcp_ca == OPTIONS[0] {
OPTIONS[1]
} else {
OPTIONS[0]
};
#[cfg(target_os = "freebsd")]
let new_tcp_ca = OPTIONS[1];
socket.set_tcp_congestion(new_tcp_ca).unwrap();
// Check if new tcp ca is successfully set
let cur_tcp_ca = socket.tcp_congestion().unwrap();
assert_eq!(
cur_tcp_ca.splitn(2, |num| *num == 0).next().unwrap(),
new_tcp_ca,
);
}

#[test]
#[ignore = "DCCP support is not enabled in all kernels of majors Linux distros"]
#[cfg(all(feature = "all", target_os = "linux"))]
fn dccp() {
let listener = Socket::new(Domain::IPV4, Type::DCCP, Some(Protocol::DCCP)).unwrap();
let addr = "127.0.0.1:0".parse::<SocketAddr>().unwrap().into();
listener.set_dccp_service(45).unwrap();
assert!(listener.dccp_service().unwrap() == 45);
assert!(listener.dccp_cur_mps().unwrap() > 0);
assert!(listener.dccp_available_ccids::<4>().unwrap().len() >= 3);
assert!(
listener.dccp_send_cscov().unwrap() == 0,
"sender cscov should be zero by default"
);
listener.set_dccp_ccid(2).unwrap();
listener.set_dccp_qpolicy_txqlen(6).unwrap();
assert!(listener.dccp_qpolicy_txqlen().unwrap() == 6);
listener.bind(&addr).unwrap();
listener.listen(10).unwrap();

let mut client = Socket::new(Domain::IPV4, Type::DCCP, Some(Protocol::DCCP)).unwrap();
client.set_dccp_service(45).unwrap();
client.connect(&addr).unwrap();

let (mut accepted, _) = listener.accept().unwrap();
let msg = "Hello World!";
assert!(client.write(msg.as_bytes()).unwrap() == msg.len());
let mut recv_buf = [0_u8; 64];
assert!(accepted.read(&mut recv_buf).unwrap() == msg.len());
}

#[test]
#[cfg(all(feature = "all", target_os = "linux"))]
fn cookie() {
let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
let first_socket_cookie = socket.cookie();
match first_socket_cookie {
Ok(_) => {}
Err(err) => panic!("Could not get socket cookie, err: {err}"),
}

//Fetch cookie again and make sure it's the same value (ALWAYS should be, smoke test)
let second_socket_cookie = socket.cookie();
match second_socket_cookie {
Ok(cookie) => assert_eq!(cookie, first_socket_cookie.unwrap()),
Err(err) => panic!("Could not get socket cookie a second time, err: {err}"),
}
}

#[cfg(all(unix, target_os = "linux"))]
#[test]
fn set_passcred() {
let socket = Socket::new(Domain::UNIX, Type::DGRAM, None).unwrap();
assert!(!socket.passcred().unwrap());

socket.set_passcred(true).unwrap();
assert!(socket.passcred().unwrap());

let socket = Socket::new(Domain::UNIX, Type::STREAM, None).unwrap();
assert!(!socket.passcred().unwrap());

socket.set_passcred(true).unwrap();
assert!(socket.passcred().unwrap());
}
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.