JDK-4120329 : RMI registry creation is impossible if first attempt fails.
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.rmi
  • Affected Version: 1.2.0
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_nt
  • CPU: x86
  • Submitted: 1998-03-17
  • Updated: 1999-01-15
  • Resolved: 1999-01-15
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.2.0 1.2fcsFixed
Related Reports
Relates :  
Description

Name: rm29839			Date: 03/17/98


Consider a Java applications as RMI clients which
must support callbacks for use by servers.  The
'rmiregistry' may not be running on the client
systems.  Therefore, we attempt to create a registry via
java.rmi.registry.LocateRegistry.createRegistry(int port).
Thus, each invokation of the application has its
own unique registry available for callbacks, without
having to run 'rmiregistry' on the client systems.

Normally this works just fine.  The registry is
created, and the client application can register
its callback in the registry, and pass a reference
for the callback to the servers.  The callbacks
work just great.

However, if the port at which the client attempts
to create the registry is already in use, an
exception is thrown.  This is as it should be.
Now, additional attempts to create a registry are
tried by incrementing the port number to find an
unused port.  However, all of these second (and later)
attempts fail with a java.rmi.serverExportException
with text "Object ID already in use".

This has problem exists at least in the 1.1.5 and
1.2beta2 JDK on Windows NT and the 1.1.4 JDK on
Solaris.

The following simple client program duplicates the
problem:

import java.net.*;
import java.rmi.*;
import java.rmi.registry.*;
 
public class bad
{
   public static void main(String args[])
   {
      final int port = 5555;
 
      // Create a socket at particular port.
      try
      {
         ServerSocket sock = new ServerSocket(port);
      }
      catch (Exception e)
      {
         System.out.println(e.getMessage());
      }
      // Attempt to create a socket at the same port.  This should fail.
      System.out.println("--------------------------------------");
      System.out.println("First attempt to create registry.");
      try
      {
         LocateRegistry.createRegistry(port);
      }
      catch (Exception e)
      {
         System.out.println("Whoops, port is in use!");
         System.out.println(e.getMessage());
      }
 
      // Attempt to create a socket at the next available port. 
      System.out.println("--------------------------------------");
      System.out.println("Second attempt to create registry.");
      try
      {
         LocateRegistry.createRegistry(port + 1);
      }
      catch (Exception e)
      {
         System.out.println("Hmmm... not good!");
         e.printStackTrace();
      }
      System.out.println("--------------------------------------");
      System.exit(0);
   }
}

The output is:

--------------------------------------
First attempt to create registry.
Whoops, port is in use!
Port already in use: 5555; nested exception is: 
        java.net.BindException: Address already in use
--------------------------------------
Second attempt to create registry.
Hmmm... not good!
java.rmi.server.ExportException: Object ID already in use
        at sun.rmi.transport.ObjectTable.putTarget(ObjectTable.java:81)
        at sun.rmi.transport.Transport.exportObject(Transport.java:72)
        at sun.rmi.transport.tcp.TCPTransport.exportObject(TCPTransport.java:173)
        at sun.rmi.transport.tcp.TCPEndpoint.exportObject(TCPEndpoint.java:222)
        at sun.rmi.transport.LiveRef.exportObject(LiveRef.java:114)
        at sun.rmi.server.UnicastServerRef.exportObject(UnicastServerRef.java:92)
        at sun.rmi.registry.RegistryImpl.setup(RegistryImpl.java:88)
        at sun.rmi.registry.RegistryImpl.<init>(RegistryImpl.java:74)
        at sun.rmi.registry.RegistryHandler.registryImpl(RegistryHandler.java:65)
        at java.rmi.registry.LocateRegistry.createRegistry(LocateRegistry.java:131)
        at bad.main(bad.java:41)
--------------------------------------

My guess is that proper cleanup of the registry
object does not occur during exceptions.  Some
reference to the original failed registry creation
is still stored in some internal table, causing
the second and all subsequent attempts to create
a registry fail.  This "object ID" needs to be
cleaned up during a failed creation attempt.
(Review ID: 26291)
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: generic FIXED IN: 1.2fcs INTEGRATED IN: 1.2fcs
14-06-2004

WORK AROUND Name: rm29839 Date: 03/17/98 I have no workaround for this problem. We can randomize the port numbers the client attempt to use, but it is inevitable that there will be collisions with used ports. This introduces great instability into the clients. There is no workaround. If 'rmiregistry' runs on all client systems, this is not a problem. However, we cannot ensure that it is available on all client systems. ======================================================================
11-06-2004

EVALUATION adrian.colley@east 1998-03-30 Sounds like a job for try { ... } finally { ... }. Should be a simple fix. peter.jones@East 1998-03-31 I just glanced at this because it was in my last "bugs in the dispatched state" e-mail (I see that it's not in that state anymore). But anyway: I think that the problem is that we put the ObjID->impl mapping into the object table before actually trying to listen on the requested port (and if that fails, it is never removed). Simply putting the super.exportObject(...) call in TCPTransport.exportObject(...) after the whole "try { listen() ..." mess. adrian.colley@east 1998-06-03 I had to add a public evictID() method to ObjectTable so that RegistryImpl.setup could clean up after itself on failure. Awaiting code review.
03-06-1998