rust
rust copied to clipboard
Setting TCP_NODELAY does not work using std::net::TcpStream
I tried this code:
// Wi-Fi setup, etc....
let s = std::net::TcpStream::connect(("example.com", 80))?;
log::info!("socket connected");
if let Err(e) = s.set_nodelay(true) {
log::error!("nodelay error: {e:?}");
};
I expected to see this happen: the socket should have been put in nodelay mode without issue.
Instead, this happened:
I (5067) myproject: socket connected
E (5067) myproject: nodelay error: Os { code: 109, kind: Uncategorized, message: "Protocol not available" }
The TCP_NODELAY option should be supported: https://docs.espressif.com/projects/esp-idf/en/v5.2.1/esp32/api-guides/lwip.html#tcp-options
Meta
rustc --version --verbose:
rustc 1.77.0-nightly (424037dcb 2024-03-18) (1.77.0.0)
binary: rustc
commit-hash: 424037dcb6937656992747c4bbff310c40061498
commit-date: 2024-03-18
host: x86_64-unknown-linux-gnu
release: 1.77.0-nightly
LLVM version: 17.0.1
- ESP-IDF 5.2.1
- esp-idf-sys 0.34.1
- esp-idf-svc 0.48.1
- esp-idf-hal 0.43.1
I think I found the bug.
LWIP defines TCP_NODELAY as 1 in esp-idf/components/lwip/lwip/src/include/lwip/sockets.h:
#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
While Rust uses the libc::TCP_NODELAY with a value of 8193 defined by the libc crate in src/unix/newlib/mod.rs:
cfg_if! {
if #[cfg(target_os = "vita")] {
pub const TCP_NODELAY: ::c_int = 1;
pub const TCP_MAXSEG: ::c_int = 2;
} else {
pub const TCP_NODELAY: ::c_int = 8193;
pub const TCP_MAXSEG: ::c_int = 8194;
}
}
I found this pull request that would fix this issue on the libc crate repository: https://github.com/rust-lang/libc/pull/3345
I've hit the same, for now I've done this as a workaround
extern "C" {
fn lwip_setsockopt(fd: i32, level: i32, optname: i32);
}
unsafe {
lwip_setsockopt(
conn.as_raw_fd(),
6, // tcp https://github.com/stm32duino/LwIP/blob/main/src/lwip/sockets.h#L250
1, // nodelay https://github.com/stm32duino/LwIP/blob/main/src/lwip/sockets.h#L279
)
};