Jess Holle wrote:
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.
I forgot the -u on my diff.  Here's a unified diff.

--
Jess Holle

--- proxy_util-2.2.9.c  2008-05-28 16:11:24.000000000 -0500
+++ proxy_util.c        2008-10-13 14:32:26.342593500 -0500
@@ -29,6 +29,10 @@
 #define apr_socket_create apr_socket_create_ex
 #endif
 
+#ifdef WIN32
+#include <iphlpapi.h>
+#endif
+
 /* Global balancer counter */
 int PROXY_DECLARE_DATA proxy_lb_workers = 0;
 static int lb_workers_limit = 0;
@@ -2266,6 +2270,131 @@
 }
 #endif /* USE_ALTERNATE_IS_CONNECTED */
 
+#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
+
 PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
                                             proxy_conn_rec *conn,
                                             proxy_worker *worker,
@@ -2348,6 +2477,13 @@
                      "proxy: %s: fam %d socket created to connect to %s",
                      proxy_function, backend_addr->family, worker->hostname);
 
+#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
         /* make the connection out of the socket */
         rv = apr_socket_connect(newsock, backend_addr);
 

Reply via email to