I am observing a case on macOS where connect_timeout returns Ok(()) but the socket is not actually connected: peer_addr() (getpeername) immediately returns ENOTCONN.
Minimal reproducer:
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
use std::{net::SocketAddr, time::Duration};
fn main() {
let remote_addr = "[<remote-ipv6>]:443"
.parse::<SocketAddr>()
.unwrap();
let socket = Socket::new(Domain::IPV6, Type::STREAM, Some(Protocol::TCP)).unwrap();
socket
.connect_timeout(&SockAddr::from(remote_addr), Duration::from_secs(10))
.unwrap();
println!("connect_timeout returned Ok(())");
println!("peer_addr: {:?}", socket.peer_addr());
}
Output on the affected machine:
Socket connected
Err(Os { code: 57, kind: NotConnected, message: "Socket is not connected" })
Environment
- macOS
15.7.3 (aarch64)
socket2 0.6.3
- IPv6 TCP socket connecting to a remote server
- The machine has a global IPv6 address and a default IPv6 route via the physical interface
- A VPN is active that captures IPv4 traffic (via a utun interface) but does not carry IPv6
In that particular environment, decomposing Socket::connect_timeout step by step the issue is in the fast path (https://github.com/rust-lang/socket2/blob/master/src/socket.rs#L217). The non-blocking connect() call returns Ok(0) instead of Err(EINPROGRESS):
set_nonblocking(true)
connect() → Ok(()) ← should be Err(EINPROGRESS) for a remote TCP address
set_nonblocking(false)
// connect_timeout returns Ok(()) here, poll_connect is never called
This happens consistently (10/10 attempts) on this machine when the VPN is active.
The same network configuration on Linux works correctly: connect() returns EINPROGRESS in both cases (with or without VPN)
There's something I am missing about how connect_timeout should be used?
I am observing a case on macOS where
connect_timeoutreturnsOk(())but the socket is not actually connected:peer_addr()(getpeername) immediately returnsENOTCONN.Minimal reproducer:
Output on the affected machine:
Environment
15.7.3(aarch64)socket2 0.6.3In that particular environment, decomposing
Socket::connect_timeoutstep by step the issue is in the fast path (https://github.com/rust-lang/socket2/blob/master/src/socket.rs#L217). The non-blockingconnect()call returnsOk(0)instead ofErr(EINPROGRESS):This happens consistently (10/10 attempts) on this machine when the VPN is active.
The same network configuration on Linux works correctly:
connect()returns EINPROGRESS in both cases (with or without VPN)There's something I am missing about how
connect_timeoutshould be used?