Skip to content

Commit

Permalink
Make TCP connect handle EINTR correctly
Browse files Browse the repository at this point in the history
According to the POSIX standart, if connect() is interrupted by a
signal that is caught while blocked waiting to establish a connection,
connect() shall fail and set errno to EINTR, but the connection
request shall not be aborted, and the connection shall be established
asynchronously. When the connection has been established asynchronously,
select() and poll() shall indicate that the file descriptor for the
socket is ready for writing.

The previous implementation differs from the recomendation: in a
case of the EINTR we tried to reconnect in a loop and sometimes
get EISCONN error (this problem was originally detected on MacOS).
  • Loading branch information
darthunix committed Sep 25, 2023
1 parent 42ca6e4 commit 4be1dfb
Showing 1 changed file with 22 additions and 1 deletion.
23 changes: 22 additions & 1 deletion library/std/src/sys_common/net.rs
Expand Up @@ -228,7 +228,28 @@ impl TcpStream {
let sock = Socket::new(addr, c::SOCK_STREAM)?;

let (addr, len) = addr.into_inner();
cvt_r(|| unsafe { c::connect(sock.as_raw(), addr.as_ptr(), len) })?;

let ret = unsafe { c::connect(sock.as_raw(), addr.as_ptr(), len) };
if ret < 0 {
let err = io::Error::last_os_error();
if !err.is_interrupted() {
return Err(err);
}

let mut pollfd = libc::pollfd { fd: sock.as_raw(), events: libc::POLLOUT, revents: 0 };
loop {
let ret = unsafe { libc::poll(&mut pollfd, 1, -1) };
if ret < 0 {
let err = io::Error::last_os_error();
if err.is_interrupted() {
continue;
}
return Err(err);
}
break;
}
sock.take_error()?;
}
Ok(TcpStream { inner: sock })
}

Expand Down

0 comments on commit 4be1dfb

Please sign in to comment.