Search code examples
javasocketsrmi

Is there a way to determine if a remote RMI Server machine is multi-homed, even if some of its IP addresses are not visible?


I'm running into a couple of snags getting RMI Servers to work properly on multi-homed machines. I've written a custom RMISocketFactory and I've tried implementing the client-side createSocket(String host, int port) method a couple of different ways. One way only works when the RMI server machine IS multi-homed, the other way only works when the RMI server machine is not. Here is my code for both createSocket method versions in my client-side RMISocketFactory implementation:

Works only when the RMI Server IS NOT Multi-homed:

@Override
public Socket createSocket(String host, int port) throws IOException{
    Socket s = new Socket(host,port);

    //Do some book-keeping here ...

    return s;
}

Works only when the RMI Server IS Multi-homed:

private TreeSet<String> validHosts = null;

@Override
public Socket createSocket(String host, int port) throws IOException{
    Socket s = null;

    try {
        s = new Socket(host,port);
        synchronized(this){
            if(validHosts == null) validHosts = new TreeSet<String>();
            validHosts.add(host);
        }
    } catch (IOException e) {}

    if(s == null && validHosts != null){
        synchronized(this){
            for(String h : validHosts){
                try {
                    s = new Socket(h,port);
                } catch (IOException e) {}
            }
        }
    }

    if(s == null){
        try {
            String h = RemoteServer.getClientHost();
            s = new Socket(RemoteServer.getClientHost(),port);

            synchronized(this){
                if(validHosts == null) validHosts = new TreeSet<String>();
                validHosts.add(h);
            }
        } catch (Exception e) {}
    }

    //No dice - throw an exception:
    if(s == null){
        TreeSet<String> set = new TreeSet<String>();
        set.add(host+"(orig)");

        synchronized(this){
            if(validHosts != null) set.addAll(validHosts);
        }

        StringBuilder sb = new StringBuilder(
            "Could not connect socket on port "+port+
            " to any of the following hosts: ");
        for(String h : set) sb.append(h+" ");

        throw new IOException(sb.toString());
    }

    //Do some book-keeping here ...

    return s;
}

Question

It would seem that if I could somehow tell if the server-side machine was multi-homed, then I could just wrap both sets of code in an if(serverIsMultihomed) ... else ... kind of statement. I do have the ability to get the actual machine name of the server within this call, but calling InetAddress.getAllByHostName(host) doesn't actually return all of the host's IP addresses, only ones that are visible to the NIC on the client's machine. So when createSocket(host,port) gets called with an IP address that isn't actually visible to the client, this is where I run into issues. Furthermore, setting the java.server.rmi.hostname to the IP address of the server that I want to use doesn't fix this problem, and would essentially forbid machines on different subnets that the server is connected to from establishing a link.

The short of it is, is there another way to get all of a host's IP addresses, visible or otherwise, from a different machine, or am I totally barking up the wrong tree here?


Solution

  • Have you had a look at this Multihomed solution?