diff options
| author | bors <bors@rust-lang.org> | 2023-10-19 11:22:28 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-10-19 11:22:28 +0000 |
| commit | 3fbcfd2b6f7030cb70328aa759107efc1516912c (patch) | |
| tree | 2b0909db89321d58f8a7e6a5fc17d08338f4947c /library/std/src | |
| parent | a01382dbea73c1442de1cf180333c273f82f710b (diff) | |
| parent | dfadd177a9738de289a3a6d4b39c08d94f384c1a (diff) | |
| download | rust-3fbcfd2b6f7030cb70328aa759107efc1516912c.tar.gz rust-3fbcfd2b6f7030cb70328aa759107efc1516912c.zip | |
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).
Diffstat (limited to 'library/std/src')
| -rw-r--r-- | library/std/src/sys/hermit/net.rs | 6 | ||||
| -rw-r--r-- | library/std/src/sys/solid/net.rs | 11 | ||||
| -rw-r--r-- | library/std/src/sys/unix/net.rs | 17 | ||||
| -rw-r--r-- | library/std/src/sys/windows/net.rs | 12 | ||||
| -rw-r--r-- | library/std/src/sys_common/net.rs | 4 |
5 files changed, 38 insertions, 12 deletions
diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs index a564f1698ba..bd8b493d65a 100644 --- a/library/std/src/sys/hermit/net.rs +++ b/library/std/src/sys/hermit/net.rs @@ -56,6 +56,12 @@ impl Socket { unimplemented!() } + pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { + let (addr, len) = addr.into_inner(); + cvt_r(|| unsafe { netc::connect(self.as_raw_fd(), addr.as_ptr(), len) })?; + Ok(()) + } + pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { self.set_nonblocking(true)?; let r = unsafe { diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs index 6adced787f3..1eae0fc0642 100644 --- a/library/std/src/sys/solid/net.rs +++ b/library/std/src/sys/solid/net.rs @@ -233,12 +233,15 @@ impl Socket { } } + pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { + let (addr, len) = addr.into_inner(); + cvt(unsafe { netc::connect(self.0.raw(), addr.as_ptr(), len) })?; + Ok(()) + } + pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { self.set_nonblocking(true)?; - let r = unsafe { - let (addr, len) = addr.into_inner(); - cvt(netc::connect(self.0.raw(), addr.as_ptr(), len)) - }; + let r = self.connect(addr); self.set_nonblocking(false)?; match r { diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 7e2016c410e..ec861f9cb86 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -6,6 +6,7 @@ use crate::net::{Shutdown, SocketAddr}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::str; use crate::sys::fd::FileDesc; +use crate::sys::unix::IsMinusOne; use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::{Duration, Instant}; @@ -140,6 +141,22 @@ impl Socket { unimplemented!() } + pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { + let (addr, len) = addr.into_inner(); + loop { + let result = unsafe { libc::connect(self.as_raw_fd(), addr.as_ptr(), len) }; + if result.is_minus_one() { + let err = crate::sys::os::errno(); + match err { + libc::EINTR => continue, + libc::EISCONN => return Ok(()), + _ => return Err(io::Error::from_raw_os_error(err)), + } + } + return Ok(()); + } + } + pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { self.set_nonblocking(true)?; let r = unsafe { diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 4b7115f97c5..c29b863665f 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -140,13 +140,15 @@ impl Socket { } } + pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { + let (addr, len) = addr.into_inner(); + let result = unsafe { c::connect(self.as_raw(), addr.as_ptr(), len) }; + cvt(result).map(drop) + } + pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { self.set_nonblocking(true)?; - let result = { - let (addr, len) = addr.into_inner(); - let result = unsafe { c::connect(self.as_raw(), addr.as_ptr(), len) }; - cvt(result).map(drop) - }; + let result = self.connect(addr); self.set_nonblocking(false)?; match result { diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 4f5b17deaa2..8712bd2eca7 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -226,9 +226,7 @@ impl TcpStream { init(); 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) })?; + sock.connect(addr)?; Ok(TcpStream { inner: sock }) } |
