Multihomed Hosts and Java RMI

It can be challenging to get Java RMI communication working right between components on multihomed hosts. To see why, it’s important to understand how RMI determines the server hostname, which ultimately ends up being passed around in RMI stubs. If a client uses an RMI stub to make a remote method call and can’t connect to the remote object’s hostname, the usual result is the following exception:

java.rmi.ConnectException: Connection refused to host: <dotted IP address>; nested exception is: Connection timed out: connect
	at sun.rmi.transport.tcp.TCPEndpoint.newSocket(Unknown Source)
	at sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source)
	at sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
	at sun.rmi.server.UnicastRef.invoke(Unknown Source)
	at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
	at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)

Attempting to ping the host in the exception fails.

How RMI determines the server hostname is addressed in the RMI FAQ. In a nutshell, the default server hostname is the IP address returned by InetAddress.getLocalHost().getHostAddress(), e.g. 192.168.X.X. I’ve noticed that this often is the wrong IP address. For example, on my development machine this returns the IP address for my VMware NIC, which isn’t reachable by clients on my network.

Setting the RMI system property java.rmi.server.hostname to a routable hostname is the best way to fix this problem. This value can be a DNS hostname (preferred) which will be resolved by the client’s naming service, or a dotted IP address.

Another RMI system property, java.rmi.server.useLocalHostname, set to true may also work. However, if a fully qualified hostname containing a “.” character can’t be obtained from the local name service, the IP address returned by InetAddress.getLocalHost().getHostAddress() is used again as the default. Since I use NetBIOS naming on my network, hostnames don’t contain a “.” character, and the problem remains.

The workaround/evaluation section for this bug case and this post by E. McManus also contain a good explanation of what’s happening here.