Skip to content

Commit 3fbcfd2

Browse files
committed
Auto merge of #116132 - darthunix:connect_poll, r=cuviper
Make TCP connect handle EINTR correctly According to the [POSIX](https://pubs.opengroup.org/onlinepubs/009695399/functions/connect.html) 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. 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). 1. More details about the problem in an [article](http://www.madore.org/~david/computers/connect-intr.html). 2. The original [issue](https://git.picodata.io/picodata/picodata/tarantool-module/-/issues/157).
2 parents a01382d + dfadd17 commit 3fbcfd2

File tree

5 files changed

+38
-12
lines changed

5 files changed

+38
-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

+7-4
Original file line numberDiff line numberDiff line change
@@ -233,12 +233,15 @@ 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+
Ok(())
240+
}
241+
236242
pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
237243
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-
};
244+
let r = self.connect(addr);
242245
self.set_nonblocking(false)?;
243246

244247
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)