-1

At first glance this may seem like a basic networking issue - but I think that is not the case. It seems like Java itself is "ignoring" the RMI connection.

All Java 8u101 on Windows 10 PCs.

We have a quite mature and robust distributed Java application that communicates via RMI on a LAN.
There has been no problem at all for our customers who have run our application on their LANs for many years. This same application also connects to a shared database (on the same "server" PC as the RMI server).

One of our customers has recently established a new building maybe 100 metres away, and their two premises are connected over a WAN. However the Java clients at the remote site cannot connect to the Java RMI server.

It seems that all the networking itself is OK as follows ....

  • on the LAN everything runs perfectly as normal
  • Non RMI is OK:
    • from the remote location we can run a different database client and successfully connect to the Database Server (on the same PC as the RMI server)
  • RMI port seem OK from the client end
    • using telnet client at the remote location we can establish a connection to the RMI port
  • RMI port seems to connect at the server PC:
    • on the PC that runs the Java RMI server itself we can witness the connections via "netstat -an" which show the established connection arriving from the appropriate WAN IP address.

This indicated (to me) that the connection is getting to the correct location and is not being blocked by misconfiguration or a firewall or anything. It seems to get "in" to the RMI server PC, but then does not get to the RMI server itself.

My first guess was to try to use something like "Java Control Panel" and perhaps adjust a security setting that might be restricting RMI traffic - but I can't recognise any such switch.

Can anyone offer any clues on this?

  • any way to verify that the connection gets to Java?
  • might it be a Java security that is blocking this before it passes on to RMI server?

Any suggestions or guidance would be most appreciated.

(Edited, adding more details ...)

A little more information is as follows ...

  • within the LAN the server PC is known as 192.168.0.110
  • from the remote location (via the WAN) the server PC is known as 110.142.83.167
  • the remote client seems to get the RMI server object
  • The stack trace (detailed below) has "Connection refused to host: 192.168.0.110;"
  • so there seems to be confusion as to which IP address it is. The client asked for 110.142.83.167, but the server thinks it is 192.168.0.110

The stack traces are as follows ...

2016-10-18 15:02:11,123 [S38P4][43983  ][AWT-EventQueue-0] WARN  StackTraceLogger log: StackTraceLogger ------- INFO=ClientRMIObject.connectToSentry(): RemoteException: sentryIP=110.142.83.167<<
StackTraceLogger ------ Throwable.MSG=Connection refused to host: 192.168.0.110; nested exception is: 
    java.net.ConnectException: Connection timed out: connect< Throwable=java.rmi.ConnectException: Connection refused to host: 192.168.0.110; nested exception is: 
    java.net.ConnectException: Connection timed out: connect
StackTraceLogger.START TRACE .................................
   sun.rmi.transport.tcp.TCPEndpoint.newSocket(Unknown Source)
   sun.rmi.transport.tcp.TCPChannel.createConnection(Unknown Source)
   sun.rmi.transport.tcp.TCPChannel.newConnection(Unknown Source)
   sun.rmi.server.UnicastRef.invoke(Unknown Source)
   java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
   java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
   com.sun.proxy.$Proxy13.registerWithSentry(Unknown Source)
   com.my.co.package.ClientRMIObject.connectToSentry(ClientRMIObject.java:198)

Following super cut down version (no boiler plate etc) of the code ...

At RMI server ...

// auto called at server on startup ...
public final class MyServer {
  public final static int SRVR_PORT = 21099;
  public final static String LOOKUP_NAME = "MyLookupName";
  public MyServer() {
      java.rmi.registry.Registry reg = java.rmi.registry.LocateRegistry.createRegistry(SRVR_PORT);
      ServerRMIObject srvrRmiObj = new ServerRMIObject();
      reg.rebind(LOOKUP_NAME, srvrRmiObj);
  }
}

ServerRMIObject ...

public final class ServerRMIObject extends java.rmi.server.UnicastRemoteObject {
  private List<ClientRMIObject> clients = ...

  public ServerRMIObject() throws java.rmi.RemoteException {
    super(MyServer.SRVR_PORT);
  }

  public void registerWithSrvr(ClientRMIObject client) {
    logger.info("This line is never run when called from remote location");
    clients.add(client);
  }

  // example method ...
  public void broadcastToClients(Delivery d) {
    for (ClientRMIObject client : clients) {
      client.receiveFromSrvr(d);
    }
  }
}

At each RMI client ...

public final class ClientRMIObject extends java.rmi.server.UnicastRemoteObject {

  private final int CLIENT_PORT = 21099;
  private final String SRVR_FROM_LAN = "//192.168.0.110:"+MyServer.SRVR_PORT+"/"+MyServer.LOOKUP_NAME; 
  private final String SRVR_FROM_WAN = "//110.142.83.167:"+MyServer.SRVR_PORT+"/"+MyServer.LOOKUP_NAME;
  private ServerRMIObject rmiSrvr = null;

  public ClientRMIObject() {
    super(CLIENT_PORT);
  }

  // auto called at client on startup
  public void start() {
    if (VIA_LAN) {
        rmiSrvr = java.rmi.Naming.lookup(SRVR_FROM_LAN);
    } else if (VIA_WAN) {
        rmiSrvr = java.rmi.Naming.lookup(SRVR_FROM_WAN);
    }

    // this has been successful to here. 

    // the following throws an exception ...
    // java.rmi.ConnectException: Connection refused to host: 192.168.0.110; 
    // please see more exception details above        
    rmiSrvr.registerWithSrvr(this); 

  }

