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