JDK-6287178 : SecurityManager.checkAccept(..) method extremely slow!
  • Type: Bug
  • Component: security-libs
  • Sub-Component: java.security
  • Affected Version: 5.0
  • Priority: P3
  • Status: Closed
  • Resolution: Cannot Reproduce
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2005-06-17
  • Updated: 2010-04-03
  • Resolved: 2005-11-17
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_02-b09)
Java HotSpot(TM) Client VM (build 1.5.0_02-b09, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

EXTRA RELEVANT SYSTEM CONFIGURATION :
Simple LAN, DNS Server not configured all clients configured with 192.168.0.X ip addresses.


A DESCRIPTION OF THE PROBLEM :
   If you try to use a SecurityManager for RMI without a DNS server, checkAccept(..) method usually try to lookup DNS server for client hostnames or IP addresses. This takes long time.

   I use this permission in policy file;

permission java.net.SocketPermission "*:1024-", "accept,connect,resolve";

So I permit all hosts with "*". I think if I give a "*" for hostname no DNS lookups must occur. Because we don't need any hostname or ip address for this permission.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Please compile following files and try to run;

Run server with this command;

java -Djava.security.policy=server.policy Server 192.168.0.1 1977

And go another machine which has Windows XP on it and run client with;

java Client 192.168.0.1 1977

DON'T USE DNS SERVER.

On server machine you will see; (Note: Server machine IP: 192.168.0.1)

checkAccept(String host, int port) -> 34000 ms. -> 192.168.0.2 -> 1566
checkAccept(String host, int port) -> 17000 ms. -> 192.168.0.2 -> 1567
checkAccept(String host, int port) -> 17000 ms. -> 192.168.0.2 -> 1568
checkAccept(String host, int port) -> 17016 ms. -> 192.168.0.2 -> 1568
checkAccept(String host, int port) -> 17000 ms. -> 192.168.0.2 -> 1568
-> sayHello called. -> clientHost=192.168.0.2 -> name='Call #1'

On Client machine you will see; (Note: Client machine IP: 192.168.0.2)

-> Object lookup OK: Proxy[Hello,RemoteObjectInvocationHandler[UnicastRef [liveRef: [endpoint:[192.168.0.1:1977](remote),objID:[-6c2a94f5:1037e68ebb8:-8000, 0]]]]]
-> Lookup Time: 91001 ms.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Fast responses.
ACTUAL -
Very slow responses.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
no errors, just slow responses

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
// Hello.java ----------
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Hello extends Remote {
    public String sayHello(String name) throws RemoteException;
}

// HelloImpl.java ----------
import java.sql.Timestamp;
import java.rmi.server.RemoteServer;
import java.rmi.server.*;

public class HelloImpl implements Hello {

    public HelloImpl() {
    }

    public String sayHello(String name) {
        String result = null;
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        result = "Hello " + name + ". Server Time Is: " + timestamp.toString();
        String clientHost = null;
        try {
            clientHost = RemoteServer.getClientHost();
        } catch (ServerNotActiveException ex) {
            ex.printStackTrace();
        }
        System.out.print("-> sayHello called. -> clientHost=" + clientHost);
        System.out.println(" -> name=" + name);
        return result;
    }

}

// MrSeaRMISecurityManager.java ----------
import java.rmi.RMISecurityManager;

public class MrSeaRMISecurityManager extends RMISecurityManager {

    public MrSeaRMISecurityManager() {
    }

    public void checkConnect(String host, int port) {
        long start = 0, end = 0;
        start = System.currentTimeMillis();
        super.checkConnect(host, port);
        end = System.currentTimeMillis();
        System.out.println("checkConnect(String host, int port) -> " +
                           (end - start) + " ms. -> " + host + " -> " + port);
    }

    public void checkConnect(String host, int port, Object context) {
        long start = 0, end = 0;
        start = System.currentTimeMillis();
        super.checkConnect(host, port, context);
        end = System.currentTimeMillis();
        System.out.println(
                "checkConnect(String host, int port, Object context) -> " +
                (end - start) + " ms. -> " + host + " -> " + port);
    }

    public void checkAccept(String host, int port) {
        long start = 0, end = 0;
        start = System.currentTimeMillis();
        super.checkAccept(host, port);
        end = System.currentTimeMillis();
        System.out.println(
                "checkAccept(String host, int port) -> " + (end - start) +
                " ms. -> " + host + " -> " + port);
    }

}

// Server.java ----------
import java.rmi.Naming;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.ExportException;
import java.rmi.server.UnicastRemoteObject;
import java.net.UnknownHostException;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RMISecurityManager;

public class Server {
    private static final String OBJECT_NAME = "Hello";
    private String host;
    private int port;
    private String fullObjectBaseURL;
    private Registry rmiRegistry;

    public Server(String host, int port) {
        this.host = host;
        this.port = port;
        this.fullObjectBaseURL = "//" + this.host + ":" + this.port + "/";
    }

    private void startRMIRegistry() throws RemoteException {
        this.rmiRegistry = null;
        try {
            this.rmiRegistry = LocateRegistry.createRegistry(this.port);
            System.out.println("-> rmiregistry started. Port: " + this.port);
        } catch (ExportException eex) {
            System.out.println("-> rmiregistry was working. Port: " + this.port);
            this.rmiRegistry = LocateRegistry.getRegistry(this.host, this.port);
        }
    }

    private void createExportAndRebindObject() throws RemoteException,
            MalformedURLException {
        HelloImpl helloImpl = new HelloImpl();
        System.setProperty("java.rmi.server.hostname", this.host);
        Remote remoteObject = UnicastRemoteObject.exportObject(
                (Remote) helloImpl, this.port);
        System.out.println("-> Object export OK: " + remoteObject.toString());
        String rebindName = this.fullObjectBaseURL + Server.OBJECT_NAME;
        long start = System.currentTimeMillis();
        Naming.rebind(rebindName, remoteObject);
        long end = System.currentTimeMillis();
        System.out.println("-> Object rebind OK: " + rebindName);
        System.out.println("-> Rebind Time: " + (end - start) + " ms.");
    }

    public static void main(String[] args) throws UnknownHostException,
            RemoteException, MalformedURLException {
        String host = null;
        String port = null;
        if (args.length > 0) {
            host = args[0];
        }
        if (args.length > 1) {
            port = args[1];
        }
        if (port != null) {
            try {
                Integer.parseInt(port);
            } catch (NumberFormatException nfex) {
                port = null;
            }
        }
        if (host == null || port == null) {
            System.out.println("Usage; Server host port");
            System.exit( -1);
        }
        Server server = new Server(host, Integer.parseInt(port));
        // set our security manager
        System.setSecurityManager(new MrSeaRMISecurityManager());
        //
        server.startRMIRegistry();
        server.createExportAndRebindObject();
        //
        String[] list = server.rmiRegistry.list();
        for (int i = 0; i < list.length; i++) {
            System.out.println("-> rmiregistry.list[" + i + "]=" + list[i]);
        }
        // wait forever
        while (true) {
            try {
                Thread.currentThread().sleep(Long.MAX_VALUE);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }

}

// Client.java
import java.rmi.RemoteException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.net.MalformedURLException;
import java.io.IOException;

public class Client {
    private static final String OBJECT_NAME = "Hello";
    private String host;
    private int port;
    private String fullObjectBaseURL;

    public Client(String host, int port) {
        this.host = host;
        this.port = port;
        this.fullObjectBaseURL = "//" + this.host + ":" + this.port + "/";
    }

    private Remote getRemoteObject() throws RemoteException,
            MalformedURLException, NotBoundException {
        Remote result = null;
        String rebindName = this.fullObjectBaseURL + Client.OBJECT_NAME;
        long start = System.currentTimeMillis();
        result = Naming.lookup(rebindName);
        long end = System.currentTimeMillis();
        System.out.println("-> Object lookup OK: " + result);
        System.out.println("-> Lookup Time: " + (end - start) + " ms.");
        return result;
    }

    public static void main(String[] args) throws RemoteException,
            MalformedURLException, NotBoundException {
        String host = null;
        String port = null;
        if (args.length > 0) {
            host = args[0];
        }
        if (args.length > 1) {
            port = args[1];
        }
        if (port != null) {
            try {
                Integer.parseInt(port);
            } catch (NumberFormatException nfex) {
                port = null;
            }
        }
        if (host == null || port == null) {
            System.out.println("Usage; Client host port");
            System.exit( -1);
        }
        Client client = new Client(host, Integer.parseInt(port));

        Hello hello = (Hello) client.getRemoteObject();

        long start = 0;
        long end = 0;
        String result = null;
        int callNo = 0;
        System.out.println("");
        while (true) {
            callNo++;
            start = System.currentTimeMillis();
            result = hello.sayHello("'Call #" + callNo + "'");
            end = System.currentTimeMillis();
            System.out.println("-> RMI Call OK. Result -------> " + result);
            System.out.println("-> Call Time: " + (end - start) + " ms.");
            try {
                System.out.println("Press enter to make a new remote call.");
                System.in.read();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

}

// server.policy ----------
grant codebase "file:/-" {
    permission java.util.PropertyPermission "java.rmi.server.hostname", "write";
    permission java.net.SocketPermission "*:1024-", "accept,connect,resolve";
};

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
1.   Just disable SecurityManager and DON'T USE any SecurityManager without DNS server. (This is not a reasonable workaround.)

2.   Add a line into Server's "hosts" file for every client like this;

192.168.0.1 server
192.168.0.2 client1
192.168.0.3 client2
###@###.### 2005-06-17 09:12:46 GMT

Comments
EVALUATION The submitter has added a note to the webbug suggesting that CR 5092063 might be the cause of this bug. CR 5092063 has been fixed for Mustang. I am closing this as non-reproducible as I cannot reproduce it. If the submitter can still reproduce this problem with Mustang, it should be reopened.
17-11-2005