OSDN Git Service

Tests for ServerSocketFactory.getDefault().
authorJesse Wilson <jessewilson@google.com>
Wed, 29 Sep 2010 02:36:39 +0000 (19:36 -0700)
committerJesse Wilson <jessewilson@google.com>
Wed, 29 Sep 2010 02:36:39 +0000 (19:36 -0700)
Motivated by http://b/2587385

Change-Id: If30898859f869c88342d1069a2425575752ebf6e

luni/src/main/java/java/net/ServerSocket.java
luni/src/main/java/javax/net/ServerSocketFactory.java
luni/src/test/java/libcore/javax/net/ServerSocketFactoryTest.java [new file with mode: 0644]

index 6ddf59e..e7e7f9f 100644 (file)
@@ -336,10 +336,10 @@ public class ServerSocket {
     }
 
     /**
-     * Binds this server socket to the given local socket address. The default
-     * number of pending connections may be backlogged. If the {@code localAddr}
-     * is set to {@code null} the socket will be bound to an available local
-     * address on any free port of the system.
+     * Binds this server socket to the given local socket address with a maximum
+     * backlog of 50 unaccepted connections. If the {@code localAddr} is set to
+     * {@code null} the socket will be bound to an available local address on
+     * any free port of the system.
      *
      * @param localAddr
      *            the local address and port to bind on.
@@ -356,20 +356,15 @@ public class ServerSocket {
     /**
      * Binds this server socket to the given local socket address. If the
      * {@code localAddr} is set to {@code null} the socket will be bound to an
-     * available local address on any free port of the system. The value for
-     * {@code backlog} must e greater than {@code 0} otherwise the default value
-     * will be used.
+     * available local address on any free port of the system.
      *
-     * @param localAddr
-     *            the local machine address and port to bind on.
-     * @param backlog
-     *            the number of pending connection requests, before requests
-     *            will be rejected.
-     * @throws IllegalArgumentException
-     *             if the {@code SocketAddress} is not supported.
-     * @throws IOException
-     *             if the socket is already bound or a problem occurs during
-     *             binding.
+     * @param localAddr the local machine address and port to bind on.
+     * @param backlog the maximum number of unaccepted connections. Passing 0 or
+     *     a negative value yields the default backlog of 50.
+     * @throws IllegalArgumentException if the {@code SocketAddress} is not
+     *     supported.
+     * @throws IOException if the socket is already bound or a problem occurs
+     *     during binding.
      */
     public void bind(SocketAddress localAddr, int backlog) throws IOException {
         checkClosedAndCreate(true);
index f2d2c0d..15ab773 100644 (file)
@@ -64,10 +64,10 @@ public abstract class ServerSocketFactory {
     }
 
     /**
-     * Creates a new server socket which is bound to the given port.
+     * Creates a new server socket which is bound to the given port with a
+     * maximum backlog of 50 unaccepted connections.
      *
-     * @param port
-     *            the port on which the created socket has to listen.
+     * @param port the port on which the created socket has to listen.
      * @return the created bound server socket.
      * @throws IOException
      *             if an error occurs while creating a new server socket.
@@ -78,13 +78,11 @@ public abstract class ServerSocketFactory {
      * Creates a new server socket which is bound to the given port and
      * configures its maximum of queued connections.
      *
-     * @param port
-     *            the port on which the created socket has to listen.
-     * @param backlog
-     *            the maximum of queued connections.
+     * @param port the port on which the created socket has to listen.
+     * @param backlog the maximum number of unaccepted connections. Passing 0 or
+     *     a negative value yields the default backlog of 50.
      * @return the created bound server socket.
-     * @throws IOException
-     *             if an error occurs while creating a new server socket.
+     * @throws IOException if an error occurs while creating a new server socket.
      */
     public abstract ServerSocket createServerSocket(int port, int backlog) throws IOException;
 
@@ -92,16 +90,13 @@ public abstract class ServerSocketFactory {
      * Creates a new server socket which is bound to the given address on the
      * specified port and configures its maximum of queued connections.
      *
-     * @param port
-     *            the port on which the created socket has to listen.
-     * @param backlog
-     *            the maximum of queued connections.
-     * @param iAddress
-     *            the address of the network interface which is used by the
-     *            created socket.
+     * @param port the port on which the created socket has to listen.
+     * @param backlog the maximum number of unaccepted connections. Passing 0 or
+     *     a negative value yields the default backlog of 50.
+     * @param iAddress the address of the network interface which is used by the
+     *     created socket.
      * @return the created bound server socket.
-     * @throws IOException
-     *             if an error occurs while creating a new server socket.
+     * @throws IOException if an error occurs while creating a new server socket.
      */
     public abstract ServerSocket createServerSocket(int port, int backlog, InetAddress iAddress)
             throws IOException;
diff --git a/luni/src/test/java/libcore/javax/net/ServerSocketFactoryTest.java b/luni/src/test/java/libcore/javax/net/ServerSocketFactoryTest.java
new file mode 100644 (file)
index 0000000..77996dd
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.javax.net;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import javax.net.ServerSocketFactory;
+import junit.framework.TestCase;
+
+public class ServerSocketFactoryTest extends TestCase {
+
+    public void testCreateServerSocket() throws IOException {
+        ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket();
+        serverSocket.bind(new InetSocketAddress(0));
+        testSocket(serverSocket, 50);
+    }
+
+    public void testCreateServerSocketWithPort() throws IOException {
+        ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(0);
+        testSocket(serverSocket, 50);
+    }
+
+    public void testCreateServerSocketWithPortNoBacklog() throws IOException {
+        ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(0, 1);
+        testSocket(serverSocket, 1);
+    }
+
+    public void testCreateServerSocketWithPortZeroBacklog() throws IOException {
+        ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(0, 0);
+        testSocket(serverSocket, 50);
+    }
+
+    public void testCreateServerSocketWithPortAndBacklog() throws IOException {
+        ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(0, 50);
+        testSocket(serverSocket, 50);
+    }
+
+    private void testSocket(final ServerSocket serverSocket, int specifiedBacklog)
+            throws IOException {
+        final byte[] data = "abc".getBytes();
+
+        new Thread(new Runnable() {
+            public void run() {
+                try {
+                    Socket s = serverSocket.accept();
+                    s.getOutputStream().write(data);
+                    s.close();
+                } catch (IOException e) {
+                }
+            }
+        }).start();
+
+        Socket socket = new Socket(InetAddress.getLocalHost(), serverSocket.getLocalPort());
+        assertBacklog(specifiedBacklog, new InetSocketAddress(
+                InetAddress.getLocalHost(), serverSocket.getLocalPort()));
+
+        InputStream in = socket.getInputStream();
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        transfer(in, out);
+        assertEquals(Arrays.toString(data), Arrays.toString(out.toByteArray()));
+        socket.close();
+
+        serverSocket.close();
+    }
+
+    /**
+     * Validates that the backlog of the listening address is as specified.
+     */
+    private void assertBacklog(int specifiedBacklog, InetSocketAddress serverAddress)
+            throws IOException {
+        List<Socket> backlog = new ArrayList<Socket>();
+        int peak = 0;
+        try {
+            int max = 100;
+            for (int i = 0; i < max; i++) {
+                Socket socket = new Socket();
+                backlog.add(socket);
+                socket.connect(serverAddress, 500);
+                peak++;
+            }
+            fail("Failed to exhaust backlog after " + max + " connections!");
+        } catch (IOException expected) {
+        }
+
+        System.out.println("backlog peaked at " + peak);
+
+        for (Socket socket : backlog) {
+            socket.close();
+        }
+
+        /*
+         * In 4.5 of UNIX Network Programming, Stevens says:
+         *     "Berkeley-derived implementations add a fudge factor to the
+         *      backlog: it is multiplied by 1.5."
+         *
+         * We've observed that Linux always adds 3 to the user-specified
+         * backlog.
+         */
+        assertTrue(peak >= specifiedBacklog && peak <= (specifiedBacklog + 3) * 1.5);
+    }
+
+    private void transfer(InputStream in, ByteArrayOutputStream out) throws IOException {
+        byte[] buffer = new byte[1024];
+        int count;
+        while ((count = in.read(buffer)) != -1) {
+            out.write(buffer, 0, count);
+        }
+    }
+}