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.SocketException;
25import java.net.StandardSocketOptions;
26import java.nio.channels.AlreadyBoundException;
27import java.nio.channels.ClosedChannelException;
28import java.nio.channels.ServerSocketChannel;
29import java.nio.channels.SocketChannel;
30import java.nio.channels.UnresolvedAddressException;
31import java.nio.channels.UnsupportedAddressTypeException;
32import java.util.Enumeration;
33import java.util.Set;
34
35public class ServerSocketChannelTest extends junit.framework.TestCase {
36    // http://code.google.com/p/android/issues/detail?id=16579
37    public void testNonBlockingAccept() throws Exception {
38        ServerSocketChannel ssc = ServerSocketChannel.open();
39        try {
40            ssc.configureBlocking(false);
41            ssc.socket().bind(null);
42            // Should return immediately, since we're non-blocking.
43            assertNull(ssc.accept());
44        } finally {
45            ssc.close();
46        }
47    }
48
49    /** Checks the state of the ServerSocketChannel and associated ServerSocket after open() */
50    public void test_open_initialState() throws Exception {
51        ServerSocketChannel ssc = ServerSocketChannel.open();
52        try {
53            assertNull(ssc.socket().getLocalSocketAddress());
54
55            ServerSocket socket = ssc.socket();
56            assertFalse(socket.isBound());
57            assertFalse(socket.isClosed());
58            assertEquals(-1, socket.getLocalPort());
59            assertNull(socket.getLocalSocketAddress());
60            assertNull(socket.getInetAddress());
61            assertTrue(socket.getReuseAddress());
62
63            assertSame(ssc, socket.getChannel());
64        } finally {
65            ssc.close();
66        }
67    }
68
69    public void test_bind_unresolvedAddress() throws IOException {
70        ServerSocketChannel ssc = ServerSocketChannel.open();
71        try {
72            ssc.socket().bind(new InetSocketAddress("unresolvedname", 31415));
73            fail();
74        } catch (SocketException expected) {
75        }
76
77        assertNull(ssc.socket().getLocalSocketAddress());
78        assertTrue(ssc.isOpen());
79
80        ssc.close();
81    }
82
83    public void test_bind_nullBindsToAll() throws Exception {
84        ServerSocketChannel ssc = ServerSocketChannel.open();
85        ssc.socket().bind(null);
86        InetSocketAddress boundAddress = (InetSocketAddress) ssc.socket().getLocalSocketAddress();
87        assertTrue(boundAddress.getAddress().isAnyLocalAddress());
88        assertFalse(boundAddress.getAddress().isLinkLocalAddress());
89        assertFalse(boundAddress.getAddress().isLoopbackAddress());
90
91        // Attempt to connect to the "any" address.
92        assertTrue(canConnect(boundAddress));
93
94        // Go through all local IPs and try to connect to each in turn - all should succeed.
95        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
96        while (interfaces.hasMoreElements()) {
97            NetworkInterface nic = interfaces.nextElement();
98            Enumeration<InetAddress> inetAddresses = nic.getInetAddresses();
99            while (inetAddresses.hasMoreElements()) {
100                InetSocketAddress address =
101                        new InetSocketAddress(inetAddresses.nextElement(), boundAddress.getPort());
102                assertTrue(canConnect(address));
103            }
104        }
105
106        ssc.close();
107    }
108
109    public void test_bind_loopback() throws Exception {
110        ServerSocketChannel ssc = ServerSocketChannel.open();
111        ssc.socket().bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
112        InetSocketAddress boundAddress = (InetSocketAddress) ssc.socket().getLocalSocketAddress();
113        assertFalse(boundAddress.getAddress().isAnyLocalAddress());
114        assertFalse(boundAddress.getAddress().isLinkLocalAddress());
115        assertTrue(boundAddress.getAddress().isLoopbackAddress());
116
117        // Attempt to connect to the "loopback" address. Note: There can be several loopback
118        // addresses, such as 127.0.0.1 (IPv4) and 0:0:0:0:0:0:0:1 (IPv6) and only one will be
119        // bound.
120        InetSocketAddress loopbackAddress =
121                new InetSocketAddress(InetAddress.getLoopbackAddress(), boundAddress.getPort());
122        assertTrue(canConnect(loopbackAddress));
123
124        // Go through all local IPs and try to connect to each in turn - all should fail except
125        // for the loopback.
126        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
127        while (interfaces.hasMoreElements()) {
128            NetworkInterface nic = interfaces.nextElement();
129            Enumeration<InetAddress> inetAddresses = nic.getInetAddresses();
130            while (inetAddresses.hasMoreElements()) {
131                InetSocketAddress address =
132                        new InetSocketAddress(inetAddresses.nextElement(), boundAddress.getPort());
133                if (!address.equals(loopbackAddress)) {
134                    assertFalse(canConnect(address));
135                }
136            }
137        }
138
139        ssc.close();
140    }
141
142    public void test_bind$SocketAddress() throws IOException {
143        ServerSocketChannel ssc = ServerSocketChannel.open();
144        ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
145        assertEquals(InetAddress.getLoopbackAddress(),
146                ((InetSocketAddress)(ssc.getLocalAddress())).getAddress());
147        assertTrue(((InetSocketAddress)(ssc.getLocalAddress())).getPort() > 0);
148
149        try {
150            ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(),
151                    ((InetSocketAddress)(ssc.getLocalAddress())).getPort()));
152            fail();
153        } catch (AlreadyBoundException expected) {
154        }
155
156        try {
157            ServerSocketChannel ssc1 = ServerSocketChannel.open();
158            ssc1.bind(new InetSocketAddress("1.1.1.1.1.1.1", 0));
159            fail();
160        } catch (UnresolvedAddressException expected) {
161        }
162
163        ssc.close();
164        try {
165            ssc.bind(new InetSocketAddress("1.1.1.1.1.1.1", 0));
166            fail();
167        } catch (ClosedChannelException expected) {
168        }
169    }
170
171    public void test_setOption() throws Exception {
172        ServerSocketChannel sc = ServerSocketChannel.open();
173        sc.setOption(StandardSocketOptions.SO_REUSEADDR, true);
174
175        // Assert that we can read back the option from the channel...
176        assertTrue(sc.getOption(StandardSocketOptions.SO_REUSEADDR));
177
178        sc.setOption(StandardSocketOptions.SO_REUSEADDR, false);
179
180        // Assert that we can read back the option from the channel...
181        assertEquals(false, (boolean)sc.getOption(StandardSocketOptions.SO_REUSEADDR));
182
183        sc.setOption(StandardSocketOptions.SO_RCVBUF, 1100);
184        assertTrue(1100 <= sc.getOption(StandardSocketOptions.SO_RCVBUF));
185
186        sc.close();
187        try {
188            sc.setOption(StandardSocketOptions.SO_RCVBUF, 2000);
189            fail();
190        } catch (ClosedChannelException expected) {
191        }
192    }
193
194    private static boolean canConnect(InetSocketAddress address) {
195        try {
196            SocketChannel socketChannel = SocketChannel.open(address);
197            socketChannel.close();
198            return true;
199        } catch (IOException e) {
200            return false;
201        }
202    }
203}
204