1/*
2 * Copyright (C) 2010 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.BindException;
21import java.net.DatagramSocket;
22import java.net.Inet4Address;
23import java.net.Inet6Address;
24import java.net.InetAddress;
25import java.net.InetSocketAddress;
26import java.net.NetworkInterface;
27import java.net.ProtocolFamily;
28import java.net.StandardProtocolFamily;
29import java.net.StandardSocketOptions;
30import java.nio.ByteBuffer;
31import java.nio.channels.AlreadyBoundException;
32import java.nio.channels.ClosedChannelException;
33import java.nio.channels.DatagramChannel;
34import java.nio.channels.UnsupportedAddressTypeException;
35import java.nio.channels.spi.SelectorProvider;
36import java.util.Enumeration;
37
38public class DatagramChannelTest extends junit.framework.TestCase {
39    public void test_read_intoReadOnlyByteArrays() throws Exception {
40        ByteBuffer readOnly = ByteBuffer.allocate(1).asReadOnlyBuffer();
41        DatagramSocket ds = new DatagramSocket(0);
42        DatagramChannel dc = DatagramChannel.open();
43        dc.connect(ds.getLocalSocketAddress());
44        try {
45            dc.read(readOnly);
46            fail();
47        } catch (IllegalArgumentException expected) {
48        }
49        try {
50            dc.read(new ByteBuffer[] { readOnly });
51            fail();
52        } catch (IllegalArgumentException expected) {
53        }
54        try {
55            dc.read(new ByteBuffer[] { readOnly }, 0, 1);
56            fail();
57        } catch (IllegalArgumentException expected) {
58        }
59    }
60
61    // http://code.google.com/p/android/issues/detail?id=16579
62    public void testNonBlockingRecv() throws Exception {
63        DatagramChannel dc = DatagramChannel.open();
64        try {
65            dc.configureBlocking(false);
66            dc.socket().bind(null);
67            // Should return immediately, since we're non-blocking.
68            assertNull(dc.receive(ByteBuffer.allocate(2048)));
69        } finally {
70            dc.close();
71        }
72    }
73
74    public void testInitialState() throws Exception {
75        DatagramChannel dc = DatagramChannel.open();
76        try {
77            DatagramSocket socket = dc.socket();
78            assertFalse(socket.isBound());
79            assertFalse(socket.getBroadcast());
80            assertFalse(socket.isClosed());
81            assertFalse(socket.isConnected());
82            assertEquals(0, socket.getLocalPort());
83            assertTrue(socket.getLocalAddress().isAnyLocalAddress());
84            assertNull(socket.getLocalSocketAddress());
85            assertNull(socket.getInetAddress());
86            assertEquals(-1, socket.getPort());
87            assertNull(socket.getRemoteSocketAddress());
88            assertFalse(socket.getReuseAddress());
89
90            assertSame(dc, socket.getChannel());
91        } finally {
92            dc.close();
93        }
94    }
95
96    public void test_bind_unresolvedAddress() throws IOException {
97        DatagramChannel dc = DatagramChannel.open();
98        try {
99            dc.socket().bind(new InetSocketAddress("unresolvedname", 31415));
100            fail();
101        } catch (IOException expected) {
102        }
103
104        assertTrue(dc.isOpen());
105        assertFalse(dc.isConnected());
106
107        dc.close();
108    }
109
110    public void test_bind_any_IPv4() throws Exception {
111        test_bind_any(InetAddress.getByName("0.0.0.0"));
112    }
113
114    public void test_bind_any_IPv6() throws Exception {
115        test_bind_any(InetAddress.getByName("::"));
116    }
117
118    private void test_bind_any(InetAddress bindAddress) throws Exception {
119        DatagramChannel dc = DatagramChannel.open();
120        dc.socket().bind(new InetSocketAddress(bindAddress, 0));
121
122        assertTrue(dc.isOpen());
123        assertFalse(dc.isConnected());
124
125        InetSocketAddress actualAddress = (InetSocketAddress) dc.socket().getLocalSocketAddress();
126        assertTrue(actualAddress.getAddress().isAnyLocalAddress());
127        assertTrue(actualAddress.getPort() > 0);
128
129        dc.close();
130    }
131
132    public void test_bind_loopback_IPv4() throws Exception {
133        test_bind(InetAddress.getByName("127.0.0.1"));
134    }
135
136    public void test_bind_loopback_IPv6() throws Exception {
137        test_bind(InetAddress.getByName("::1"));
138    }
139
140    public void test_bind_IPv4() throws Exception {
141        InetAddress bindAddress = getNonLoopbackNetworkInterfaceAddress(true /* ipv4 */);
142        test_bind(bindAddress);
143    }
144
145    public void test_bind_IPv6() throws Exception {
146        InetAddress bindAddress = getNonLoopbackNetworkInterfaceAddress(false /* ipv4 */);
147        test_bind(bindAddress);
148    }
149
150    private void test_bind(InetAddress bindAddress) throws IOException {
151        DatagramChannel dc = DatagramChannel.open();
152        dc.socket().bind(new InetSocketAddress(bindAddress, 0));
153
154        InetSocketAddress actualAddress = (InetSocketAddress) dc.socket().getLocalSocketAddress();
155        assertEquals(bindAddress, actualAddress.getAddress());
156        assertTrue(actualAddress.getPort() > 0);
157
158        dc.close();
159    }
160
161    public void test_setOption() throws Exception {
162        DatagramChannel dc = DatagramChannel.open();
163        // There were problems in the past as the number used here was below the minimum for
164        // some platforms (b/27821554). It was increased from 1024 to 4096.
165        dc.setOption(StandardSocketOptions.SO_SNDBUF, 4096);
166
167        // Assert that we can read back the option from the channel...
168        assertEquals(4096, (int) dc.getOption(StandardSocketOptions.SO_SNDBUF));
169        // ... and its socket adaptor.
170        assertEquals(4096, dc.socket().getSendBufferSize());
171
172        dc.close();
173        try {
174            dc.setOption(StandardSocketOptions.SO_SNDBUF, 4096);
175            fail();
176        } catch (ClosedChannelException expected) {
177        }
178    }
179
180    // http://b/26292854
181    public void test_getFileDescriptor() throws Exception {
182        DatagramSocket socket = DatagramChannel.open().socket();
183        socket.getReuseAddress();
184        assertNotNull(socket.getFileDescriptor$());
185    }
186
187    public void test_bind() throws IOException {
188        InetSocketAddress socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
189        DatagramChannel channel = DatagramChannel.open();
190        channel.bind(socketAddress);
191        assertEquals(socketAddress.getAddress(),
192                ((InetSocketAddress)(channel.getLocalAddress())).getAddress());
193        assertTrue(((InetSocketAddress)(channel.getLocalAddress())).getPort() > 0);
194
195        try {
196            channel.bind(socketAddress);
197            fail();
198        } catch (AlreadyBoundException expected) {
199        }
200
201        socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK,
202                ((InetSocketAddress)(channel.getLocalAddress())).getPort());
203        try {
204            DatagramChannel.open().bind(socketAddress);
205            fail();
206        } catch (BindException expected) {}
207
208        channel.close();
209        socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
210        try {
211            channel.bind(socketAddress);
212        } catch (ClosedChannelException expected) {}
213    }
214
215    public void test_getRemoteAddress() throws IOException {
216        InetSocketAddress socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
217        DatagramChannel clientChannel = DatagramChannel.open();
218        DatagramChannel serverChannel = DatagramChannel.open();
219        serverChannel.bind(socketAddress);
220
221        assertNull(clientChannel.getRemoteAddress());
222
223        clientChannel.connect(serverChannel.getLocalAddress());
224        assertEquals(socketAddress.getAddress(),
225                ((InetSocketAddress)(clientChannel.getRemoteAddress())).getAddress());
226        assertEquals(((InetSocketAddress)(serverChannel.getLocalAddress())).getPort(),
227                ((InetSocketAddress)(clientChannel.getRemoteAddress())).getPort());
228    }
229
230    public void test_open$java_net_ProtocolFamily() throws IOException {
231        DatagramChannel channel = DatagramChannel.open(StandardProtocolFamily.INET);
232
233        channel.bind(new InetSocketAddress(Inet4Address.LOOPBACK, 0));
234        assertEquals(SelectorProvider.provider(), channel.provider());
235
236        try {
237            // Should not support IPv6 Address
238            // InetSocketAddress(int) returns IPv6 ANY  address
239            DatagramChannel.open(StandardProtocolFamily.INET).bind(new InetSocketAddress(0));
240            fail();
241        } catch (UnsupportedAddressTypeException expected) {}
242
243        DatagramChannel.open(StandardProtocolFamily.INET6).bind(new InetSocketAddress(0));
244
245        try {
246            DatagramChannel.open(MockProtocolFamily.MOCK);
247            fail();
248        } catch (UnsupportedOperationException expected) {}
249
250        try {
251            DatagramChannel.open(null);
252            fail();
253        } catch (NullPointerException expected) {}
254    }
255
256    private static InetAddress getNonLoopbackNetworkInterfaceAddress(boolean ipv4) throws IOException {
257        Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
258        while (networkInterfaces.hasMoreElements()) {
259            NetworkInterface networkInterface = networkInterfaces.nextElement();
260            if (networkInterface.isLoopback() || !networkInterface.isUp()) {
261                continue;
262            }
263            Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
264            while (inetAddresses.hasMoreElements()) {
265                InetAddress inetAddress = inetAddresses.nextElement();
266                if ( (ipv4 && inetAddress instanceof Inet4Address)
267                        || (!ipv4 && inetAddress instanceof Inet6Address)) {
268                    return inetAddress;
269                }
270            }
271        }
272        return null;
273    }
274
275    enum MockProtocolFamily implements ProtocolFamily {
276        MOCK,
277    }
278}
279