gln
gln

Reputation: 1031

WSAWaitForMultipleEvents and NetworkEvents

I'm trying to get FD_CLOSE event (c++) by WSAWaitForMulipleObjects. in the WSASelectEvent I've set only the FD_CLOSE. however, the wait return, and the network enumaration also return 0, but NetworkEvents return 0 from the enumaration so I can't see FD_CLOSE in it.

Any help?

thanks.

void EventThread(void* obj)
{

    WSANETWORKEVENTS NetworkEvents;

    WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
    DWORD EventTotal = 0; 
    EventArray[EventTotal] = WSACreateEvent();
    EventTotal++;
    int res;
    int index;
    if(WSAEventSelect(_socket, EventArray[EventTotal - 1], FD_CLOSE)==SOCKET_ERROR)
        Logger::GetInstance() << "WSAEventSelect failed with error " << WSAGetLastError() << endl;

    bool bResult;
    while(true)
    {
        if((index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE))==WSA_WAIT_FAILED)
        {
            Logger::GetInstance() << "WSAWaitForMultipleEvents failed with error " << WSAGetLastError() << endl;
        }


         if ((index != WSA_WAIT_FAILED) && (index != WSA_WAIT_TIMEOUT)) {
            res = WSAEnumNetworkEvents(_socket, EventArray[index - WSA_WAIT_EVENT_0], &NetworkEvents) ;

            if(NetworkEvents.lNetworkEvents & FD_CLOSE)
            {
                if(NetworkEvents.iErrorCode[FD_CLOSE_BIT] !=0)
                {
                    Logger::GetInstance() << "FD_CLOSE failed with error " << NetworkEvents.iErrorCode[FD_CLOSE_BIT] << endl;
                }
                else
                {
                    Logger::GetInstance() << "FD_CLOSE is OK!!! " << NetworkEvents.iErrorCode[FD_CLOSE_BIT] << endl;
                }
            }
         }


    }

}

Upvotes: 1

Views: 3960

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 596672

The WinSock documentation says the following:

The FD_CLOSE message is posted when a close indication is received for the virtual circuit corresponding to the socket. In TCP terms, this means that the FD_CLOSE is posted when the connection goes into the TIME_WAIT or CLOSE_WAIT states. This results from the remote end performing a shutdown() on the send side or a closesocket(). FD_CLOSE should only be posted after all data is read from a socket, but an application should check for remaining data upon receipt of FD_CLOSE to avoid any possibility of losing data.

Be aware that the application will only receive an FD_CLOSE message to indicate closure of a virtual circuit, and only when all the received data has been read if this is a graceful close. It will not receive an FD_READ message to indicate this condition.

...

Here is a summary of events and conditions for each asynchronous notification message.

...

FD_CLOSE: Only valid on connection-oriented sockets (for example, SOCK_STREAM)

  1. When WSAAsyncSelect() called, if socket connection has been closed.

  2. After remote system initiated graceful close, when no data currently available to receive (Be aware that, if data has been received and is waiting to be read when the remote system initiates a graceful close, the FD_CLOSE is not delivered until all pending data has been read).

  3. After local system initiates graceful close with shutdown() and remote system has responded with "End of Data" notification (for example, TCP FIN), when no data currently available to receive.

  4. When remote system terminates connection (for example, sent TCP RST), and lParam will contain WSAECONNRESET error value.

Note FD_CLOSE is not posted after closesocket() is called.

Pulling out the network cable does not satisfy any of those conditions. This is actually by design, as networks are designed to handle unexpected outages so they can maintain existing connections as best as they can during short outages. Wait a few minutes until the OS times out and see what happens. Also, when you put the cable back in, the OS will validate pre-existing connections and then may or may not reset them at that time.

Upvotes: 1

Related Questions