HRESULT EnsureWinSockMethods()

in cpp/Riosock/Riosock.cpp [55:134]


HRESULT EnsureWinSockMethods(
    _In_  SOCKET  socket
    )
{
    static const LONG LockUninitialized = 0;
    static const LONG LockInitialized = 1;
    static const LONG LockInitializing = 2;

    LONG lastState;

    while((lastState = ::InterlockedCompareExchange(
                &WinSockMethodsLock,
                LockInitializing,
                LockUninitialized)) == LockInitializing)
    {
        Sleep(0);
    }
    
    if (lastState == LockInitialized)
    {
        return S_OK;
    }

    WSADATA wsaData;
    auto err = WSAStartup(WINSOCK_VERSION, &wsaData);
    if (err != 0) {
        // Reset lock to uninitialized
        ::InterlockedExchange(&WinSockMethodsLock, LockUninitialized);
        // WSAStartup does not set LastWin32Error
        SetLastError(err);
        return HRESULT_FROM_WIN32(err);
    }

    // Check to see if we need to create a temp socket
    auto localSocket = socket;
    if (INVALID_SOCKET == localSocket)
    {
        DWORD dwFlags = WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED | WSA_FLAG_REGISTERED_IO;
        localSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, dwFlags);
        if (INVALID_SOCKET == localSocket)
        {
            DWORD errorCode = WSAGetLastError();
            // Reset lock to uninitialized
            WSACleanup();
            ::InterlockedExchange(&WinSockMethodsLock, LockUninitialized);
            SetLastError(errorCode);
            return HRESULT_FROM_WIN32(errorCode);
        }
    }

    GUID funcGuid = WSAID_MULTIPLE_RIO;
    DWORD dwBytes = 0;

    if (WSAIoctl(
            localSocket,
            SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER,
            &funcGuid, sizeof(GUID),
            &RIOFuncs, sizeof(RIOFuncs),
            &dwBytes,nullptr, nullptr) != 0)
    {
        DWORD errorCode = WSAGetLastError();
        if (localSocket != socket)
        {
            closesocket(localSocket);
        }

        WSACleanup();
        // Reset lock to uninitialized
        ::InterlockedExchange(&WinSockMethodsLock, LockUninitialized);
        SetLastError(errorCode);
        return HRESULT_FROM_WIN32(errorCode);
    }

    // Update lock to fully Initialized
    ::InterlockedExchange(&WinSockMethodsLock, LockInitialized);
    if (localSocket != socket) {
        closesocket(localSocket);
    }
    return S_OK;
}