Skip to content

Commit a3d422a

Browse files
committed
Make TCP connect() handle EINTR correctly
According to the POSIX standard, 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. If asynchronous connection was successfully established after EINTR and before the next connection attempt, OS returns EISCONN that was handled as an error before. This behavior is fixed now and we handle it as success. The problem affects MacOS users: Linux doesn't return EISCONN in this case, Windows connect() can not be interrupted without an old-fashoin WSACancelBlockingCall function that is not used in the library. So current solution gives connect() as OS specific implementation.
1 parent 130ff8c commit a3d422a

File tree

5 files changed

+37
-12
lines changed

5 files changed

+37
-12
lines changed

library/std/src/sys/hermit/net.rs

+6
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ impl Socket {
5656
unimplemented!()
5757
}
5858

59+
pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
60+
let (addr, len) = addr.into_inner();
61+
cvt_r(|| unsafe { netc::connect(self.as_raw_fd(), addr.as_ptr(), len) })?;
62+
Ok(())
63+
}
64+
5965
pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
6066
self.set_nonblocking(true)?;
6167
let r = unsafe {

library/std/src/sys/solid/net.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -233,12 +233,14 @@ impl Socket {
233233
}
234234
}
235235

236+
pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
237+
let (addr, len) = addr.into_inner();
238+
cvt(unsafe { netc::connect(self.0.raw(), addr.as_ptr(), len) })
239+
}
240+
236241
pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
237242
self.set_nonblocking(true)?;
238-
let r = unsafe {
239-
let (addr, len) = addr.into_inner();
240-
cvt(netc::connect(self.0.raw(), addr.as_ptr(), len))
241-
};
243+
let r = self.connect(addr);
242244
self.set_nonblocking(false)?;
243245

244246
match r {

library/std/src/sys/unix/net.rs

+17
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::net::{Shutdown, SocketAddr};
66
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
77
use crate::str;
88
use crate::sys::fd::FileDesc;
9+
use crate::sys::unix::IsMinusOne;
910
use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
1011
use crate::sys_common::{AsInner, FromInner, IntoInner};
1112
use crate::time::{Duration, Instant};
@@ -140,6 +141,22 @@ impl Socket {
140141
unimplemented!()
141142
}
142143

144+
pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
145+
let (addr, len) = addr.into_inner();
146+
loop {
147+
let result = unsafe { libc::connect(self.as_raw_fd(), addr.as_ptr(), len) };
148+
if result.is_minus_one() {
149+
let err = crate::sys::os::errno();
150+
match err {
151+
libc::EINTR => continue,
152+
libc::EISCONN => return Ok(()),
153+
_ => return Err(io::Error::from_raw_os_error(err)),
154+
}
155+
}
156+
return Ok(());
157+
}
158+
}
159+
143160
pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
144161
self.set_nonblocking(true)?;
145162
let r = unsafe {

library/std/src/sys/windows/net.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,15 @@ impl Socket {
140140
}
141141
}
142142

143+
pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
144+
let (addr, len) = addr.into_inner();
145+
let result = unsafe { c::connect(self.as_raw(), addr.as_ptr(), len) };
146+
cvt(result).map(drop)
147+
}
148+
143149
pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
144150
self.set_nonblocking(true)?;
145-
let result = {
146-
let (addr, len) = addr.into_inner();
147-
let result = unsafe { c::connect(self.as_raw(), addr.as_ptr(), len) };
148-
cvt(result).map(drop)
149-
};
151+
let result = self.connect(addr);
150152
self.set_nonblocking(false)?;
151153

152154
match result {

library/std/src/sys_common/net.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,7 @@ impl TcpStream {
226226
init();
227227

228228
let sock = Socket::new(addr, c::SOCK_STREAM)?;
229-
230-
let (addr, len) = addr.into_inner();
231-
cvt_r(|| unsafe { c::connect(sock.as_raw(), addr.as_ptr(), len) })?;
229+
sock.connect(addr)?;
232230
Ok(TcpStream { inner: sock })
233231
}
234232

0 commit comments

Comments
 (0)