diff --git a/ThunksList.md b/ThunksList.md index 60843c0..000c928 100644 --- a/ThunksList.md +++ b/ThunksList.md @@ -813,4 +813,5 @@ | FreeAddrInfoEx(W) | 不存在时,内部实现。 | GetAddrInfoW | 不存在时,调用getaddrinfo。 | FreeAddrInfoW | 不存在时,内部实现。 -| WSASocketW(A) | 低于6.1.7601时自动去除 `WSA_FLAG_NO_HANDLE_INHERIT` +| WSASocketW(A) | 低于6.1.7601时自动去除 `WSA_FLAG_NO_HANDLE_INHERIT`。 +| WSAIoctl | 低于6.0时,`SIO_BASE_HANDLE` 代码返回SOCKET自身。 diff --git a/src/Thunks/WS2_32.hpp b/src/Thunks/WS2_32.hpp index 2259e87..0b169bc 100644 --- a/src/Thunks/WS2_32.hpp +++ b/src/Thunks/WS2_32.hpp @@ -7,6 +7,10 @@ #endif // ! FreeAddrInfoEx #endif +#if (YY_Thunks_Target < __WindowsNT6) +#include +#endif + #if (YY_Thunks_Target < __WindowsNT6_1_SP1) && !defined(__Comment_Lib_ws2_32) #define __Comment_Lib_ws2_32 #pragma comment(lib, "Ws2_32.lib") @@ -1471,6 +1475,62 @@ namespace YY::Thunks #endif +#if (YY_Thunks_Target < __WindowsNT6) + + // Windows XP就支持 + // 但是 Windows XP不支持 SIO_BASE_HANDLE + __DEFINE_THUNK( + ws2_32, + 36, + int, + WSAAPI, + WSAIoctl, + _In_ SOCKET s, + _In_ DWORD dwIoControlCode, + _In_reads_bytes_opt_(cbInBuffer) LPVOID lpvInBuffer, + _In_ DWORD cbInBuffer, + _Out_writes_bytes_to_opt_(cbOutBuffer, *lpcbBytesReturned) LPVOID lpvOutBuffer, + _In_ DWORD cbOutBuffer, + _Out_ LPDWORD lpcbBytesReturned, + _Inout_opt_ LPWSAOVERLAPPED lpOverlapped, + _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine + ) + { + // Upon successful completion, the WSAIoctl returns zero. Otherwise, a value of SOCKET_ERROR is returned, + // and a specific error code can be retrieved by calling WSAGetLastError. + auto const _pfnWSAIoctl = try_get_WSAIoctl(); + if (!_pfnWSAIoctl) + { + WSASetLastError(WSAVERNOTSUPPORTED); + return SOCKET_ERROR; + } + + if (dwIoControlCode == SIO_BASE_HANDLE && internal::GetSystemVersion() < internal::MakeVersion(6, 0)) + { + // So while we do have layered service providers in Windows XP or earlier, this specific io control is not supported. + // Worse, LSP is actually deprecated since Windows Server 2012, meaning this io control should likely return the socket + // input on later OS as well (effectively bypassed the LSPs) + // So almost nobody except mio's library uses this io control...god help... + + if (lpvOutBuffer == nullptr || lpcbBytesReturned == nullptr) + { + // https://learn.microsoft.com/zh-cn/windows/win32/winsock/winsock-ioctls#sio_bsp_handle-opcode-setting-o-t1 + // If the output buffer is not large enough for a socket handle (the cbOutBuffer is less than the size of a SOCKET) or the lpvOutBuffer + // parameter is a NULL pointer, SOCKET_ERROR is returned as the result of this IOCTL and WSAGetLastError returns WSAEFAULT. + WSASetLastError(WSAEFAULT); + return SOCKET_ERROR; + } + + *(SOCKET*)lpvOutBuffer = s; + *lpcbBytesReturned = sizeof(SOCKET); + return 0; + } + + return _pfnWSAIoctl(s, dwIoControlCode, lpvInBuffer, cbInBuffer, lpvOutBuffer, cbOutBuffer, lpcbBytesReturned, lpOverlapped, lpCompletionRoutine); + } +#endif + + #if (YY_Thunks_Target < __WindowsNT6_1_SP1) // Windows XP