1/*
2 * Copyright (C) 2016 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 org.junit.Rule;
20
21import java.io.IOException;
22import java.net.BindException;
23import java.net.InetSocketAddress;
24import java.net.ServerSocket;
25import java.net.Socket;
26import java.net.SocketOption;
27import java.net.StandardSocketOptions;
28import java.nio.channels.AlreadyBoundException;
29import java.nio.channels.AsynchronousChannelGroup;
30import java.nio.channels.AsynchronousCloseException;
31import java.nio.channels.AsynchronousServerSocketChannel;
32import java.nio.channels.AsynchronousSocketChannel;
33import java.nio.channels.ClosedChannelException;
34import java.nio.channels.NotYetBoundException;
35import java.nio.channels.UnresolvedAddressException;
36import java.nio.channels.spi.AsynchronousChannelProvider;
37import java.util.Set;
38import java.util.concurrent.ExecutionException;
39import java.util.concurrent.Executors;
40import java.util.concurrent.Future;
41import java.util.concurrent.TimeUnit;
42import java.util.concurrent.atomic.AtomicReference;
43import libcore.junit.junit3.TestCaseWithRules;
44import libcore.junit.util.ResourceLeakageDetector;
45import libcore.junit.util.ResourceLeakageDetector.LeakageDetectorRule;
46
47public class AsynchronousServerSocketChannelTest extends TestCaseWithRules {
48
49    @Rule
50    public LeakageDetectorRule leakageDetectorRule = ResourceLeakageDetector.getRule();
51
52    public void test_bind() throws Throwable {
53        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
54        assertTrue(assc.isOpen());
55        assertNull(assc.getLocalAddress());
56        assc.bind(new InetSocketAddress(0));
57        assertNotNull(assc.getLocalAddress());
58        try {
59            assc.bind(new InetSocketAddress(0));
60            fail();
61        } catch (AlreadyBoundException expected) {}
62
63        assc.close();
64        assertFalse(assc.isOpen());
65    }
66
67    public void test_bind_null() throws Throwable {
68        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
69        assertTrue(assc.isOpen());
70        assertNull(assc.getLocalAddress());
71        assc.bind(null);
72        assertNotNull(assc.getLocalAddress());
73        try {
74            assc.bind(null);
75            fail();
76        } catch (AlreadyBoundException expected) {}
77
78        assc.close();
79        assertFalse(assc.isOpen());
80    }
81
82    public void test_bind_unresolvedAddress() throws Throwable {
83        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
84        try {
85            assc.bind(new InetSocketAddress("unresolvedname", 31415));
86            fail();
87        } catch (UnresolvedAddressException expected) {}
88
89        assertNull(assc.getLocalAddress());
90        assertTrue(assc.isOpen());
91        assc.close();
92    }
93
94    public void test_bind_used() throws Throwable {
95        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
96        ServerSocket ss = new ServerSocket(0);
97        try {
98            assc.bind(ss.getLocalSocketAddress());
99            fail();
100        } catch (BindException expected) {}
101        assertNull(assc.getLocalAddress());
102
103        ss.close();
104        assc.close();
105    }
106
107    public void test_futureAccept() throws Throwable {
108        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
109        assc.bind(new InetSocketAddress(0));
110
111        Future<AsynchronousSocketChannel> acceptFuture = assc.accept();
112
113        Socket s = new Socket();
114        s.connect(assc.getLocalAddress());
115
116        AsynchronousSocketChannel asc = acceptFuture.get(1000, TimeUnit.MILLISECONDS);
117
118        assertTrue(s.isConnected());
119        assertNotNull(asc.getLocalAddress());
120        assertEquals(asc.getLocalAddress(), s.getRemoteSocketAddress());
121        assertNotNull(asc.getRemoteAddress());
122        assertEquals(asc.getRemoteAddress(), s.getLocalSocketAddress());
123
124        asc.close();
125        s.close();
126        assc.close();
127    }
128
129    public void test_completionHandlerAccept() throws Throwable {
130        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
131        assc.bind(new InetSocketAddress(0));
132
133        FutureLikeCompletionHandler<AsynchronousSocketChannel> acceptCompletionHandler =
134            new FutureLikeCompletionHandler<AsynchronousSocketChannel>();
135
136        assc.accept(null /* attachment */, acceptCompletionHandler);
137
138        Socket s = new Socket();
139        s.connect(assc.getLocalAddress());
140        AsynchronousSocketChannel asc = acceptCompletionHandler.get(1000);
141
142        assertNotNull(asc);
143        assertTrue(s.isConnected());
144        assertNotNull(asc.getLocalAddress());
145        assertEquals(asc.getLocalAddress(), s.getRemoteSocketAddress());
146        assertNotNull(asc.getRemoteAddress());
147        assertEquals(asc.getRemoteAddress(), s.getLocalSocketAddress());
148
149        assertNull(acceptCompletionHandler.getAttachment());
150
151        asc.close();
152        s.close();
153        assc.close();
154    }
155
156    public void test_completionHandlerAccept_attachment() throws Throwable {
157        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
158        assc.bind(new InetSocketAddress(0));
159
160        FutureLikeCompletionHandler<AsynchronousSocketChannel> acceptCompletionHandler =
161            new FutureLikeCompletionHandler<AsynchronousSocketChannel>();
162
163        Integer attachment = new Integer(123);
164        assc.accept(attachment, acceptCompletionHandler);
165
166        Socket s = new Socket();
167        s.connect(assc.getLocalAddress());
168        AsynchronousSocketChannel asc = acceptCompletionHandler.get(1000);
169
170        assertNotNull(asc);
171        assertTrue(s.isConnected());
172
173        assertEquals(attachment, acceptCompletionHandler.getAttachment());
174
175        asc.close();
176        s.close();
177        assc.close();
178    }
179
180    public void test_completionHandlerAccept_nyb() throws Throwable {
181        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
182
183        FutureLikeCompletionHandler<AsynchronousSocketChannel> acceptCompletionHandler =
184            new FutureLikeCompletionHandler<AsynchronousSocketChannel>();
185        try {
186            assc.accept(null /* attachment */, acceptCompletionHandler);
187            fail();
188        } catch(NotYetBoundException expected) {}
189
190        assc.close();
191    }
192
193    public void test_completionHandlerAccept_npe() throws Throwable {
194        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
195        assc.bind(new InetSocketAddress(0));
196
197        try {
198            assc.accept(null /* attachment */, null /* completionHandler */);
199            fail();
200        } catch(NullPointerException expected) {}
201
202        assc.close();
203    }
204
205
206    public void test_options() throws Throwable {
207        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
208
209        assc.setOption(StandardSocketOptions.SO_RCVBUF, 5000);
210        assertEquals(5000, (long)assc.getOption(StandardSocketOptions.SO_RCVBUF));
211
212        assc.setOption(StandardSocketOptions.SO_REUSEADDR, true);
213        assertTrue(assc.getOption(StandardSocketOptions.SO_REUSEADDR));
214
215        assc.close();
216    }
217
218    public void test_options_iae() throws Throwable {
219        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
220
221        try {
222            assc.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
223            fail();
224        } catch (UnsupportedOperationException expected) {}
225
226        assc.close();
227    }
228
229    public void test_group() throws Throwable {
230        AsynchronousChannelProvider provider =
231            AsynchronousChannelProvider.provider();
232        AsynchronousChannelGroup group =
233            provider.openAsynchronousChannelGroup(2, Executors.defaultThreadFactory());
234
235        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open(group);
236        assertNull(assc.getLocalAddress());
237        assc.bind(new InetSocketAddress(0));
238        assertNotNull(assc.getLocalAddress());
239        assertEquals(provider, assc.provider());
240        assc.close();
241    }
242
243    public void test_close() throws Throwable {
244        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
245        assc.bind(new InetSocketAddress(0));
246        assc.close();
247
248        Future<AsynchronousSocketChannel> acceptFuture = assc.accept();
249        try {
250            acceptFuture.get(1000, TimeUnit.MILLISECONDS);
251            fail();
252        } catch(ExecutionException expected) {
253            assertTrue(expected.getCause() instanceof ClosedChannelException);
254        }
255
256        FutureLikeCompletionHandler<AsynchronousSocketChannel> acceptCompletionHandler =
257            new FutureLikeCompletionHandler<AsynchronousSocketChannel>();
258        assc.accept(null /* attachment */, acceptCompletionHandler);
259        try {
260            acceptCompletionHandler.get(1000);
261            fail();
262        } catch(ClosedChannelException expected) {}
263
264        try {
265            assc.bind(new InetSocketAddress(0));
266            fail();
267        } catch(ClosedChannelException expected) {}
268
269        try {
270            assc.setOption(StandardSocketOptions.SO_REUSEADDR, true);
271            fail();
272        } catch(ClosedChannelException expected) {}
273
274        // Try second close
275        assc.close();
276    }
277
278    public void test_future_concurrent_close() throws Throwable {
279        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
280        assc.bind(new InetSocketAddress(0));
281
282        final AtomicReference<Exception> killerThreadException =
283            new AtomicReference<Exception>(null);
284        final Thread killer = new Thread(new Runnable() {
285            public void run() {
286                try {
287                    Thread.sleep(2000);
288                    assc.close();
289                } catch (Exception ex) {
290                    killerThreadException.set(ex);
291                }
292            }
293        });
294        killer.start();
295        Future<AsynchronousSocketChannel> acceptFuture = assc.accept();
296        try {
297            // This may timeout on slow devices, they may need more time for the killer thread to
298            // do its thing.
299            acceptFuture.get(10000, TimeUnit.MILLISECONDS);
300            fail();
301        } catch(ExecutionException expected) {
302            assertTrue(expected.getCause() instanceof ClosedChannelException);
303        }
304
305        assertNull(killerThreadException.get());
306    }
307
308    public void test_completionHandler_concurrent_close() throws Throwable {
309        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
310        assc.bind(new InetSocketAddress(0));
311
312        final AtomicReference<Exception> killerThreadException =
313            new AtomicReference<Exception>(null);
314        final Thread killer = new Thread(new Runnable() {
315            public void run() {
316                try {
317                    Thread.sleep(2000);
318                    assc.close();
319                } catch (Exception ex) {
320                    killerThreadException.set(ex);
321                }
322            }
323        });
324        killer.start();
325
326        FutureLikeCompletionHandler<AsynchronousSocketChannel> acceptCompletionHandler =
327            new FutureLikeCompletionHandler<AsynchronousSocketChannel>();
328
329        assc.accept(null /* attachment */, acceptCompletionHandler);
330
331        try {
332            // This may timeout on slow devices, they may need more time for the killer thread to
333            // do its thing.
334            acceptCompletionHandler.get(10000);
335            fail();
336        } catch(AsynchronousCloseException expected) {}
337
338        assertNull(killerThreadException.get());
339    }
340
341    public void test_supportedOptions() throws Throwable {
342        AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open();
343
344        Set<SocketOption<?>> supportedOptions = assc.supportedOptions();
345        assertEquals(2, supportedOptions.size());
346
347        assertTrue(supportedOptions.contains(StandardSocketOptions.SO_REUSEADDR));
348        assertTrue(supportedOptions.contains(StandardSocketOptions.SO_RCVBUF));
349
350        // supportedOptions should work after close according to spec
351        assc.close();
352        supportedOptions = assc.supportedOptions();
353        assertEquals(2, supportedOptions.size());
354    }
355
356    public void test_closeGuardSupport() throws IOException {
357        try (AsynchronousServerSocketChannel asc = AsynchronousServerSocketChannel.open()) {
358            leakageDetectorRule.assertUnreleasedResourceCount(asc, 1);
359        }
360    }
361
362    public void test_closeGuardSupport_group() throws IOException {
363        AsynchronousChannelProvider provider =
364                AsynchronousChannelProvider.provider();
365        AsynchronousChannelGroup group =
366                provider.openAsynchronousChannelGroup(2, Executors.defaultThreadFactory());
367
368        try (AsynchronousServerSocketChannel assc = AsynchronousServerSocketChannel.open(group)) {
369            leakageDetectorRule.assertUnreleasedResourceCount(assc, 1);
370        }
371    }
372}
373