  // example method ...
  public void receiveFromSrvr(Delivery d) {
     ....
  }

  // example broadcast from one client to all clients ...
  public void broadcastToClients(Delivery d) {
    rmiSrvr.broadcastToClients(d);
  }
}
Damian C
  • 79
  • 1
  • 8
  • Define 'cannot connect'. What happens instead? – user207421 Oct 17 '16 at 11:47
  • have you explicitly specified _both_ rmi ports? – jtahlborn Oct 17 '16 at 13:11
  • Thank you EJP and jtahlborn for your responses. – Damian C Oct 18 '16 at 04:43
  • Woops, too quick with the enter button .... jtahlborn: I believe I have specifed both ports (client * server sides) EJP: I have added more details in the question includind the location of the exception. – Damian C Oct 18 '16 at 04:45
  • I don't see any code that calls `registerWithSentry()` anywhere, and I also don't see any remote interfaces, or remote objects that implement them. This isn't correct RMI yet. – user207421 Oct 18 '16 at 05:01
  • EJP. Again, thanks for taking the time. I have further cleaned up the code samples. These samples are tiny stylised fragments of 3 classes that have around 2000 lines total - so I have tried to be simultaneously "faithful to the original" and "clear to the reviewer". Some terms (eg "sentry") had leaked across from the source. I believe the server side is starting OK. I believe that the client gets the ServerRMIObject, but the ServerRMIObject refuses to allow the client to call its method "rmiSrvr.registerWithSrvr(...)". – Damian C Oct 18 '16 at 05:45
  • Sounds like a case of [RMI FAQ item #A.1](https://docs.oracle.com/javase/8/docs/technotes/guides/rmi/faq.html#domain) to me. – user207421 Oct 18 '16 at 09:37
  • And it is hardly a case of Java 'ignoring' anything. An exception doesn't constitute ignoring something. – user207421 Sep 07 '20 at 05:05

2 Answers2

2

We have faced similar issue when we upgraded RMI server machines to WINDOWS 10.

This exception is due to windows firewall of Windows10 on which server is running is not allowing traffic to ports via TCP protocol.

To enable windows10 firewall for TCP we need to follow below steps: 1. Open control panel 2. Windows firewall -> Advanced settings 3. Click inbound rules 4. In the right column -> new rule option 5. Make a port rule and create both a TCP and UDP rule, both on - local port 1099 /All ports 6. In the action section, click "allow the connection" 7. Keep everything checked for where the rule applies

ladybug
  • 39
  • 7
1

From https://docs.oracle.com/javase/8/docs/technotes/guides/rmi/javarmiproperties.html

java.rmi.server.hostname

The value of this property represents the host name string that should be associated with remote stubs for locally created remote objects, in order to allow clients to invoke methods on the remote object. The default value of this property is the IP address of the local host, in "dotted-quad" format.

The RMI registry reports back to the client an IP address (or hostname) and a port which the client can then connect to to invoke the remote object. By default, it uses the address of the local host.

Your server is configured with the IP address 192.168.0.110 and thus, that is what the RMI registry reports back with. The RMI registry does not know that you want to access the machine through some other IP address (namely the publicly routable 110.142.83.167 - nor could it reasonable know if it is the case that a firewall is doing Network Address Translation).

The conversation goes like this:

  • WAN Client connects to RMI registry at 110.142.83.167.
  • WAN Client asks: I'd like to know how to talk to object Foo
  • RMI registry reports: You can reach Foo at 192.168.0.110:<some port>
  • WAN Client tries to connect to 192.168.0.110:<some port>, but that machine is not reachable

You can set the java.rmi.server.hostname to an explicit value (such as 110.142.83.167), but note that then all clients will attempt to connect to remote objects using that IP address.

One way to solve this problem is use a hostname and a split DNS system where external clients resolve the hostname to 110.142.83.167 but internal clients resolve the hostname to 192.168.0.110. (Alternatively you could use a hosts file entry on the client machines, but that becomes a hassle administratively if the number of client machines is large).

Note also, that if you have not explicitly bound the remote object to a particular port, then an ephemeral port will be used -- you will therefore need your firewall to allowing access to all ports. By binding the remote object to a particular port, your firewall could then be configured to only allow that port through (plus the registry port).

Greg Kopff
  • 15,945
  • 12
  • 55
  • 78
  • Thank you Greg. Clarifying ... On creation the ServerRMIObject is "hard" set as "My-IP=192.168.0.110 and My-Port=21099". Then the remote Client gets the ServerRMIObject from the registry, and the ServerRMIObject still thinks "My-IP=192.168.0.110 and My-Port=21099". So I now need the remote client to "intercept" the call to 192.168.0.110 (server IP on LAN) and instead route it to 110.142.83.167 (server IP on WAN). If so, might that be possible via route tables etc? - or is it more complex than that? Many thanks. – Damian C Oct 18 '16 at 07:18
  • @DamianC What exactly do you mean by 'hard set'? The technique described in this answer is the only way of associating a non-default IP address with a remote object. – user207421 Oct 18 '16 at 11:02