about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorSteven Fackler <sfackler@gmail.com>2017-10-13 19:22:33 -0700
committerSteven Fackler <sfackler@gmail.com>2017-10-14 13:56:30 -0700
commitcab99a3f8c8dcdfd9052fd54787d22611ab36edc (patch)
tree7e3a4d2fe0181c9a6ec65b603fe51fce08cd4f65 /src
parent02a24dbdd8c3a5daa6578af72116020de75b5f93 (diff)
downloadrust-cab99a3f8c8dcdfd9052fd54787d22611ab36edc.tar.gz
rust-cab99a3f8c8dcdfd9052fd54787d22611ab36edc.zip
Fix TcpStream::connect_timeout on linux
Linux appears to set POLLOUT when a conection's refused, which is pretty
weird. Invert the check to look for an error explicitly. Also add an
explict test for this case.

Closes #45265.
Diffstat (limited to 'src')
-rw-r--r--src/libstd/net/tcp.rs15
-rw-r--r--src/libstd/sys/unix/net.rs13
2 files changed, 24 insertions, 4 deletions
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index b904641a336..4656cc5a7a7 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -1580,6 +1580,21 @@ mod tests {
     }
 
     #[test]
+    fn connect_timeout_unbound() {
+        // bind and drop a socket to track down a "probably unassigned" port
+        let socket = TcpListener::bind("127.0.0.1:0").unwrap();
+        let addr = socket.local_addr().unwrap();
+        drop(socket);
+
+        let timeout = Duration::from_secs(1);
+        let e = TcpStream::connect_timeout(&addr, timeout).unwrap_err();
+        assert!(e.kind() == io::ErrorKind::ConnectionRefused ||
+                e.kind() == io::ErrorKind::TimedOut ||
+                e.kind() == io::ErrorKind::Other,
+                "bad error: {} {:?}", e, e.kind());
+    }
+
+    #[test]
     fn connect_timeout_valid() {
         let listener = TcpListener::bind("127.0.0.1:0").unwrap();
         let addr = listener.local_addr().unwrap();
diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs
index c8019d1c768..e775f857f2b 100644
--- a/src/libstd/sys/unix/net.rs
+++ b/src/libstd/sys/unix/net.rs
@@ -176,11 +176,16 @@ impl Socket {
                 }
                 0 => {}
                 _ => {
-                    if pollfd.revents & libc::POLLOUT == 0 {
-                        if let Some(e) = self.take_error()? {
-                            return Err(e);
-                        }
+                    // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
+                    // for POLLHUP rather than read readiness
+                    if pollfd.revents & libc::POLLHUP != 0 {
+                        let e = self.take_error()?
+                            .unwrap_or_else(|| {
+                                io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP")
+                            });
+                        return Err(e);
                     }
+
                     return Ok(());
                 }
             }