Skip to content

Commit fe67d6a

Browse files
authored
Merge pull request #10 from sfackler/timeout-fix
Fix refused connections in connect_timeout
2 parents 7a57682 + caabdf5 commit fe67d6a

File tree

2 files changed

+28
-7
lines changed

2 files changed

+28
-7
lines changed

src/socket.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,24 @@ mod test {
827827
}
828828
}
829829

830+
#[test]
831+
fn connect_timeout_unbound() {
832+
// bind and drop a socket to track down a "probably unassigned" port
833+
let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
834+
let addr = "127.0.0.1:0".parse::<SocketAddr>().unwrap().into();
835+
socket.bind(&addr).unwrap();
836+
let addr = socket.local_addr().unwrap();
837+
drop(socket);
838+
839+
let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
840+
match socket.connect_timeout(&addr, Duration::from_millis(250)) {
841+
Ok(_) => panic!("unexpected success"),
842+
Err(ref e) if e.kind() == io::ErrorKind::ConnectionRefused ||
843+
e.kind() == io::ErrorKind::TimedOut => {},
844+
Err(e) => panic!("unexpected error {}", e),
845+
}
846+
}
847+
830848
#[test]
831849
fn connect_timeout_valid() {
832850
let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();

src/sys/unix/mod.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ use std::time::{Duration, Instant};
2222
#[cfg(feature = "unix")]
2323
use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
2424

25-
use libc::{self, c_void, c_int};
26-
use libc::{sockaddr, socklen_t, ssize_t};
25+
use libc::{self, c_void, c_int, socklen_t, ssize_t};
2726

2827
cfg_if! {
2928
if #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
@@ -184,10 +183,14 @@ impl Socket {
184183
}
185184
0 => return Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")),
186185
_ => {
187-
if pollfd.revents & libc::POLLOUT == 0 {
188-
if let Some(e) = self.take_error()? {
189-
return Err(e);
190-
}
186+
// linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
187+
// for POLLHUP rather than read readiness
188+
if pollfd.revents & libc::POLLHUP != 0 {
189+
let e = self.take_error()?
190+
.unwrap_or_else(|| {
191+
io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP")
192+
});
193+
return Err(e);
191194
}
192195
return Ok(());
193196
}
@@ -256,7 +259,7 @@ impl Socket {
256259
let mut socket = None;
257260
#[cfg(target_os = "linux")] {
258261
weak! {
259-
fn accept4(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int
262+
fn accept4(c_int, *mut libc::sockaddr, *mut socklen_t, c_int) -> c_int
260263
}
261264
if let Some(f) = accept4.get() {
262265
let res = cvt_r(|| unsafe {

0 commit comments

Comments
 (0)