Author: bombe
Date: 2006-04-29 23:21:27 +0000 (Sat, 29 Apr 2006)
New Revision: 8597
Modified:
trunk/freenet/src/freenet/io/NetworkInterface.java
Log:
don't start acceptors until first call of accept() so that the SO_TIMEOUT can
be set prior to accept()
added some javadoc
Modified: trunk/freenet/src/freenet/io/NetworkInterface.java
===================================================================
--- trunk/freenet/src/freenet/io/NetworkInterface.java 2006-04-29 23:18:18 UTC
(rev 8596)
+++ trunk/freenet/src/freenet/io/NetworkInterface.java 2006-04-29 23:21:27 UTC
(rev 8597)
@@ -34,16 +34,36 @@
import freenet.support.Logger;
/**
+ * Replacement for {@link ServerSocket} that can handle multiple bind addresses
+ * and allows IP address level filtering.
+ *
* @author David Roden <droden at gmail.com>
* @version $Id$
*/
public class NetworkInterface {
+ /** Object for synchronisation purpose. */
protected final Object syncObject = new Object();
+
+ /** Acceptors created by this interface. */
private final List/* <Acceptor> */acceptors = new ArrayList();
+
+ /** List of allowed hosts. */
protected final List/* <String> */allowedHosts = new ArrayList();
+
+ /** Maps allowed hosts to IPv4 address matchers, if possible. */
protected final Map/* <String, Inet4AddressMatcher> */addressMatchers =
new HashMap();
+
+ /** Queue of accepted client connections. */
protected final List/* <Socket> */acceptedSockets = new ArrayList();
+
+ /**
+ * Whether the acceptors have already been started. Necessary for
+ * {@link #setSoTimeout(int)} to work.
+ */
+ private boolean started = false;
+
+ /** The timeout set by {@link #setSoTimeout(int)}. */
private int timeout = 0;
/**
@@ -66,11 +86,17 @@
serverSocket.bind(new InetSocketAddress((String)
bindToTokenList.get(serverSocketIndex), port));
Acceptor acceptor = new Acceptor(serverSocket);
acceptors.add(acceptor);
- new Thread(acceptor).start();
}
setAllowedHosts(allowedHosts);
}
+ /**
+ * Sets the list of allowed hosts to <code>allowedHosts</code>. The new
+ * list is in effect immediately after this method has finished.
+ *
+ * @param allowedHosts
+ * The new list of allowed hosts
+ */
public void setAllowedHosts(String allowedHosts) {
StringTokenizer allowedHostsTokens = new
StringTokenizer(allowedHosts, ",");
synchronized (syncObject) {
@@ -88,6 +114,15 @@
}
}
+ /**
+ * Sets the SO_TIMEOUT value on the server sockets.
+ *
+ * @param timeout
+ * The timeout in milliseconds, <code>0</code> to disable
+ * @throws SocketException
+ * if the SO_TIMEOUT value can not be set
+ * @see ServerSocket#setSoTimeout(int)
+ */
public void setSoTimeout(int timeout) throws SocketException {
Iterator acceptors = this.acceptors.iterator();
while (acceptors.hasNext()) {
@@ -95,8 +130,26 @@
}
}
+ /**
+ * Waits for a connection. If a timeout has been set using
+ * {@link #setSoTimeout(int)} and no connection is established this
method
+ * will return after the specified timeout has been expired, throwing a
+ * {@link SocketTimeoutException}. If no timeout has been set this
method
+ * will wait until a connection has been established.
+ *
+ * @return The socket that is connected to the client
+ * @throws SocketTimeoutException
+ * if the timeout has expired waiting for a connection
+ */
public Socket accept() throws SocketTimeoutException {
synchronized (syncObject) {
+ if (!started) {
+ started = true;
+ Iterator acceptors = this.acceptors.iterator();
+ while (acceptors.hasNext()) {
+ new Thread((Acceptor) acceptors.next(),
"Network Interface Acceptor").start();
+ }
+ }
while (acceptedSockets.size() == 0) {
try {
syncObject.wait(timeout);
@@ -110,6 +163,13 @@
}
}
+ /**
+ * Closes this interface and all underlying server sockets.
+ *
+ * @throws IOException
+ * if an I/O exception occurs
+ * @see ServerSocket#close()
+ */
public void close() throws IOException {
IOException exception = null;
Iterator acceptors = this.acceptors.iterator();
@@ -126,24 +186,63 @@
}
}
+ /**
+ * Wrapper around a {@link ServerSocket} that checks whether the
incoming
+ * connection is allowed.
+ *
+ * @author David Roden <droden at gmail.com>
+ * @version $Id$
+ */
private class Acceptor implements Runnable {
+ /** The {@link ServerSocket} to listen on. */
private final ServerSocket serverSocket;
+
+ /** Whether this acceptor has been closed. */
private boolean closed = false;
+ /**
+ * Creates a new acceptor on the specified server socket.
+ *
+ * @param serverSocket
+ * The server socket to listen on
+ */
public Acceptor(ServerSocket serverSocket) {
this.serverSocket = serverSocket;
}
+ /**
+ * Sets the SO_TIMEOUT value on this acceptor's server socket.
+ *
+ * @param timeout
+ * The timeout in milliseconds, or <code>0</code> to
+ * disable
+ * @throws SocketException
+ * if the SO_TIMEOUT value can not be set
+ * @see ServerSocket#setSoTimeout(int)
+ */
public void setSoTimeout(int timeout) throws SocketException {
serverSocket.setSoTimeout(timeout);
}
+ /**
+ * Closes this acceptor and the underlying server socket.
+ *
+ * @throws IOException
+ * if an I/O exception occurs
+ * @see ServerSocket#close()
+ */
public void close() throws IOException {
closed = true;
serverSocket.close();
}
+ /**
+ * Main method that accepts connections and checks the address
against
+ * the list of allowed hosts.
+ *
+ * @see NetworkInterface#allowedHosts
+ */
public void run() {
while (!closed) {
try {