Subject InterServer & Windows Socket Problems
Author Paul Beach
A heavy user of InterClient / InterServer in the Windows environment, has
been seeing some very strange behaviour re. InterServer in there test
environment (they haven't shipped their product yet). On closer inspection
the following would happen....

On Windows NT, InterServer sockets would be left in a CLOSE_WAIT state until
the system was rebooted or InterServer was stopped and restarted whilst
on Windows 2000 InterServer sockets would remain in an ESTABLISHED state
even though the Client processes on both systems had successfully
disconnected by the JDBC connection.close() method. Since the application
uses a large number of sockets over time, eventually the systems would run
out of memory and hang, thus requiring a reboot.

On further investigation I found the following.

In the InterServer source code NetTCP.cpp, the socket close statement
consists of the following:

void
NetTCP::netClose (int sockfd)
{
close (sockfd)
}

This function is responsible for closing the server side socket when
InterClient no longer needs it.

Unfortunately if you start looking at the MS doc's re. sockets in detail,
you will find that:

"Close and Closesocket
Sockets are represented by standard file descriptors in Berkeley Sockets, so
the closesocket function can be used to close sockets as well as regular
files. While nothing in the Windows Sockets prevents an implementation from
using regular file handles to identify sockets, nothing requires it either.
Sockets must be closed by using the closesocket routine. Using the close
routine to close a socket is incorrect and the effects of doing so are
undefined by this specification."

Well we now know the effects :-)

If the call is changed to void
NetTCP::netClose (int sockfd)
{

#ifdef WIN32
// Close Windows Sockets Properly
closesocket (sockfd);
#endif

close (sockfd);
}

And the other close (socket) call in NetTCP are corrected to close Windows
sockets properly - don't forget the forked InterServer process

cf:

/*
* Fork a child process to handle the client's request.
* The parent returns the child pid to the caller, which is
* a multi-client server to wait for the next client request
*/
#ifdef WIN32
if ( (childpid = fork(tmpSockfd)) < 0)
Error::err_sys ("server can't fork");
else if (childpid > 0)
{ /* parent */
// Close Windows Sockets Properly
closesocket (tmpSockfd); /* close new connection */
return (childpid); /* and return */
}
#endif

The problem seems to go away. More serious testing on this to follow on the
InterClient users site.
I'll be posting these changes to the Firebird version of InterServer
shortly. I have to confess that digging into this has raised a number of
other minor (I think) issues that should be looked at in more detail.

However if there is demand for it, I can rebuild InterServer 2.0 with these
modifications and put it on ftp.ibphoenix.com, for anybody who needs it.

Oh and BTW its worth pulling in
#include <winsock2.h>
The updated Windows sockets header as well.

On the down side, it doesn't look like Borland have released the source code
for there recent changes to InterClient (2.01) and InterServer (2.02),
please somebody - correct me if I am wrong, so I can't put this fix into the
latest version.

Regards
Paul Beach
Main Tel (UK):+44 (0) 1844 354465
Mobile: (UK): +44 (0) 7764 188603
http://www.ibphoenix.com