RMI Callbacks and Firewall/Proxy Issues

Generally, callbacks should be avoided. If you really want to use them for some application, then the hack discussed below can help. However, I would recommend using something else if you possibly can. For example, a simple POP3-like polling thread can probably suffice for most applications. Callback semantics are nice to program with, but they can cause quite a bit of frustration in the deployment phase, especially for commercially distributed applications.

 

In order to use callbacks, your client needs to be able to open a listening (server) socket. This automatically means that your applet or application client must run outside the Java security sandbox. That is definitely to be avoided, because the sandbox adds great value to your application. Also, as discussed below, you won’t be able to use HTTP-tunneling with callbacks.

 

I would now recommend using my hack only as a quick way of working around firewall problems in an application that already uses callbacks. You might, for example, use the hack for the short term while converting callback semantics to a producer/consumer design for later release. Alternately, if you know that you are going to be distributing clients only to trusted and trusting sites (intranet or extranet, for example), then the hack may fill the bill for a longer period of time.

 

The solution below was designed to solve the problem of getting callbacks through a server firewall set for port forwarding to the RMI server. This is a case where, for example, a home user can create an RMI connection to the server but the server can't connect back to the client.

Other scenarios in which this hack should work include cases where the client connects to the server through an SSH tunnel, dial-up PPP, or a VPN. In all of these cases, the client can open a socket to the remote server, but the server can't open a socket back to the client.

The code (version 1.2.1) downloaded here and is free for any use. Please let me know if it doesn't work for you, and I'll try to make an update. I'm also interested in knowing if it works through a SOCKS proxy if anyone tries this.

Send questions or comments to tttaylor@cssassociates.com.

Also see Alternatives below for more information on other software that might better fit your needs.

Known Limitations and Bugs

Your server should export all of its RMI objects _and run the registry_ on the same port. This is a good practice anyway. The example provided shows how to do this.

The latest version (V1.2.1) fixes a problem with the automatic mapping of direct and destination endpoint addresses. When you connect to a firewall that is port forwarding or an SSH tunnel, etc., the destination endpoint address (the actual address and port for the server) will be different from the direct address (the firewall or tunnel address you actually make your direct connection to). The rmicb socket factories did not correctly make this mapping in the earlier versions.

A known problem can occur if your client PC is using an unofficial IP address such as 192.168.x.x (NAT, etc.).  If another client is using that same address from another PC, and the PC callback RMI server objects happen to use the same port for export, the callbacks may fail.  One way to get around this is for the client to negotiate a callback port with the server.  Then the client can export all of its callbacks on that port.  (It really should be added to the rmicb package, but I've been a little busy -- making a living, etc.) 

This hack _will not work_ if your client must reach the Internet through an HTTP proxying firewall. You need to be able to get a real socket through the firewall in some way. SOCKS should work, but I have not tried it. I.e., if your firewall will let a client use SOCKS to get _out_, then you should be able to set the standard SOCKS support of your JVM to use your SOCKS server for all sockets. Since my hack just uses plain sockets, it should automatically work through SOCKS. I am thinking of writing a mailbox-style framework to allow limited communication from server to client. This might provide much of the benefit of callbacks while retaining the ability to tunnel through HTTP.

Alternatives

People have told me that RMI Doves may do a better job than my solution. For example, the RMI Doves web site says that their socket factories can use HTTP Connect to tunnel past client-side firewalls. This is an absolute must if you plan to distribute your client to a general business audience. One problem I would note is that usually client-side proxies will not allow you to HTTP Connect (by default) to any external port other than 443 (SSL port), but you can set up your RMI server to export on port 443.

There is also RMIProxy, which seems to provide the desired tunneling functionality but (I think) requires installation on each firewall between the client and server.