Re: specifying range for rmiregistry to bind from
Peter Jones - JavaSoft East <[email protected]>
| Newsgroups | gmane.comp.java.sun.rmi |
|---|---|
| Message-ID | <20050303020611.GL29071@east> |
> Is there a way to limit the range of anonymous ports from which
> rmiregistry picks for the redirect?
I assume by "for the redirect" you are referring to ports used for
communication to general application remote objects (which are perhaps
bound in an RMI registry) in contrast to the port used for
communication to a registry itself (such as for a lookup invocation).
A registry implementation doesn't "pick" these ports; they are
generally chosen when a remote object is exported, and they are part
of the serialized state of the resulting stub (which is perhaps then
passed to a registry).
> We're paranoid enough we don't want to simply open all anonymous
> ports to the entire subnet.
>
> If we want to use just one port, it looks like UnicastRemoteObject( port )
> should do the trick, if (according to the archives) one does not extend
> the class.
To be specific, the UnicastRemoteObject(int) constructor applies if
the remote object's class does extend UnicastRemoteObject, and the
static method UnicastRemoteObject.exportObject(Remote,int) applies if
it does not:
http://archives.java.sun.com/cgi-bin/wa?A2=ind0302&L=rmi-users&P=3663
> For a range, it looks like the socket factory class is the place to
> look, but I tried (once) and was unsatisfied with the
> results. (Couldn't get it to run. Blame my lack of skill in Java.)
See below for a basic example.
> However, man rmiregistry indicates that the only options for
> rmiregistry are for the port for the initial query and for passing
> options to java. So it looks like I just have to figure out how to
> use or override the socket factory class. Is that correct?
As above, this port choice is not part of the operation of rmiregistry;
it depends on how each remote object is exported (in its own VM).
> (I worry about all the things that RMIServerSocketFactory does and
> needs done that I might not really understand, such as how to avoid
> ports that are already in use by other processes when you don't just
> let the system allocate the port, and why UnicastRemoteObject
> provides a constructor which accepts separate factory instances for
> the client and server.
There are two RMI socket factory interfaces: an RMIServerSocketFactory
creates bound server sockets (for receiving remote invocations on the
"server" side), and an RMIClientSocketFactory creates connected
sockets (for sending remote invocations on the "client" side).
An RMIClientSocketFactory, if used when exporting a remote object,
becomes part of the serialized form of the remote object's stub (and
thus it must be serializable). An RMIServerSocketFactory does not; it
is only used in the remote object's VM.
It seems to me that what you want is to use an RMIServerSocketFactory
implementation that overrides createServerSocket to, if the port
argument is 0, attempt to create bound server sockets only from some
configured port range (instead of the OS's anonymous range) until such
an attempt succeeds (doesn't throw a BindException) and then return
the resulting server socket. (And if the port argument is non-zero,
it would simply attempt to create a server socket bound to that port.)
Appended below in an example RMIServerSocketFactory implementation
that does this, with the caveat that it's been only trivially tested.
If always starting a linear search from the bottom of the range is
deemed unsatisfactory (not that this should be a high frequency
operation), an alternative might be to remember (in a thread-safe
fashion) the last port previously attempted and start beyond there
next time (wrapping around at the end of the range); or have each
factory use its own randomized order for searching the range; or
something else...
> Incidentally, if anyone could point my to a page that shows IANA's
> current definition of the anonymous port ranges, I'd appreciate it.)
I believe that IANA recommends the range 49152-65535:
http://www.iana.org/assignments/port-numbers
although I don't offhand know of an OS that actually uses that range
by default. In particular, Windows seems to bind anonymous ports
starting right above 1024, which seems dicey...
-- Peter
import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.rmi.server.RMIServerSocketFactory;
public class PortRangeRMIServerSocketFactory
implements RMIServerSocketFactory
{
private final RMIServerSocketFactory ssf;
private final int rangeStart;
private final int rangeEnd;
public PortRangeRMIServerSocketFactory(RMIServerSocketFactory ssf,
int rangeStart,
int rangeEnd)
{
this.ssf = ssf;
if (rangeStart < 0 || rangeEnd > 65536 || rangeStart > rangeEnd) {
throw new IllegalArgumentException(
"illegal port range: [" + rangeStart + "," + rangeEnd + "]");
}
this.rangeStart = rangeStart;
this.rangeEnd = rangeEnd;
}
public ServerSocket createServerSocket(int port) throws IOException {
if (port == 0) {
BindException bindException = null;
for (int i = rangeStart; i <= rangeEnd; i++) {
try {
return newServerSocket(i);
} catch (BindException e) {
bindException = e;
}
}
assert bindException != null;
throw bindException;
} else {
return newServerSocket(port);
}
}
public int hashCode() {
return
getClass().hashCode() ^
(ssf == null ? 0 : ssf.hashCode()) ^
((rangeStart << 16) + rangeEnd);
}
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj == null || getClass() != obj.getClass()) {
return false;
}
PortRangeRMIServerSocketFactory other =
(PortRangeRMIServerSocketFactory) obj;
return
(ssf == null ? other.ssf == null : ssf.equals(other.ssf)) &&
rangeStart == other.rangeStart &&
rangeEnd == other.rangeEnd;
}
private ServerSocket newServerSocket(int port) throws IOException {
if (ssf == null) {
return new ServerSocket(port);
} else {
return ssf.createServerSocket(port);
}
}
}
===========================================================================
To unsubscribe, send email to [email protected] and include in the body
of the message "signoff RMI-USERS". For general help, send email to
[email protected] and include in the body of the message "help".
For a list of frequently asked RMI questions please refer to:
http://java.sun.com/j2se/1.3/docs/guide/rmi/faq.html
To view past RMI-USERS postings, please see:
http://archives.java.sun.com/archives/rmi-users.html