Skip to content

Commit b6e08b7

Browse files
committed
fix(host): use ioctlsocket(FIONREAD) fallback for read-readiness on Windows
select() on Windows fails to report read-readiness on connected sockets (both TCP and UDP), even when data is sitting in the receive buffer. This causes blocking urllib calls without a timeout to hang indefinitely — the guest's poll loop never sees POLLIN. Add ioctlsocket(FIONREAD) as a fallback in both handle_net_poll and hl_sleep_poll_sockets: if select() misses read-readiness, check whether the socket has bytes pending in its receive buffer. Signed-off-by: danbugs <danilochiarlone@gmail.com>
1 parent 9960572 commit b6e08b7

1 file changed

Lines changed: 27 additions & 3 deletions

File tree

host/src/lib.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,7 +1706,8 @@ fn handle_net_poll(
17061706
use serde_json::json;
17071707
use std::os::windows::io::AsRawSocket;
17081708
use windows_sys::Win32::Networking::WinSock::{
1709-
__WSAFDIsSet, select, FD_SET, FD_SETSIZE, SOCKET, SOCKET_ERROR, TIMEVAL,
1709+
__WSAFDIsSet, ioctlsocket, select, FD_SET, FD_SETSIZE, FIONREAD, SOCKET, SOCKET_ERROR,
1710+
TIMEVAL,
17101711
};
17111712

17121713
const POSIX_POLLIN: i16 = 0x0001;
@@ -1819,6 +1820,17 @@ fn handle_net_poll(
18191820
if unsafe { __WSAFDIsSet(e.raw, &mut readfds) } != 0 {
18201821
revents |= POSIX_POLLIN;
18211822
}
1823+
// Fallback: select() on Windows can miss read-readiness on
1824+
// connected sockets. Use ioctlsocket(FIONREAD) to check if
1825+
// bytes are waiting in the receive buffer.
1826+
if e.want_read && revents & POSIX_POLLIN == 0 {
1827+
let mut bytes_available: u32 = 0;
1828+
if unsafe { ioctlsocket(e.raw, FIONREAD, &mut bytes_available) } == 0
1829+
&& bytes_available > 0
1830+
{
1831+
revents |= POSIX_POLLIN;
1832+
}
1833+
}
18221834
if unsafe { __WSAFDIsSet(e.raw, &mut writefds) } != 0 {
18231835
revents |= POSIX_POLLOUT;
18241836
}
@@ -1892,7 +1904,7 @@ fn hl_sleep_poll_sockets(
18921904
use serde_json::json;
18931905
use std::os::windows::io::AsRawSocket;
18941906
use windows_sys::Win32::Networking::WinSock::{
1895-
select, FD_SET, FD_SETSIZE, SOCKET, SOCKET_ERROR, TIMEVAL,
1907+
ioctlsocket, select, FD_SET, FD_SETSIZE, FIONREAD, SOCKET, SOCKET_ERROR, TIMEVAL,
18961908
};
18971909

18981910
let tbl = table.lock().unwrap();
@@ -1937,7 +1949,19 @@ fn hl_sleep_poll_sockets(
19371949
return Err(anyhow!("hl_sleep select() failed: {err}"));
19381950
}
19391951

1940-
let ready = ret > 0;
1952+
// select() on Windows can miss read-readiness on connected sockets.
1953+
// Fall back to ioctlsocket(FIONREAD) to detect pending data.
1954+
let mut ready = ret > 0;
1955+
if !ready {
1956+
for &s in &raw_sockets {
1957+
let mut bytes_available: u32 = 0;
1958+
if unsafe { ioctlsocket(s, FIONREAD, &mut bytes_available) } == 0 && bytes_available > 0
1959+
{
1960+
ready = true;
1961+
break;
1962+
}
1963+
}
1964+
}
19411965
Ok(json!({"socket_ready": ready}))
19421966
}
19431967

0 commit comments

Comments
 (0)