Skip to content

Commit

Permalink
Merge pull request #10 from sfackler/timeout-fix
Browse files Browse the repository at this point in the history
Fix refused connections in connect_timeout
  • Loading branch information
alexcrichton authored Oct 14, 2017
2 parents 7a57682 + caabdf5 commit fe67d6a
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 7 deletions.
18 changes: 18 additions & 0 deletions src/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,24 @@ mod test {
}
}

#[test]
fn connect_timeout_unbound() {
// bind and drop a socket to track down a "probably unassigned" port
let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
let addr = "127.0.0.1:0".parse::<SocketAddr>().unwrap().into();
socket.bind(&addr).unwrap();
let addr = socket.local_addr().unwrap();
drop(socket);

let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
match socket.connect_timeout(&addr, Duration::from_millis(250)) {
Ok(_) => panic!("unexpected success"),
Err(ref e) if e.kind() == io::ErrorKind::ConnectionRefused ||
e.kind() == io::ErrorKind::TimedOut => {},
Err(e) => panic!("unexpected error {}", e),
}
}

#[test]
fn connect_timeout_valid() {
let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
Expand Down
17 changes: 10 additions & 7 deletions src/sys/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ use std::time::{Duration, Instant};
#[cfg(feature = "unix")]
use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};

use libc::{self, c_void, c_int};
use libc::{sockaddr, socklen_t, ssize_t};
use libc::{self, c_void, c_int, socklen_t, ssize_t};

cfg_if! {
if #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
Expand Down Expand Up @@ -184,10 +183,14 @@ impl Socket {
}
0 => return Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")),
_ => {
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(());
}
Expand Down Expand Up @@ -256,7 +259,7 @@ impl Socket {
let mut socket = None;
#[cfg(target_os = "linux")] {
weak! {
fn accept4(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int
fn accept4(c_int, *mut libc::sockaddr, *mut socklen_t, c_int) -> c_int
}
if let Some(f) = accept4.get() {
let res = cvt_r(|| unsafe {
Expand Down

0 comments on commit fe67d6a

Please sign in to comment.