Skip to content

Commit 43ba0ed

Browse files
authored
Add capability to set TCP ACK Frequency on Windows (#638)
1 parent 9a30f4f commit 43ba0ed

3 files changed

Lines changed: 58 additions & 0 deletions

File tree

src/socket.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2280,6 +2280,14 @@ impl Socket {
22802280
)
22812281
}
22822282
}
2283+
2284+
/// On Windows this invokes the `SIO_TCP_SET_ACK_FREQUENCY` IOCTL which
2285+
/// configures the number of TCP segments that must be received before
2286+
/// the delayed ACK timer is ignored.
2287+
#[cfg(all(feature = "all", windows))]
2288+
pub fn set_tcp_ack_frequency(&self, frequency: u8) -> io::Result<()> {
2289+
sys::set_tcp_ack_frequency(self.as_raw(), frequency)
2290+
}
22832291
}
22842292

22852293
impl Read for Socket {

src/sys/windows.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ use windows_sys::Win32::Networking::WinSock::{
2727
SOCKET_ERROR, WSABUF, WSAEMSGSIZE, WSAESHUTDOWN, WSAPOLLFD, WSAPROTOCOL_INFOW,
2828
WSA_FLAG_NO_HANDLE_INHERIT, WSA_FLAG_OVERLAPPED, WSA_FLAG_REGISTERED_IO,
2929
};
30+
31+
#[cfg(feature = "all")]
32+
use windows_sys::Win32::Networking::WinSock::{
33+
SIO_TCP_SET_ACK_FREQUENCY, TCP_ACK_FREQUENCY_PARAMETERS,
34+
};
35+
3036
#[cfg(feature = "all")]
3137
use windows_sys::Win32::Networking::WinSock::{
3238
IP6T_SO_ORIGINAL_DST, SOL_IP, SO_ORIGINAL_DST, SO_PROTOCOL_INFOW,
@@ -798,6 +804,31 @@ pub(crate) fn set_tcp_keepalive(socket: RawSocket, keepalive: &TcpKeepalive) ->
798804
Ok(())
799805
}
800806

807+
#[cfg(feature = "all")]
808+
pub(crate) fn set_tcp_ack_frequency(socket: RawSocket, frequency: u8) -> io::Result<()> {
809+
let mut freq_params = TCP_ACK_FREQUENCY_PARAMETERS {
810+
TcpDelayedAckFrequency: frequency,
811+
};
812+
813+
let mut out = 0;
814+
syscall!(
815+
WSAIoctl(
816+
socket,
817+
SIO_TCP_SET_ACK_FREQUENCY,
818+
&mut freq_params as *mut _ as *mut _,
819+
size_of::<TCP_ACK_FREQUENCY_PARAMETERS>() as _,
820+
ptr::null_mut(),
821+
0,
822+
&mut out,
823+
ptr::null_mut(),
824+
None,
825+
),
826+
PartialEq::eq,
827+
SOCKET_ERROR
828+
)
829+
.map(|_| ())
830+
}
831+
801832
/// Caller must ensure `T` is the correct type for `level` and `optname`.
802833
// NOTE: `optname` is actually `i32`, but all constants are `u32`.
803834
pub(crate) unsafe fn getsockopt<T>(socket: RawSocket, level: c_int, optname: i32) -> io::Result<T> {

tests/socket.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1824,6 +1824,25 @@ fn tcp_congestion() {
18241824
);
18251825
}
18261826

1827+
#[test]
1828+
#[cfg(all(feature = "all", windows))]
1829+
fn tcp_set_ack_frequency() {
1830+
let socket = Socket::new(Domain::IPV4, Type::STREAM, Some(Protocol::TCP)).unwrap();
1831+
match socket.set_tcp_ack_frequency(1) {
1832+
Ok(_) => {}
1833+
Err(err) => panic!("set_tcp_ack_frequency on tcp socket should succeed, error: {err}"),
1834+
}
1835+
1836+
let socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP)).unwrap();
1837+
match socket.set_tcp_ack_frequency(1) {
1838+
Ok(_) => panic!("set_tcp_ack_frequency on udp socket should fail"),
1839+
Err(err) => assert_eq!(
1840+
err.raw_os_error(),
1841+
Some(windows_sys::Win32::Networking::WinSock::WSAEOPNOTSUPP)
1842+
),
1843+
}
1844+
}
1845+
18271846
#[test]
18281847
#[ignore = "DCCP support is not enabled in all kernels of majors Linux distros"]
18291848
#[cfg(all(feature = "all", target_os = "linux"))]

0 commit comments

Comments
 (0)