VirtualBox

Changeset 70481 in vbox for trunk/src/VBox/Runtime/r3


Ignore:
Timestamp:
Jan 7, 2018 6:46:08 PM (7 years ago)
Author:
vboxsync
Message:

iprt/socket,tcp,pollset: Added RTTcpCreatePair. Implemented polling fallback for winsock 1.x. Extended tstRTPoll to cover sockets and actual waiting and receiving of events on pipe & socket events.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/socket.cpp

    r70401 r70481  
    165165    /** Saved events which are only posted once. */
    166166    uint32_t            fEventsSaved;
     167    /** Set if we're using the polling fallback. */
     168    bool                fPollFallback;
     169    /** Set if the fallback polling is active (event not set). */
     170    bool volatile       fPollFallbackActive;
     171    /** Set to shut down the fallback polling thread. */
     172    bool volatile       fPollFallbackShutdown;
     173    /** Socket use to wake up the select thread. */
     174    RTSOCKETNATIVE      hPollFallbackNotifyW;
     175    /** Socket the select thread always waits on. */
     176    RTSOCKETNATIVE      hPollFallbackNotifyR;
     177    /** The fallback polling thread. */
     178    RTTHREAD            hPollFallbackThread;
    167179#endif /* RT_OS_WINDOWS */
    168180} RTSOCKETINT;
     
    189201static uint32_t volatile g_uWinSockInitedVersion = 0;
    190202#endif
     203
     204
     205/*********************************************************************************************************************************
     206*   Internal Functions                                                                                                           *
     207*********************************************************************************************************************************/
     208#ifdef RT_OS_WINDOWS
     209static void rtSocketPokePollFallbackThread(RTSOCKETINT *pThis);
     210#endif
     211
    191212
    192213
     
    480501#endif
    481502#ifdef RT_OS_WINDOWS
    482     pThis->hEvent           = WSA_INVALID_EVENT;
    483     pThis->fPollEvts        = 0;
    484     pThis->fSubscribedEvts  = 0;
    485     pThis->fEventsSaved     = 0;
     503    pThis->hEvent                   = WSA_INVALID_EVENT;
     504    pThis->fPollEvts                = 0;
     505    pThis->fSubscribedEvts          = 0;
     506    pThis->fEventsSaved             = 0;
     507    pThis->fPollFallback            = g_uWinSockInitedVersion < MAKEWORD(2, 0)
     508                                   || g_pfnWSACreateEvent == NULL
     509                                   || g_pfnWSACloseEvent == NULL
     510                                   || g_pfnWSAEventSelect == NULL
     511                                   || g_pfnWSAEnumNetworkEvents == NULL;
     512    pThis->fPollFallbackActive      = false;
     513    pThis->fPollFallbackShutdown    = false;
     514    pThis->hPollFallbackNotifyR     = NIL_RTSOCKETNATIVE;
     515    pThis->hPollFallbackNotifyW     = NIL_RTSOCKETNATIVE;
     516    pThis->hPollFallbackThread      = NIL_RTTHREAD;
    486517#endif
    487518    *ppSocket = pThis;
     
    550581
    551582
     583/**
     584 * Wrapper around socketpair() for creating a local TCP connection.
     585 *
     586 * @returns IPRT status code.
     587 * @param   phServer            Where to return the first native socket.
     588 * @param   phClient            Where to return the second native socket.
     589 */
     590static int rtSocketCreateNativeTcpPair(RTSOCKETNATIVE *phServer, RTSOCKETNATIVE *phClient)
     591{
     592#ifdef RT_OS_WINDOWS
     593    /*
     594     * Initialize WinSock and make sure we got the necessary APIs.
     595     */
     596    int rc = rtSocketInitWinsock();
     597    if (RT_FAILURE(rc))
     598        return rc;
     599    AssertReturn(g_pfnsocket, VERR_NET_NOT_UNSUPPORTED);
     600    AssertReturn(g_pfnclosesocket, VERR_NET_NOT_UNSUPPORTED);
     601    AssertReturn(g_pfnsetsockopt, VERR_NET_NOT_UNSUPPORTED);
     602    AssertReturn(g_pfnbind, VERR_NET_NOT_UNSUPPORTED);
     603    AssertReturn(g_pfngetsockname, VERR_NET_NOT_UNSUPPORTED);
     604    AssertReturn(g_pfnlisten, VERR_NET_NOT_UNSUPPORTED);
     605    AssertReturn(g_pfnaccept, VERR_NET_NOT_UNSUPPORTED);
     606    AssertReturn(g_pfnconnect, VERR_NET_NOT_UNSUPPORTED);
     607
     608    /*
     609     * Create the "server" listen socket and the "client" socket.
     610     */
     611    RTSOCKETNATIVE hListener = g_pfnsocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     612    if (hListener == NIL_RTSOCKETNATIVE)
     613        return rtSocketError();
     614    RTSOCKETNATIVE hClient = g_pfnsocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     615    if (hClient != NIL_RTSOCKETNATIVE)
     616    {
     617
     618        /*
     619         * We let WinSock choose a port number when we bind.
     620         */
     621        union
     622        {
     623            struct sockaddr_in  Ip;
     624            struct sockaddr     Generic;
     625        } uAddr;
     626        RT_ZERO(uAddr);
     627        uAddr.Ip.sin_family      = AF_INET;
     628        uAddr.Ip.sin_addr.s_addr = RT_H2N_U32_C(INADDR_LOOPBACK);
     629        //uAddr.Ip.sin_port      = 0;
     630        int fReuse = 1;
     631        rc = g_pfnsetsockopt(hListener, SOL_SOCKET, SO_REUSEADDR, (const char *)&fReuse, sizeof(fReuse));
     632        if (rc == 0)
     633        {
     634            rc = g_pfnbind(hListener, &uAddr.Generic, sizeof(uAddr.Ip));
     635            if (rc == 0)
     636            {
     637                /*
     638                 * Get the address the client should connect to.  According to the docs,
     639                 * we cannot assume that getsockname sets the IP and family.
     640                 */
     641                RT_ZERO(uAddr);
     642                int cbAddr = sizeof(uAddr.Ip);
     643                rc = g_pfngetsockname(hListener, &uAddr.Generic, &cbAddr);
     644                if (rc == 0)
     645                {
     646                    uAddr.Ip.sin_family      = AF_INET;
     647                    uAddr.Ip.sin_addr.s_addr = RT_H2N_U32_C(INADDR_LOOPBACK);
     648
     649                    /*
     650                     * Listen, connect and accept.
     651                     */
     652                    rc = g_pfnlisten(hListener, 1 /*cBacklog*/);
     653                    if (rc == 0)
     654                    {
     655                        rc = g_pfnconnect(hClient, &uAddr.Generic, sizeof(uAddr.Ip));
     656                        if (rc == 0)
     657                        {
     658                            RTSOCKETNATIVE hServer = g_pfnaccept(hListener, NULL, NULL);
     659                            if (hServer != NIL_RTSOCKETNATIVE)
     660                            {
     661                                g_pfnclosesocket(hListener);
     662
     663                                /*
     664                                 * Done!
     665                                 */
     666                                *phServer = hServer;
     667                                *phClient = hClient;
     668                                return VINF_SUCCESS;
     669                            }
     670                        }
     671                    }
     672                }
     673            }
     674        }
     675        rc = rtSocketError();
     676        g_pfnclosesocket(hClient);
     677    }
     678    else
     679        rc = rtSocketError();
     680    g_pfnclosesocket(hListener);
     681    return rc;
     682
     683#else
     684    /*
     685     * Got socket pair, so use it.
     686     */
     687    int aSockets[2] = { -1, -1 };
     688    int (socketpair(AF_INET, SOCK_STREAM, IPPROTO_TCP, aSockets) == 0)
     689    {
     690        *phServer = aSockets[0];
     691        *phClient = aSockets[0];
     692        return VINF_SUCCESS;
     693    }
     694    return rtSocketError();
     695#endif
     696}
     697
     698
     699/**
     700 * Worker for RTTcpCreatePair.
     701 *
     702 * @returns IPRT status code.
     703 * @param   phServer            Where to return the "server" side of the pair.
     704 * @param   phClient            Where to return the "client" side of the pair.
     705 * @note    There is no server or client side, but we gotta call it something.
     706 */
     707DECLHIDDEN(int) rtSocketCreateTcpPair(RTSOCKET *phServer, RTSOCKET *phClient)
     708{
     709    RTSOCKETNATIVE hServer = NIL_RTSOCKETNATIVE;
     710    RTSOCKETNATIVE hClient = NIL_RTSOCKETNATIVE;
     711    int rc = rtSocketCreateNativeTcpPair(&hServer, &hClient);
     712    if (RT_SUCCESS(rc))
     713    {
     714        rc = rtSocketCreateForNative(phServer, hServer);
     715        if (RT_SUCCESS(rc))
     716        {
     717            rc = rtSocketCreateForNative(phClient, hClient);
     718            if (RT_SUCCESS(rc))
     719                return VINF_SUCCESS;
     720            RTSocketRelease(*phServer);
     721        }
     722        else
     723        {
     724#ifdef RT_OS_WINDOWS
     725            g_pfnclosesocket(hServer);
     726#else
     727            close(hServer);
     728#endif
     729        }
     730#ifdef RT_OS_WINDOWS
     731        g_pfnclosesocket(hClient);
     732#else
     733        close(hClient);
     734#endif
     735    }
     736
     737    *phServer = NIL_RTSOCKET;
     738    *phClient = NIL_RTSOCKET;
     739    return rc;
     740}
     741
     742
    552743RTDECL(uint32_t) RTSocketRetain(RTSOCKET hSocket)
    553744{
     
    580771    if (ASMAtomicCmpXchgBool(&pThis->fClosed, true, false))
    581772    {
     773#ifdef RT_OS_WINDOWS
     774        /*
     775         * Poke the polling thread if active and give it a small chance to stop.
     776         */
     777        if (   pThis->fPollFallback
     778            && pThis->hPollFallbackThread != NIL_RTTHREAD)
     779        {
     780            ASMAtomicWriteBool(&pThis->fPollFallbackShutdown, true);
     781            rtSocketPokePollFallbackThread(pThis);
     782            int rc2 = RTThreadWait(pThis->hPollFallbackThread, RT_MS_1SEC, NULL);
     783            if (RT_SUCCESS(rc2))
     784                pThis->hPollFallbackThread = NIL_RTTHREAD;
     785        }
     786#endif
     787
    582788        /*
    583789         * Close the native handle.
     
    606812#ifdef RT_OS_WINDOWS
    607813        /*
    608          * Close the event.
     814         * Windows specific polling cleanup.
    609815         */
    610816        WSAEVENT hEvent = pThis->hEvent;
     
    612818        {
    613819            pThis->hEvent = WSA_INVALID_EVENT;
    614             Assert(g_pfnWSACloseEvent);
    615             if (g_pfnWSACloseEvent)
    616                 g_pfnWSACloseEvent(hEvent);
     820            if (!pThis->fPollFallback)
     821            {
     822                Assert(g_pfnWSACloseEvent);
     823                if (g_pfnWSACloseEvent)
     824                    g_pfnWSACloseEvent(hEvent);
     825            }
     826            else
     827                CloseHandle(hEvent);
     828        }
     829
     830        if (pThis->fPollFallback)
     831        {
     832            if (pThis->hPollFallbackNotifyW != NIL_RTSOCKETNATIVE)
     833            {
     834                g_pfnclosesocket(pThis->hPollFallbackNotifyW);
     835                pThis->hPollFallbackNotifyW = NIL_RTSOCKETNATIVE;
     836            }
     837
     838            if (pThis->hPollFallbackThread != NIL_RTTHREAD)
     839            {
     840                int rc2 = RTThreadWait(pThis->hPollFallbackThread, RT_MS_1MIN / 2, NULL);
     841                AssertRC(rc2);
     842                pThis->hPollFallbackThread = NIL_RTTHREAD;
     843            }
     844
     845            if (pThis->hPollFallbackNotifyR != NIL_RTSOCKETNATIVE)
     846            {
     847                g_pfnclosesocket(pThis->hPollFallbackNotifyR);
     848                pThis->hPollFallbackNotifyR = NIL_RTSOCKETNATIVE;
     849            }
    617850        }
    618851#endif
     
    16991932
    17001933
    1701 RTDECL(int) RTSocketSelectOneEx(RTSOCKET hSocket, uint32_t fEvents, uint32_t *pfEvents, RTMSINTERVAL cMillies)
    1702 {
    1703     /*
    1704      * Validate input.
    1705      */
    1706     RTSOCKETINT *pThis = hSocket;
    1707     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    1708     AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
    1709     AssertPtrReturn(pfEvents, VERR_INVALID_PARAMETER);
    1710     AssertReturn(!(fEvents & ~RTSOCKET_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
    1711     AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
    1712 
     1934/**
     1935 * Internal worker for RTSocketSelectOneEx and rtSocketPollCheck (fallback)
     1936 *
     1937 * @returns IPRT status code
     1938 * @param   pThis               The socket (valid).
     1939 * @param   fEvents             The events to select for.
     1940 * @param   pfEvents            Where to return the events.
     1941 * @param   cMillies            How long to select for, in milliseconds.
     1942 */
     1943static int rtSocketSelectOneEx(RTSOCKET pThis, uint32_t fEvents, uint32_t *pfEvents, RTMSINTERVAL cMillies)
     1944{
    17131945    RTSOCKETNATIVE hNative = pThis->hNative;
    17141946    if (hNative == NIL_RTSOCKETNATIVE)
     
    17872019#endif
    17882020    return rc;
     2021}
     2022
     2023
     2024RTDECL(int) RTSocketSelectOneEx(RTSOCKET hSocket, uint32_t fEvents, uint32_t *pfEvents, RTMSINTERVAL cMillies)
     2025{
     2026    /*
     2027     * Validate input.
     2028     */
     2029    RTSOCKETINT *pThis = hSocket;
     2030    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     2031    AssertReturn(pThis->u32Magic == RTSOCKET_MAGIC, VERR_INVALID_HANDLE);
     2032    AssertPtrReturn(pfEvents, VERR_INVALID_PARAMETER);
     2033    AssertReturn(!(fEvents & ~RTSOCKET_EVT_VALID_MASK), VERR_INVALID_PARAMETER);
     2034    AssertReturn(RTMemPoolRefCount(pThis) >= (pThis->cUsers ? 2U : 1U), VERR_CALLER_NO_REFERENCE);
     2035
     2036    return rtSocketSelectOneEx(pThis, fEvents, pfEvents, cMillies);
    17892037}
    17902038
     
    22742522    }
    22752523    else
    2276         rc = VERR_NET_NOT_UNSUPPORTED;
     2524    {
     2525        AssertCompile(WSA_INVALID_EVENT == (WSAEVENT)NULL);
     2526        pThis->hEvent = CreateEventW(NULL, TRUE /*fManualReset*/, FALSE /*fInitialState*/,  NULL /*pwszName*/);
     2527        *phNative = (RTHCINTPTR)pThis->hEvent;
     2528        if (pThis->hEvent == WSA_INVALID_EVENT)
     2529            rc = RTErrConvertFromWin32(GetLastError());
     2530    }
    22772531
    22782532    rtSocketUnlock(pThis);
     
    22882542
    22892543/**
     2544 * Fallback poller thread.
     2545 *
     2546 * @returns VINF_SUCCESS.
     2547 * @param   hSelf               The thread handle.
     2548 * @param   pvUser              Socket instance data.
     2549 */
     2550static DECLCALLBACK(int) rtSocketPollFallbackThreadProc(RTTHREAD hSelf, void *pvUser)
     2551{
     2552    RTSOCKETINT *pThis = (RTSOCKETINT *)pvUser;
     2553    RT_NOREF(hSelf);
     2554# define __WSAFDIsSet g_pfn__WSAFDIsSet
     2555
     2556    /*
     2557     * The execution loop.
     2558     */
     2559    while (!ASMAtomicReadBool(&pThis->fPollFallbackShutdown))
     2560    {
     2561        /*
     2562         * Do the selecting (with a 15 second timeout because that seems like a good idea).
     2563         */
     2564        struct fd_set SetRead;
     2565        struct fd_set SetWrite;
     2566        struct fd_set SetXcpt;
     2567
     2568        FD_ZERO(&SetRead);
     2569        FD_ZERO(&SetWrite);
     2570        FD_ZERO(&SetXcpt);
     2571
     2572        FD_SET(pThis->hPollFallbackNotifyR, &SetRead);
     2573        FD_SET(pThis->hPollFallbackNotifyR, &SetXcpt);
     2574
     2575        bool     fActive = ASMAtomicReadBool(&pThis->fPollFallbackActive);
     2576        uint32_t fEvents;
     2577        if (!fActive)
     2578            fEvents = 0;
     2579        else
     2580        {
     2581            fEvents = ASMAtomicReadU32(&pThis->fSubscribedEvts);
     2582            if (fEvents & RTPOLL_EVT_READ)
     2583                FD_SET(pThis->hNative, &SetRead);
     2584            if (fEvents & RTPOLL_EVT_WRITE)
     2585                FD_SET(pThis->hNative, &SetWrite);
     2586            if (fEvents & RTPOLL_EVT_ERROR)
     2587                FD_SET(pThis->hNative, &SetXcpt);
     2588        }
     2589
     2590        struct timeval Timeout;
     2591        Timeout.tv_sec  = 15;
     2592        Timeout.tv_usec = 0;
     2593        int rc = g_pfnselect(INT_MAX /*ignored*/, &SetRead, &SetWrite, &SetXcpt, &Timeout);
     2594
     2595        /* Stop immediately if told to shut down. */
     2596        if (ASMAtomicReadBool(&pThis->fPollFallbackShutdown))
     2597            break;
     2598
     2599        /*
     2600         * Process the result.
     2601         */
     2602        if (rc > 0)
     2603        {
     2604            /* First the socket we're listening on. */
     2605            if (   fEvents
     2606                && (   FD_ISSET(pThis->hNative, &SetRead)
     2607                    || FD_ISSET(pThis->hNative, &SetWrite)
     2608                    || FD_ISSET(pThis->hNative, &SetXcpt)) )
     2609            {
     2610                ASMAtomicWriteBool(&pThis->fPollFallbackActive, false);
     2611                SetEvent(pThis->hEvent);
     2612            }
     2613
     2614            /* Then maintain the notification pipe.  (We only read one byte here
     2615               because we're overly paranoid wrt socket switching to blocking mode.) */
     2616            if (FD_ISSET(pThis->hPollFallbackNotifyR, &SetRead))
     2617            {
     2618                char chIgnored;
     2619                g_pfnrecv(pThis->hPollFallbackNotifyR, &chIgnored, sizeof(chIgnored), MSG_NOSIGNAL);
     2620            }
     2621        }
     2622        else
     2623            AssertMsg(rc == 0, ("%Rrc\n", rtSocketError()));
     2624    }
     2625
     2626# undef __WSAFDIsSet
     2627    return VINF_SUCCESS;
     2628}
     2629
     2630
     2631/**
     2632 * Pokes the fallback thread, making sure it gets out of whatever it's stuck in.
     2633 *
     2634 * @param   pThis               The socket handle.
     2635 */
     2636static void rtSocketPokePollFallbackThread(RTSOCKETINT *pThis)
     2637{
     2638    Assert(pThis->fPollFallback);
     2639    if (pThis->hPollFallbackThread != NIL_RTTHREAD)
     2640    {
     2641        int cbWritten = g_pfnsend(pThis->hPollFallbackNotifyW, "!", 1, MSG_NOSIGNAL);
     2642        AssertMsg(cbWritten == 1, ("cbWritten=%d err=%Rrc\n",  rtSocketError()));
     2643        RT_NOREF_PV(cbWritten);
     2644    }
     2645}
     2646
     2647
     2648/**
     2649 * Called by rtSocketPollStart to make the thread start selecting on the socket.
     2650 *
     2651 * @returns 0 on success, RTPOLL_EVT_ERROR on failure.
     2652 * @param   pThis               The socket handle.
     2653 */
     2654static uint32_t rtSocketPollFallbackStart(RTSOCKETINT *pThis)
     2655{
     2656    /*
     2657     * Reset the event and tell the thread to start selecting on the socket.
     2658     */
     2659    ResetEvent(pThis->hEvent);
     2660    ASMAtomicWriteBool(&pThis->fPollFallbackActive, true);
     2661
     2662    /*
     2663     * Wake up the thread the thread.
     2664     */
     2665    if (pThis->hPollFallbackThread != NIL_RTTHREAD)
     2666        rtSocketPokePollFallbackThread(pThis);
     2667    else
     2668    {
     2669        /*
     2670         * Not running, need to set it up and start it.
     2671         */
     2672        AssertLogRelReturn(pThis->hEvent != NULL && pThis->hEvent != INVALID_HANDLE_VALUE, RTPOLL_EVT_ERROR);
     2673
     2674        /* Create the notification socket pair. */
     2675        int rc;
     2676        if (pThis->hPollFallbackNotifyR == NIL_RTSOCKETNATIVE)
     2677        {
     2678            rc = rtSocketCreateNativeTcpPair(&pThis->hPollFallbackNotifyW, &pThis->hPollFallbackNotifyR);
     2679            AssertLogRelRCReturn(rc, RTPOLL_EVT_ERROR);
     2680
     2681            /* Make the read end non-blocking (not fatal). */
     2682            u_long fNonBlocking = 1;
     2683            rc = g_pfnioctlsocket(pThis->hPollFallbackNotifyR, FIONBIO, &fNonBlocking);
     2684            AssertLogRelMsg(rc == 0,  ("rc=%#x %Rrc\n", rc, rtSocketError()));
     2685        }
     2686
     2687        /* Finally, start the thread.  ASSUME we don't need too much stack. */
     2688        rc = RTThreadCreate(&pThis->hPollFallbackThread, rtSocketPollFallbackThreadProc, pThis,
     2689                            _128K, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "sockpoll");
     2690        AssertLogRelRCReturn(rc, RTPOLL_EVT_ERROR);
     2691    }
     2692    return 0;
     2693}
     2694
     2695
     2696/**
    22902697 * Undos the harm done by WSAEventSelect.
    22912698 *
     
    22982705    if (pThis->fSubscribedEvts)
    22992706    {
    2300         if (g_pfnWSAEventSelect && g_pfnioctlsocket)
    2301         {
    2302             if (g_pfnWSAEventSelect(pThis->hNative, WSA_INVALID_EVENT, 0) == 0)
     2707        if (!pThis->fPollFallback)
     2708        {
     2709            Assert(g_pfnWSAEventSelect && g_pfnioctlsocket);
     2710            if (g_pfnWSAEventSelect && g_pfnioctlsocket)
    23032711            {
    2304                 pThis->fSubscribedEvts = 0;
    2305 
    2306                 /*
    2307                  * Switch back to blocking mode if that was the state before the
    2308                  * operation.
    2309                  */
    2310                 if (pThis->fBlocking)
     2712                if (g_pfnWSAEventSelect(pThis->hNative, WSA_INVALID_EVENT, 0) == 0)
    23112713                {
    2312                     u_long fNonBlocking = 0;
    2313                     int rc2 = g_pfnioctlsocket(pThis->hNative, FIONBIO, &fNonBlocking);
    2314                     if (rc2 != 0)
     2714                    pThis->fSubscribedEvts = 0;
     2715
     2716                    /*
     2717                     * Switch back to blocking mode if that was the state before the
     2718                     * operation.
     2719                     */
     2720                    if (pThis->fBlocking)
    23152721                    {
    2316                         rc = rtSocketError();
    2317                         AssertMsgFailed(("%Rrc; rc2=%d\n", rc, rc2));
     2722                        u_long fNonBlocking = 0;
     2723                        int rc2 = g_pfnioctlsocket(pThis->hNative, FIONBIO, &fNonBlocking);
     2724                        if (rc2 != 0)
     2725                        {
     2726                            rc = rtSocketError();
     2727                            AssertMsgFailed(("%Rrc; rc2=%d\n", rc, rc2));
     2728                        }
    23182729                    }
     2730                }
     2731                else
     2732                {
     2733                    rc = rtSocketError();
     2734                    AssertMsgFailed(("%Rrc\n", rc));
    23192735                }
    23202736            }
    23212737            else
    23222738            {
    2323                 rc = rtSocketError();
    2324                 AssertMsgFailed(("%Rrc\n", rc));
     2739                Assert(pThis->fPollFallback);
     2740                rc = VINF_SUCCESS;
    23252741            }
    23262742        }
     2743        /*
     2744         * Just clear the event mask as we never started waiting if we get here.
     2745         */
    23272746        else
    2328             rc = VERR_NET_NOT_UNSUPPORTED;
     2747            ASMAtomicWriteU32(&pThis->fSubscribedEvts, 0);
    23292748    }
    23302749    return rc;
     
    23412760static int rtSocketPollUpdateEvents(RTSOCKETINT *pThis, uint32_t fEvents)
    23422761{
    2343     LONG fNetworkEvents = 0;
    2344     if (fEvents & RTPOLL_EVT_READ)
    2345         fNetworkEvents |= FD_READ;
    2346     if (fEvents & RTPOLL_EVT_WRITE)
    2347         fNetworkEvents |= FD_WRITE;
    2348     if (fEvents & RTPOLL_EVT_ERROR)
    2349         fNetworkEvents |= FD_CLOSE;
    2350     LogFlowFunc(("fNetworkEvents=%#x\n", fNetworkEvents));
    2351     int rc;
    2352     if (g_pfnWSAEventSelect)
    2353     {
     2762    if (!pThis->fPollFallback)
     2763    {
     2764        LONG fNetworkEvents = 0;
     2765        if (fEvents & RTPOLL_EVT_READ)
     2766            fNetworkEvents |= FD_READ;
     2767        if (fEvents & RTPOLL_EVT_WRITE)
     2768            fNetworkEvents |= FD_WRITE;
     2769        if (fEvents & RTPOLL_EVT_ERROR)
     2770            fNetworkEvents |= FD_CLOSE;
     2771        LogFlowFunc(("fNetworkEvents=%#x\n", fNetworkEvents));
     2772
    23542773        if (g_pfnWSAEventSelect(pThis->hNative, pThis->hEvent, fNetworkEvents) == 0)
    23552774        {
     
    23572776            return VINF_SUCCESS;
    23582777        }
    2359         rc = rtSocketError();
     2778
     2779        int rc = rtSocketError();
    23602780        AssertMsgFailed(("fNetworkEvents=%#x rc=%Rrc\n", fNetworkEvents, rtSocketError()));
    2361     }
    2362     else
    2363         rc = VERR_NET_NOT_UNSUPPORTED;
    2364     return rc;
     2781        return rc;
     2782    }
     2783
     2784    /*
     2785     * Update the events we're waiting for.  Caller will poke/start the thread. later
     2786     */
     2787    ASMAtomicWriteU32(&pThis->fSubscribedEvts, fEvents);
     2788    return VINF_SUCCESS;
    23652789}
    23662790
     
    23892813        rc = rtSocketPollUpdateEvents(pThis, pThis->fSubscribedEvts | fEvents);
    23902814
    2391     /* Get the event mask, ASSUMES that WSAEnumNetworkEvents doesn't clear stuff.  */
    2392     if (g_pfnWSAEnumNetworkEvents)
    2393     {
     2815    if (!pThis->fPollFallback)
     2816    {
     2817        /* Atomically get pending events and reset the event semaphore. */
     2818        Assert(g_pfnWSAEnumNetworkEvents);
    23942819        WSANETWORKEVENTS NetEvts;
    23952820        RT_ZERO(NetEvts);
     
    24202845            rc = rtSocketError();
    24212846    }
    2422     else if (RT_SUCCESS(rc))
    2423         rc = VERR_NET_NOT_UNSUPPORTED;
    2424 
    2425     /* Fall back on select if we hit an error above. */
    2426     if (RT_FAILURE(rc))
    2427     {
    2428         rc = RTSocketSelectOneEx(pThis, fEvents, &fRetEvents, 0);
    2429         if (RT_FAILURE(rc))
     2847
     2848    /* Fall back on select if we hit an error above or is using fallback polling. */
     2849    if (pThis->fPollFallback || RT_FAILURE(rc))
     2850    {
     2851        rc = rtSocketSelectOneEx(pThis, fEvents & RTPOLL_EVT_ERROR ? fEvents | RTPOLL_EVT_READ : fEvents, &fRetEvents, 0);
     2852        if (RT_SUCCESS(rc))
     2853        {
     2854            /* rtSocketSelectOneEx may return RTPOLL_EVT_READ on disconnect.  Use
     2855               getpeername to fix this. */
     2856            if ((fRetEvents & (RTPOLL_EVT_READ | RTPOLL_EVT_ERROR)) == RTPOLL_EVT_READ)
     2857            {
     2858# if 0 /* doens't work */
     2859                rtSocketErrorReset();
     2860                char chIgn;
     2861                rc = g_pfnrecv(pThis->hNative, &chIgn, 0, MSG_NOSIGNAL);
     2862                rc = rtSocketError();
     2863                if (RT_FAILURE(rc))
     2864                    fRetEvents |= RTPOLL_EVT_ERROR;
     2865
     2866                rc = g_pfnsend(pThis->hNative, &chIgn, 0, MSG_NOSIGNAL);
     2867                rc = rtSocketError();
     2868                if (RT_FAILURE(rc))
     2869                    fRetEvents |= RTPOLL_EVT_ERROR;
     2870
     2871                RTSOCKADDRUNION u;
     2872                int cbAddr = sizeof(u);
     2873                if (g_pfngetpeername(pThis->hNative, &u.Addr, &cbAddr) == SOCKET_ERROR)
     2874                    fRetEvents |= RTPOLL_EVT_ERROR;
     2875# endif
     2876                /* If no bytes are available, assume error condition. */
     2877                u_long cbAvail = 0;
     2878                rc = ioctlsocket(pThis->hNative, FIONREAD, &cbAvail);
     2879                if (rc == 0 && cbAvail == 0)
     2880                    fRetEvents |= RTPOLL_EVT_ERROR;
     2881            }
     2882            fRetEvents &= fEvents | RTPOLL_EVT_ERROR;
     2883        }
     2884        else if (rc == VERR_TIMEOUT)
    24302885            fRetEvents = 0;
    2431     }
    2432 
    2433 #else  /* RT_OS_OS2 */
     2886        else
     2887            fRetEvents |= RTPOLL_EVT_ERROR;
     2888    }
     2889
     2890# else  /* RT_OS_OS2 */
    24342891    int aFds[4] = { pThis->hNative, pThis->hNative, pThis->hNative, -1 };
    24352892    int rc = os2_select(aFds, 1, 1, 1, 0);
     
    24442901        fRetEvents &= fEvents;
    24452902    }
    2446 #endif /* RT_OS_OS2 */
     2903# endif /* RT_OS_OS2 */
    24472904
    24482905    LogFlowFunc(("fRetEvents=%#x\n", fRetEvents));
     
    25242981        ASMAtomicDecU32(&pThis->cUsers);
    25252982    }
     2983# ifdef RT_OS_WINDOWS
     2984    /*
     2985     * Kick the poller thread on if this is the final entry and we're in
     2986     * winsock 1.x fallback mode.
     2987     */
     2988    else if (pThis->fPollFallback && fFinalEntry)
     2989        fRetEvents = rtSocketPollFallbackStart(pThis);
     2990# endif
    25262991
    25272992    return fRetEvents;
     
    25543019    RT_NOREF_PV(fFinalEntry);
    25553020
    2556     /* Harvest events and clear the event mask for the next round of polling. */
     3021# ifdef RT_OS_WINDOWS
     3022    /*
     3023     * Deactivate the poll thread if we're in winsock 1.x fallback poll mode.
     3024     */
     3025    if (   pThis->fPollFallback
     3026        && pThis->hPollFallbackThread != NIL_RTTHREAD)
     3027    {
     3028        ASMAtomicWriteU32(&pThis->fSubscribedEvts, 0);
     3029        if (ASMAtomicXchgBool(&pThis->fPollFallbackActive, false))
     3030            rtSocketPokePollFallbackThread(pThis);
     3031    }
     3032# endif
     3033
     3034    /*
     3035     * Harvest events and clear the event mask for the next round of polling.
     3036     */
    25573037    uint32_t fRetEvents = rtSocketPollCheck(pThis, fEvents);
    25583038# ifdef RT_OS_WINDOWS
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette