Re: dirty socket growth problem

Peter Jones - JavaSoft East <[email protected]> Wed, 4 Jan 2006 17:50:55 -0500
Newsgroups gmane.comp.java.sun.rmi
Message-ID <20060104225054.GD18807@east>
> Finally we solved this problem.  I mentioned in my original post that I had
> added debug to our socket factories and it showed that when the growth
> occurred it was not using our socket factories - I placed the debug in the
> wrong place.  I should have put it in the accept method of the
> MyServerSocket because obviously once RMI has a server socket it can keep
> calling it to create more sockets.
>
> Anyway we played around with the accept code and discovered:
>
> // it is found if we invoke setSoTime or getSoTimeout before imp
> lAccept
> // the socket never got released by OS
> // workaround is to create a plain socket and call setSoTimeout
> after
> // implAccpet returns
> // Socket s = new MyClientSocket(); original code
> Socket s = new Socket();
> implAccept(s);
> s.setSoTimeout(10*1000); <---- PROBLEM IF BEFORE immplAccept
> return s;
>
> This problem did not occur with JDK1.3.  Can anybody from the Sun RMI group
> comment on this?

I think that I see an explanation for the behavior that you have
observed-- it seems to be the result of changes to java.net.Socket
between 1.3 and 1.4.

In 1.3, the file descriptor for a java.net.Socket is never created
until immediately before a connect or accept operation is performed.
If you attempt to invoke one of most of the option-setting methods on
an unconnected Socket, a SocketException will be thrown indicating
"Socket closed" (even though it was really just never connected).
setSoTimeout is implemented specially, however-- instead of making a
system call, the timeout value is just maintained in a field; because
no file descriptor is needed, it doesn't throw a SocketException.

In 1.4, the file descriptor for an unconnected Socket can get created
before a connect or accept operation if certain methods are invoked,
including the option-setting methods.  This is done to support using
the connect method that was added in 1.4, which provides a way to do a
connect operation after an unconnected Socket has been constructed.
Using the connect method allows specification of a connect timeout,
and with the option-setting methods now supporting an unconnected
Socket, it also allows the setting of socket options for the connect
itself.  setSoTimeout forces creation of the file descriptor too.

The "problem" is that ServerSocket.implAccept always stuffs a new file
descriptor in the provided Socket-- the one produced by the accept
system call.  If a descriptor had already been created for the Socket
because of a prior option-setting invocation as described above, that
descriptor will be forgotten, but never closed-- i.e. leaked.  (Also,
any options that had apparently been in effect by being set on the
underlying descriptor will have been lost.)

The solution for the case you describe seems straightforward: don't
invoke setSoTimeout until implAccept() has returned.  But there does
seem to be a bug of some sort here, in that this leak is allowed to
occur silently, and I haven't found a report filed for it yet...

-- Peter

===========================================================================
To unsubscribe, send email to [email protected] and include in the body
of the message "signoff RMI-USERS".  For general help, send email to
[email protected] and include in the body of the message "help".

For a list of frequently asked RMI questions please refer to:
http://java.sun.com/j2se/1.3/docs/guide/rmi/faq.html

To view past RMI-USERS postings, please see:
http://archives.java.sun.com/archives/rmi-users.html