shawn
shawn

Reputation: 4223

Setting winsock select timeout accurately

I am trying to make my accept call timeout after a specified time period and I tried following the suggestion here:

Winsock accept timeout

in which case I pass a TIMEVAL struct to select when I call it, problem is when I set tv.tv_usec to say around 40 minutes or so, the select call times out immediately instead of waiting for the 40 minutes I specified. MSDN states that the timeout for select is the maximum time that it will wait, how do I make it such that select or accept for that matter waits for a specific time period before timing out?

#define WIN32_LEAN_AND_MEAN

#include <Windows.h>

#include <WinSock2.h>
#include <Ws2tcpip.h>

#include <cstdio>
#include <tchar.h>

VOID _tmain( int argc, TCHAR *argv[] )
{
    WSADATA wsaData = { 0 };
    ADDRINFOA hINTs = { 0 };
    PADDRINFOA pResult = NULL;
    SOCKET hServerSocket = INVALID_SOCKET,
           hClientSocket = INVALID_SOCKET;
    TIMEVAL tv = { 0 };
    INT iReturnStatus = -1;
    DWORD dwRecvTimeout = 30000, // Milliseconds
          dwSendTimeout = 30000; // Milliseconds
    fd_set readFDs = { 0 };

    if ( WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) )
    {
        _tprintf_s( TEXT( "WSAStartup Failed\n" ) );
        return;
    }

    ZeroMemory( &hINTs, sizeof( hINTs ) );
    hINTs.ai_family = AF_INET;
    hINTs.ai_socktype = SOCK_STREAM;
    hINTs.ai_protocol = IPPROTO_TCP;
    hINTs.ai_flags = AI_PASSIVE;
    if ( getaddrinfo( NULL, TEXT( "9001" ), &hINTs, &pResult ) )
    {
        WSACleanup();
        _tprintf_s( TEXT( "getaddrinfo Failed\n" ) );
        return;
    }

    if ( ( hServerSocket = socket( pResult -> ai_family, pResult -> ai_socktype, pResult -> ai_protocol ) ) == INVALID_SOCKET )
    {
        freeaddrinfo( pResult );
        WSACleanup();
        _tprintf_s( TEXT( "socket Failed\n" ) );
        return;
    }

    int iResult = bind( hServerSocket, ( pResult -> ai_addr ), pResult -> ai_addrlen );
    if ( iResult == SOCKET_ERROR )
    {
        freeaddrinfo( pResult );
        closesocket( hServerSocket );
        WSACleanup();
        _tprintf_s( TEXT( "bind Failed\n" ) );
        return;
    }
    freeaddrinfo( pResult );

    if ( listen( hServerSocket, SOMAXCONN ) )
    {
        closesocket( hServerSocket );
        WSACleanup();
        _tprintf_s( TEXT( "listen Failed\n" ) );
        return;
    }

    hClientSocket = INVALID_SOCKET;

    for ( ;; )
    {
        tv.tv_usec = 2400000000; // microseconds
        FD_ZERO( &readFDs );
        FD_SET( hServerSocket, &readFDs );
        _tprintf( "select()\n" );
        iReturnStatus = select( 0, &readFDs, NULL, NULL, &tv );

        // Select Error
        if ( iReturnStatus == SOCKET_ERROR )
        {
            _tprintf( "select Failed\n" );
        }
        // Select Success
        else if ( iReturnStatus )
        {
            // Connection Established On Server Socket
            if ( FD_ISSET( hServerSocket, &readFDs ) )
            {
                // Accept Client Connection
                hClientSocket = accept( hServerSocket, NULL, NULL );
                if ( hClientSocket == INVALID_SOCKET )
                {
                    _tprintf( "accept Failed\n" );
                }
                else
                {
                    // Set Recv Timeout
                    setsockopt( hClientSocket, SOL_SOCKET, SO_RCVTIMEO, ( const char * ) &dwRecvTimeout, sizeof( dwRecvTimeout ) );

                    // Set Send Timeout                 
                    setsockopt( hClientSocket, SOL_SOCKET, SO_SNDTIMEO, ( const char * ) &dwSendTimeout, sizeof( dwSendTimeout ) );

                    // Process Client Request(s)
                    // HandleConnection( ClientSocket );
                }
            }
            // Connection Established On Unknown Socket
            else
            {
                _tprintf( "Invalid Socket Returned\n" );
            }
        }
        // Select Timeout
        else
        {
            _tprintf( "select Timeout\n" );
        }

    }
    if ( hServerSocket != INVALID_SOCKET )
        closesocket( hServerSocket );

    return;
}

Upvotes: 5

Views: 14275

Answers (2)

Viswesn
Viswesn

Reputation: 4880

The problem is with tv.tv_usec; tv_usec as per man page is of type 'long'. The value (2400000000) is out of range of long and that is the reason you are getting such select system behavior.

If you want select to wait for 40 min then make sure you are using tv.tv_sec.

Upvotes: 2

alk
alk

Reputation: 70941

why is this so?

This is per defintion.

Verbatim from MSDN:

tv_sec Time interval, in seconds.

tv_usec Time interval, in microseconds. This value is used in combination with the tv_sec member to represent time interval values that are not a multiple of seconds.

Upvotes: 4

Related Questions