Skip to content

Commit ab611df

Browse files
committed
Fix an inconsitency in Linux version of TcpListener::accept
If TcpListener is in non-blocking mode then accepted streams inherit this property on all platforms except Linux, where accept4 is used instead of accept. This fix checks if a listener is in non-blocking mode and pass the corresponding flag to accept4. Fixes #67027
1 parent b181835 commit ab611df

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

src/libstd/net/tcp.rs

+27
Original file line numberDiff line numberDiff line change
@@ -1818,4 +1818,31 @@ mod tests {
18181818
let addr = listener.local_addr().unwrap();
18191819
TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap();
18201820
}
1821+
1822+
#[test]
1823+
fn nonblocking_accept() {
1824+
let socket_addr = next_test_ip4();
1825+
let listener = t!(TcpListener::bind(&socket_addr));
1826+
t!(listener.set_nonblocking(true));
1827+
1828+
let _t = thread::spawn(move || {
1829+
t!(TcpStream::connect(&("localhost", socket_addr.port())));
1830+
thread::sleep(Duration::from_millis(1000));
1831+
});
1832+
1833+
loop {
1834+
match listener.accept() {
1835+
Ok((mut stream, _)) => {
1836+
let mut buf = [0; 2];
1837+
match stream.read_exact(&mut buf) {
1838+
Ok(_) => panic!("expected error"),
1839+
Err(ref e) if e.kind() == ErrorKind::WouldBlock => return,
1840+
Err(e) => panic!("unexpected error {:?}", e),
1841+
}
1842+
}
1843+
Err(e) if e.kind() == ErrorKind::WouldBlock => {}
1844+
Err(e) => panic!("unexpected error {:?}", e),
1845+
}
1846+
}
1847+
}
18211848
}

src/libstd/sys/unix/net.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,14 @@ impl Socket {
189189
flags: c_int
190190
) -> c_int
191191
}
192-
let res = cvt_r(|| unsafe { accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC) });
192+
let is_blocking =
193+
unsafe { (cvt(libc::fcntl(self.0.raw(), libc::F_GETFL))? & libc::O_NONBLOCK) != 0 };
194+
let accept_flags = if is_blocking {
195+
libc::SOCK_CLOEXEC | libc::SOCK_NONBLOCK
196+
} else {
197+
libc::SOCK_CLOEXEC
198+
};
199+
let res = cvt_r(|| unsafe { accept4(self.0.raw(), storage, len, accept_flags) });
193200
match res {
194201
Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
195202
Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
@@ -329,7 +336,11 @@ impl Socket {
329336

330337
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
331338
let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?;
332-
if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
339+
if raw == 0 {
340+
Ok(None)
341+
} else {
342+
Ok(Some(io::Error::from_raw_os_error(raw as i32)))
343+
}
333344
}
334345
}
335346

0 commit comments

Comments
 (0)