-
Notifications
You must be signed in to change notification settings - Fork 251
Description
Hello,
I'm building a testing-tool on top of isahc and couldn't figure out some odd behaviour around the TCP connection as detailed here and here.
I finally narrowed it to down to the TCP socket not having the option TCP_NODELAY set on it even though the Rust program explicity sets this. I used strace and knetstat to verify this. I'm able to reproduce the issue locally with the following simple example:
Setup:
OS: Debian 4.19.171-2
OpenSSL 1.1.1d
Cargo.toml:
[dependencies]
curl = "0.4.34"
Rust program:
use curl::easy::Easy;
fn main() {
let mut easy = Easy::new();
easy.verbose(true);
easy.tcp_nodelay(true).unwrap();
easy.url("https://www.example.org/").unwrap();
easy.perform().unwrap();
println!("{}", easy.response_code().unwrap());
}
Curl command(for comparison):
# curl --version
curl 7.64.0 (x86_64-pc-linux-gnu) libcurl/7.64.0 OpenSSL/1.1.1d zlib/1.2.11 libidn2/2.0.5 libpsl/0.20.2 (+libidn2/2.0.5) libssh2/1.8.0 nghttp2/1.36.0 librtmp/2.3
Release-Date: 2019-02-06
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL
#curl -v https://www.example.org/
Note: curl has TCP_NODELAY on by default now
Differences between cargo run and curl command
stdout
cargo run
* Trying 93.184.216.34:443...
* Connected to www.example.org (93.184.216.34) port 443 (#0)
curl
* Trying 93.184.216.34... * TCP_NODELAY set * Connected to www.example.org (93.184.216.34) port 443 (#0)
knetstat
cargo run
0 523 10.140.0.2:48106 93.184.216.34:443 ESTB ># SO_REUSEADDR=0,SO_REUSEPORT=0,SO_KEEPALIVE=0,TCP_NODELAY=0,TCP_DEFER_ACCEPT=0
curl
0 523 10.140.0.2:48190 93.184.216.34:443 ESTB ># SO_REUSEADDR=0,SO_REUSEPORT=0,SO_KEEPALIVE=1,TCP_KEEPIDLE=60,TCP_KEEPINTVL=60,TCP_NODELAY=1,TCP_DEFER_ACCEPT=0
strace
cargo run
# strace -f -tt cargo run 2>&1 | grep sock
11:09:49.017727 socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_TCP) = 5
11:09:49.144278 getsockopt(5, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
11:09:49.145171 getsockname(5, {sa_family=AF_INET, sin_port=htons(48204), sin_addr=inet_addr("10.140.0.2")}, [256->16]) = 0
curl
# strace -f -tt curl -v https://www.example.org/ 2>&1 | grep sock
11:07:42.346046 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
11:07:42.346623 setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0
11:07:42.347039 setsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
11:07:42.347091 setsockopt(3, SOL_TCP, TCP_KEEPIDLE, [60], 4) = 0
11:07:42.347301 setsockopt(3, SOL_TCP, TCP_KEEPINTVL, [60], 4) = 0
11:07:42.473227 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
11:07:42.473664 getsockname(3, {sa_family=AF_INET, sin_port=htons(48198), sin_addr=inet_addr("10.140.0.2")}, [128->16]) = 0
The curl-rust implementation here and here look the same as every other option and I've double-checked that the code 121 is correct. I'm not sure why the options are not getting set on the socket though.
Is my usage of easy.tcp_nodelay(true) incorrect in the sample program?
Can you please try to reproduce this issue too?
/cc @sagebind (sort of related to sagebind/isahc#303)