@@ -527,7 +527,8 @@ impl SelectorInner {
527527cfg_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
651683impl Drop for SelectorInner {
0 commit comments