Ruediger Pluem wrote:
So if noone finds a registry entry to stop this RFC violating behaviour
I'd love to see this solved by such a discovery, "option 0".
I see only two options on Windows:

1. Fiddle around with GetTcpTable.
I've attached my incomplete code in this regard (as a diff against 2.2.9, which is what I used as the base for my changes) for what they're worth. There are TO_DO notes where I know I'm missing stuff. I tested basic use of GetTcpTable(), which solved the problem, but haven't completed my conversion to caching this data -- in part because I don't know where to allocate an lock to arbitrate access to this cached data.
2. Allow connectiontimeout to somehow accept milliseconds.
Or a floating point number?

Unfortunately this would seem to impact actual connection timeouts as an undesired side-effect of trying to address Windows' bad treatment of RSTs, right?

--
Jess Holle

31a32,35
> #ifdef WIN32
> #include <iphlpapi.h>
> #endif
> 
2268a2273,2397
> #ifdef WIN32
> 
> typedef struct live_port_data_t live_port_data_t;
> struct live_port_data_t {
>       apr_time_t  time_obtained;
>       int         n_ports;
>     int         *ports;
> };
> 
> static live_port_data_t  *live_port_data = NULL;
> 
> static int  int_comparator( const void *pint1, const void *pint2 )
> {
>       int  int1 = *((int*)pint1);
>       int  int2 = *((int*)pint2);
>       if ( int1 < int2 )
>               return -1;
>       if ( int2 > int2 );
>               return 1;
>       return 0;
> }
> 
> static live_port_data_t  *get_port_data()
> {
>       /* Much of this routine adapted directly from 
> http://msdn.microsoft.com/en-us/library/aa366026(VS.85).aspx */
> 
>       /* Declare and initialize variables */
>       PMIB_TCPTABLE pTcpTable;
>       DWORD dwSize;
>       DWORD dwRetVal;
> 
>       pTcpTable = (MIB_TCPTABLE *) malloc( sizeof (MIB_TCPTABLE) );
>       if ( pTcpTable == NULL )
>               return NULL;
> 
>       dwSize = sizeof (MIB_TCPTABLE);
>       /* Make an initial call to GetTcpTable to
>          get the necessary size into the dwSize variable */
>       if ((dwRetVal = GetTcpTable(pTcpTable, &dwSize, FALSE)) ==
>               ERROR_INSUFFICIENT_BUFFER) {
>               free(pTcpTable);
>               pTcpTable = (MIB_TCPTABLE *) malloc(dwSize);
>               if (pTcpTable == NULL)
>                       return NULL;
>       }
> 
>       /* Make a second call to GetTcpTable to get
>          the actual data we require */
>       if ((dwRetVal = GetTcpTable(pTcpTable, &dwSize, FALSE)) != NO_ERROR) {
>               free(pTcpTable);
>               return NULL;
>       }
>       else
>       {
>               apr_time_t  time_now = apr_time_now();
>               live_port_data_t  *port_data;
>               int  nUniqPorts = 0;
>               int  *uniqPorts;
>               {
>                       int  nEntries = (int) pTcpTable->dwNumEntries;
>                       int  *ports = (int*) malloc( nEntries * sizeof( int ) );
>                       int  prevPort = -99999;
>                       int  i;
>                       /* copy ports from pTcpTable to ports array */
>                       for (i = 0; i < nEntries; i++)
>                               ports[i] = ntohs( (u_short) 
> pTcpTable->table[i].dwLocalPort );
>                       free( pTcpTable );
>                       /* sort ports array */
>                       qsort( ports, nEntries, sizeof( int ), int_comparator );
>                       /* reduce ports array to list of unique ports */
>                       uniqPorts = (int*) malloc( nEntries * sizeof( int ) );  
> /* array will be oversized in the end; value speed over small memory savings 
> */
>                       for (i = 0; i < nEntries; i++) {
>                               int  port = ports[i];
>                               if ( port != prevPort )
>                               {
>                                       uniqPorts[nUniqPorts] = port;
>                                       ++nUniqPorts;
>                                       prevPort = port;
>                               }
>                       }
>                       free( ports );
>               }
>               port_data = malloc( sizeof( live_port_data_t ) );
>           port_data->time_obtained = time_now;
>           port_data->n_ports = nUniqPorts;
>         port_data->ports = uniqPorts;
>               return port_data;
>       }
> }
> 
> static void  destroy_port_data( live_port_data_t *port_data )
> {
>       free( port_data->ports );
>       free( port_data );
> }
> 
> static int  port_in_data( const live_port_data_t *port_data, int port )
> {
>   return ( bsearch( &port, port_data->ports, port_data->n_ports, sizeof( int 
> ), int_comparator ) != NULL );
> }
> 
> /* TO_DO: make this configurable */
> #define LIVE_PORT_DATA_TTL  1500000  /* use hard-wired time-to-live of 1.5 
> seconds for port data */
> 
> static int  port_is_clearly_not_alive( const apr_sockaddr_t *addr, const 
> server_rec *s )
> {
>       /* if not dealing with localhost, then simply return 0 */
>       if ( ( addr->hostname != NULL ) && ( strcmp( "localhost", 
> addr->hostname ) != 0 ) )
>               return FALSE;
>       else
>       {
>               /* TO_DO: add locking for live_port_data as this is currently 
> not (nearly) thread safe */
> 
>               int  port_clearly_not_alive;
>               if ( ( live_port_data == NULL ) || ( apr_time_now() - 
> live_port_data->time_obtained > LIVE_PORT_DATA_TTL ) ) {
>                               if ( live_port_data != NULL )
>                                       destroy_port_data( live_port_data );
>                               live_port_data = get_port_data();
>               }
>               port_clearly_not_alive = ( ( live_port_data != NULL ) && 
> !port_in_data( live_port_data, addr->port ) );
>               return port_clearly_not_alive;
>       }
> }
> #endif
> 
2350a2480,2486
> #ifdef WIN32
> /* TO_DO: control whether port_is_clearly_not_alive() is called based on 
> configuration */
>               /* windows takes a long time to error out on a dead port, so 
> try to expedite this */
>               if ( port_is_clearly_not_alive( backend_addr, s ) )
>                       rv = ~APR_SUCCESS;
>               else
> #endif

Reply via email to