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