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 &lt;droden at gmail.com&gt;
+        * @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 {


Reply via email to