5

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;
}
Community
  • 1
  • 1
shawn
  • 4,063
  • 7
  • 37
  • 54
  • 1
    MSDN says max time because the `select` wait ends if the socket will not block on accept. So either your select call isn't correct or a connection is available on the listening socket. If you post some code, it might be possible help you. – Gene Jun 12 '12 at 04:48
  • Checkout, is the timeout specifies in seconds or minutes. I think it must be in seconds not in minutes. – Viswesn Jun 12 '12 at 04:55
  • `tv.tv_usec` is microseconds, and `tv.tv_sec` is seconds. Also, please show the code you use for initializing the structures/fd_sets and the `select` call. – Some programmer dude Jun 12 '12 at 05:31
  • added code, units used should be correct – shawn Jun 12 '12 at 05:47
  • Just a thought, why not set `tv.tv_sec` to `2` and `tv.tv_usec` to `400000`? It's just the same as you have now, but more "correct". :) – Some programmer dude Jun 12 '12 at 05:54
  • Also, I know this is a Windows-only program, but you should make it a good habit to set the first argument to `select` correct just in case you in the future have to do it on a platform where the argument is used, so you don't forget it then. – Some programmer dude Jun 12 '12 at 05:57
  • tv.tv_sec = 2400; tv.tv_usec = 0; //2400000000; microseconds ok if i do it like this, it won't timeout immediately but why is this so? – shawn Jun 12 '12 at 06:05
  • 3
    Because you use tv_sec for timeouts *GREATER* than 1 second, tv_usec for timeouts *LESS* than 1 second, and you should *NOT* allow tv_usec > 1,000,000. – paulsm4 Jun 12 '12 at 06:47
  • 2
    `tv.tv_sec = ( timeout_in_microseconds / 1000000 ); tv.tv_usec = ( timeout_in_microseconds % 1000000 );` – bob2 Jun 12 '12 at 19:42

2 Answers2

4

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.

alk
  • 69,737
  • 10
  • 105
  • 255
2

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.

Viswesn
  • 4,674
  • 2
  • 28
  • 45
  • the range of long is -2147483648 and 2147483647. – Viswesn Jun 12 '12 at 06:55
  • I wonder if tv_usec=2147483647 really would lead to a time out of 2147s, but 0.483647s ... - no win32 available right now to check. – alk Jun 12 '12 at 16:14