Skip to content

Commit b15fc18

Browse files
committed
On windows, try some alternative IOCTLs if SIO_BASE_HANDLE fails
Fixes: #1314
1 parent 0380418 commit b15fc18

File tree

1 file changed

+40
-8
lines changed

1 file changed

+40
-8
lines changed

src/sys/windows/selector.rs

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,8 @@ impl SelectorInner {
527527
cfg_net! {
528528
use std::mem::size_of;
529529
use std::ptr::null_mut;
530-
use winapi::um::mswsock::SIO_BASE_HANDLE;
530+
use winapi::um::mswsock;
531+
use winapi::um::winsock2::WSAGetLastError;
531532
use winapi::um::winsock2::{WSAIoctl, SOCKET_ERROR};
532533

533534
impl SelectorInner {
@@ -557,7 +558,7 @@ cfg_net! {
557558
};
558559

559560
this.queue_state(sock);
560-
unsafe { this.update_sockets_events_if_polling()?; }
561+
unsafe { this.update_sockets_events_if_polling()? };
561562

562563
Ok(state)
563564
}
@@ -623,29 +624,60 @@ cfg_net! {
623624
}
624625
}
625626

626-
fn get_base_socket(raw_socket: RawSocket) -> io::Result<RawSocket> {
627+
fn try_get_base_socket(raw_socket: RawSocket, ioctl: u32) -> Result<RawSocket, i32> {
627628
let mut base_socket: RawSocket = 0;
628629
let mut bytes: u32 = 0;
629-
630630
unsafe {
631631
if WSAIoctl(
632632
raw_socket as usize,
633-
SIO_BASE_HANDLE,
633+
ioctl,
634634
null_mut(),
635635
0,
636636
&mut base_socket as *mut _ as PVOID,
637637
size_of::<RawSocket>() as u32,
638638
&mut bytes,
639639
null_mut(),
640640
None,
641-
) == SOCKET_ERROR
641+
) != SOCKET_ERROR
642642
{
643-
Err(io::Error::last_os_error())
644-
} else {
645643
Ok(base_socket)
644+
} else {
645+
Err(WSAGetLastError())
646646
}
647647
}
648648
}
649+
650+
fn get_base_socket(raw_socket: RawSocket) -> io::Result<RawSocket> {
651+
let res = try_get_base_socket(raw_socket, mswsock::SIO_BASE_HANDLE);
652+
if let Ok(base_socket) = res {
653+
return Ok(base_socket);
654+
}
655+
656+
// The `SIO_BASE_HANDLE` should not be intercepted by LSPs, therefore
657+
// it should not fail as long as `raw_socket` is a valid socket. See
658+
// https://docs.microsoft.com/en-us/windows/win32/winsock/winsock-ioctls.
659+
// However, at least one known LSP deliberately breaks it, so we try
660+
// some alternative IOCTLs, starting with the most appropriate one.
661+
for &ioctl in &[
662+
mswsock::SIO_BSP_HANDLE_SELECT,
663+
mswsock::SIO_BSP_HANDLE_POLL,
664+
mswsock::SIO_BSP_HANDLE,
665+
] {
666+
if let Ok(base_socket) = try_get_base_socket(raw_socket, ioctl) {
667+
// Since we know now that we're dealing with an LSP (otherwise
668+
// SIO_BASE_HANDLE would't have failed), only return any result
669+
// when it is different from the original `raw_socket`.
670+
if base_socket != raw_socket {
671+
return Ok(base_socket);
672+
}
673+
}
674+
}
675+
676+
// If the alternative IOCTLs also failed, return the original error.
677+
let os_error = res.unwrap_err();
678+
let err = io::Error::from_raw_os_error(os_error);
679+
Err(err)
680+
}
649681
}
650682

651683
impl Drop for SelectorInner {

0 commit comments

Comments
 (0)