ServerSocketChannelTest.java revision df29508a7aa622f265aaebdc472eb7d679185ebb
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package libcore.java.nio.channels;
18
19import java.io.IOException;
20import java.net.InetAddress;
21import java.net.InetSocketAddress;
22import java.net.NetworkInterface;
23import java.net.ServerSocket;
24import java.net.SocketOption;
25import java.net.StandardSocketOptions;
26import java.nio.channels.ClosedChannelException;
27import java.nio.channels.ServerSocketChannel;
28import java.nio.channels.SocketChannel;
29import java.nio.channels.UnresolvedAddressException;
30import java.util.Enumeration;
31import java.util.Set;
32
33public class ServerSocketChannelTest extends junit.framework.TestCase {
34    // http://code.google.com/p/android/issues/detail?id=16579
35    public void testNonBlockingAccept() throws Exception {
36        ServerSocketChannel ssc = ServerSocketChannel.open();
37        try {
38            ssc.configureBlocking(false);
39            ssc.bind(null);
40            // Should return immediately, since we're non-blocking.
41            assertNull(ssc.accept());
42        } finally {
43            ssc.close();
44        }
45    }
46
47    /** Checks the state of the ServerSocketChannel and associated ServerSocket after open() */
48    public void test_open_initialState() throws Exception {
49        ServerSocketChannel ssc = ServerSocketChannel.open();
50        try {
51            assertNull(ssc.getLocalAddress());
52
53            ServerSocket socket = ssc.socket();
54            assertFalse(socket.isBound());
55            assertFalse(socket.isClosed());
56            assertEquals(-1, socket.getLocalPort());
57            assertNull(socket.getLocalSocketAddress());
58            assertNull(socket.getInetAddress());
59            assertTrue(socket.getReuseAddress());
60
61            assertSame(ssc, socket.getChannel());
62        } finally {
63            ssc.close();
64        }
65    }
66
67    public void test_bind_unresolvedAddress() throws IOException {
68        ServerSocketChannel ssc = ServerSocketChannel.open();
69        try {
70            ssc.bind(new InetSocketAddress("unresolvedname", 31415));
71            fail();
72        } catch (UnresolvedAddressException expected) {
73        }
74
75        assertNull(ssc.getLocalAddress());
76        assertTrue(ssc.isOpen());
77
78        ssc.close();
79    }
80
81    public void test_bind_nullBindsToAll() throws Exception {
82        ServerSocketChannel ssc = ServerSocketChannel.open();
83        ssc.bind(null);
84        InetSocketAddress boundAddress = (InetSocketAddress) ssc.getLocalAddress();
85        assertTrue(boundAddress.getAddress().isAnyLocalAddress());
86        assertFalse(boundAddress.getAddress().isLinkLocalAddress());
87        assertFalse(boundAddress.getAddress().isLoopbackAddress());
88
89        // Attempt to connect to the "any" address.
90        assertTrue(canConnect(boundAddress));
91
92        // Go through all local IPs and try to connect to each in turn - all should succeed.
93        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
94        while (interfaces.hasMoreElements()) {
95            NetworkInterface nic = interfaces.nextElement();
96            Enumeration<InetAddress> inetAddresses = nic.getInetAddresses();
97            while (inetAddresses.hasMoreElements()) {
98                InetSocketAddress address =
99                        new InetSocketAddress(inetAddresses.nextElement(), boundAddress.getPort());
100                assertTrue(canConnect(address));
101            }
102        }
103
104        ssc.close();
105    }
106
107    public void test_bind_loopback() throws Exception {
108        ServerSocketChannel ssc = ServerSocketChannel.open();
109        ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
110        InetSocketAddress boundAddress = (InetSocketAddress) ssc.getLocalAddress();
111        assertFalse(boundAddress.getAddress().isAnyLocalAddress());
112        assertFalse(boundAddress.getAddress().isLinkLocalAddress());
113        assertTrue(boundAddress.getAddress().isLoopbackAddress());
114
115        // Attempt to connect to the "loopback" address. Note: There can be several loopback
116        // addresses, such as 127.0.0.1 (IPv4) and 0:0:0:0:0:0:0:1 (IPv6) and only one will be
117        // bound.
118        InetSocketAddress loopbackAddress =
119                new InetSocketAddress(InetAddress.getLoopbackAddress(), boundAddress.getPort());
120        assertTrue(canConnect(loopbackAddress));
121
122        // Go through all local IPs and try to connect to each in turn - all should fail except
123        // for the loopback.
124        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
125        while (interfaces.hasMoreElements()) {
126            NetworkInterface nic = interfaces.nextElement();
127            Enumeration<InetAddress> inetAddresses = nic.getInetAddresses();
128            while (inetAddresses.hasMoreElements()) {
129                InetSocketAddress address =
130                        new InetSocketAddress(inetAddresses.nextElement(), boundAddress.getPort());
131                if (!address.equals(loopbackAddress)) {
132                    assertFalse(canConnect(address));
133                }
134            }
135        }
136
137        ssc.close();
138    }
139
140    private static boolean canConnect(InetSocketAddress address) {
141        try {
142            SocketChannel socketChannel = SocketChannel.open(address);
143            socketChannel.close();
144            return true;
145        } catch (IOException e) {
146            return false;
147        }
148    }
149
150    public void test_supportedOptions() throws Exception {
151        ServerSocketChannel ssc = ServerSocketChannel.open();
152        Set<SocketOption<?>> options = ssc.supportedOptions();
153
154        // Probe some values. This is not intended to be complete.
155        assertTrue(options.contains(StandardSocketOptions.SO_REUSEADDR));
156        assertFalse(options.contains(StandardSocketOptions.IP_MULTICAST_TTL));
157    }
158
159    public void test_getOption_unsupportedOption() throws Exception {
160        ServerSocketChannel ssc = ServerSocketChannel.open();
161        try {
162            ssc.getOption(StandardSocketOptions.IP_MULTICAST_TTL);
163            fail();
164        } catch (UnsupportedOperationException expected) {}
165
166        ssc.close();
167    }
168
169    public void test_getOption_afterClose() throws Exception {
170        ServerSocketChannel ssc = ServerSocketChannel.open();
171        ssc.close();
172
173        try {
174            ssc.getOption(StandardSocketOptions.SO_RCVBUF);
175            fail();
176        } catch (ClosedChannelException expected) {}
177    }
178
179    public void test_setOption_afterClose() throws Exception {
180        ServerSocketChannel ssc = ServerSocketChannel.open();
181        ssc.close();
182
183        try {
184            ssc.setOption(StandardSocketOptions.SO_RCVBUF, 1234);
185            fail();
186        } catch (ClosedChannelException expected) {}
187    }
188
189    public void test_getOption_SO_RCVBUF_defaults() throws Exception {
190        ServerSocketChannel ssc = ServerSocketChannel.open();
191
192        int value = ssc.getOption(StandardSocketOptions.SO_RCVBUF);
193        assertTrue(value > 0);
194        assertEquals(value, ssc.socket().getReceiveBufferSize());
195
196        ssc.close();
197    }
198
199    public void test_setOption_SO_RCVBUF_afterOpen() throws Exception {
200        ServerSocketChannel ssc = ServerSocketChannel.open();
201
202        trySetReceiveBufferSizeOption(ssc);
203
204        ssc.close();
205    }
206
207    private static void trySetReceiveBufferSizeOption(ServerSocketChannel ssc) throws IOException {
208        int initialValue = ssc.getOption(StandardSocketOptions.SO_RCVBUF);
209        try {
210            ssc.setOption(StandardSocketOptions.SO_RCVBUF, -1);
211            fail();
212        } catch (IllegalArgumentException expected) {}
213        int actualValue = ssc.getOption(StandardSocketOptions.SO_RCVBUF);
214        assertEquals(initialValue, actualValue);
215        assertEquals(initialValue, ssc.socket().getReceiveBufferSize());
216
217        int newBufferSize = initialValue - 1;
218        ssc.setOption(StandardSocketOptions.SO_RCVBUF, newBufferSize);
219        actualValue = ssc.getOption(StandardSocketOptions.SO_RCVBUF);
220        // The Linux Kernel actually doubles the value it is given and may choose to ignore it.
221        // This assertion may be brittle.
222        assertTrue(actualValue != initialValue);
223        assertEquals(actualValue, ssc.socket().getReceiveBufferSize());
224    }
225
226    public void test_getOption_SO_REUSEADDR_defaults() throws Exception {
227        ServerSocketChannel ssc = ServerSocketChannel.open();
228
229        boolean value = ssc.getOption(StandardSocketOptions.SO_REUSEADDR);
230        assertTrue(value);
231        assertTrue(ssc.socket().getReuseAddress());
232
233        ssc.close();
234    }
235
236    public void test_setOption_SO_REUSEADDR_afterOpen() throws Exception {
237        ServerSocketChannel ssc = ServerSocketChannel.open();
238
239        boolean initialValue = ssc.getOption(StandardSocketOptions.SO_REUSEADDR);
240        ssc.setOption(StandardSocketOptions.SO_REUSEADDR, !initialValue);
241        assertEquals(!initialValue, (boolean) ssc.getOption(StandardSocketOptions.SO_REUSEADDR));
242        assertEquals(!initialValue, ssc.socket().getReuseAddress());
243
244        ssc.close();
245    }
246
247}
248