1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package org.apache.harmony.nio.tests.java.nio.channels;
19
20import java.io.IOException;
21import java.io.InputStream;
22import java.io.OutputStream;
23import java.net.InetSocketAddress;
24import java.net.ServerSocket;
25import java.net.Socket;
26import java.nio.ByteBuffer;
27import java.nio.channels.AsynchronousCloseException;
28import java.nio.channels.ClosedChannelException;
29import java.nio.channels.IllegalBlockingModeException;
30import java.nio.channels.NotYetBoundException;
31import java.nio.channels.SelectionKey;
32import java.nio.channels.ServerSocketChannel;
33import java.nio.channels.SocketChannel;
34import java.nio.channels.spi.SelectorProvider;
35
36import junit.framework.TestCase;
37import tests.support.Support_PortManager;
38
39/*
40 * test for ServerSocketChannel
41 */
42public class ServerSocketChannelTest extends TestCase {
43
44    private static final int CAPACITY_NORMAL = 200;
45
46    private static final int CAPACITY_64KB = 65536;
47
48    private static final int TIME_UNIT = 200;
49
50    private InetSocketAddress localAddr1;
51
52    private ServerSocketChannel serverChannel;
53
54    private SocketChannel clientChannel;
55
56    protected void setUp() throws Exception {
57        super.setUp();
58        this.localAddr1 = new InetSocketAddress(
59                "127.0.0.1", Support_PortManager
60                        .getNextPort());
61        this.serverChannel = ServerSocketChannel.open();
62        this.clientChannel = SocketChannel.open();
63    }
64
65    protected void tearDown() throws Exception {
66        if (null != this.serverChannel) {
67            try {
68                this.serverChannel.close();
69            } catch (Exception e) {
70                //ignore
71            }
72
73        }
74        if (null != this.clientChannel) {
75            try {
76                this.clientChannel.close();
77            } catch (Exception e) {
78                //ignore
79            }
80        }
81        super.tearDown();
82    }
83
84    // -------------------------------------------------------------------
85    // Test for methods in abstract class.
86    // -------------------------------------------------------------------
87
88    /*
89     * Test method for 'java.nio.channels.ServerSocketChannel.validOps()'
90     */
91    public void testValidOps() {
92        MockServerSocketChannel testMSChnlnull = new MockServerSocketChannel(
93                null);
94        MockServerSocketChannel testMSChnl = new MockServerSocketChannel(
95                SelectorProvider.provider());
96        assertEquals(SelectionKey.OP_ACCEPT, this.serverChannel.validOps());
97        assertEquals(SelectionKey.OP_ACCEPT, testMSChnl.validOps());
98        assertEquals(SelectionKey.OP_ACCEPT, testMSChnlnull.validOps());
99
100    }
101
102    /*
103     * Test method for 'java.nio.channels.ServerSocketChannel.open()'
104     */
105    public void testOpen() {
106        MockServerSocketChannel testMSChnl = new MockServerSocketChannel(null);
107        MockServerSocketChannel testMSChnlnotnull = new MockServerSocketChannel(
108                SelectorProvider.provider());
109        assertEquals(SelectionKey.OP_ACCEPT, testMSChnlnotnull.validOps());
110        assertNull(testMSChnl.provider());
111        assertNotNull(testMSChnlnotnull.provider());
112        assertNotNull(this.serverChannel.provider());
113        assertEquals(testMSChnlnotnull.provider(), this.serverChannel
114                .provider());
115    }
116
117    // -------------------------------------------------------------------
118    // Test for socket()
119    // -------------------------------------------------------------------
120
121    /*
122     * Test method for 'java.nio.channels.ServerSocketChannel.socket()'
123     */
124    public void testSocket_Block_BeforeClose() throws Exception {
125        assertTrue(this.serverChannel.isOpen());
126        assertTrue(this.serverChannel.isBlocking());
127        ServerSocket s1 = this.serverChannel.socket();
128        assertFalse(s1.isClosed());
129        assertSocketNotAccepted(s1);
130        ServerSocket s2 = this.serverChannel.socket();
131        // same
132        assertSame(s1, s2);
133
134        // socket close makes the channel close
135        s1.close();
136        assertFalse(this.serverChannel.isOpen());
137
138    }
139
140    public void testSocket_NonBlock_BeforeClose() throws Exception {
141        assertTrue(this.serverChannel.isOpen());
142        this.serverChannel.configureBlocking(false);
143        ServerSocket s1 = this.serverChannel.socket();
144        assertFalse(s1.isClosed());
145        assertSocketNotAccepted(s1);
146        ServerSocket s2 = this.serverChannel.socket();
147        // same
148        assertSame(s1, s2);
149
150        // socket close makes the channel close
151        s1.close();
152        assertFalse(this.serverChannel.isOpen());
153
154    }
155
156    public void testSocket_Block_Closed() throws Exception {
157        this.serverChannel.close();
158        assertFalse(this.serverChannel.isOpen());
159        assertTrue(this.serverChannel.isBlocking());
160        ServerSocket s1 = this.serverChannel.socket();
161        assertTrue(s1.isClosed());
162        assertSocketNotAccepted(s1);
163        ServerSocket s2 = this.serverChannel.socket();
164        // same
165        assertSame(s1, s2);
166    }
167
168    public void testSocket_NonBlock_Closed() throws Exception {
169        this.serverChannel.configureBlocking(false);
170        this.serverChannel.close();
171        assertFalse(this.serverChannel.isBlocking());
172        assertFalse(this.serverChannel.isOpen());
173        ServerSocket s1 = this.serverChannel.socket();
174        assertTrue(s1.isClosed());
175        assertSocketNotAccepted(s1);
176        ServerSocket s2 = this.serverChannel.socket();
177        // same
178        assertSame(s1, s2);
179    }
180
181    private void assertSocketNotAccepted(ServerSocket s) throws IOException {
182        assertFalse(s.isBound());
183        assertNull(s.getInetAddress());
184        assertEquals(-1, s.getLocalPort());
185        assertNull(s.getLocalSocketAddress());
186        try {
187            assertEquals(0, s.getSoTimeout());
188        } catch (IOException expected) {
189            // Android doesn't cache the timeout, so the getsockopt(2) fails and throws.
190        }
191    }
192
193    public void testChannelBasicStatus() {
194        ServerSocket gotSocket = this.serverChannel.socket();
195        assertFalse(gotSocket.isClosed());
196        assertTrue(this.serverChannel.isBlocking());
197        assertFalse(this.serverChannel.isRegistered());
198        assertEquals(SelectionKey.OP_ACCEPT, this.serverChannel.validOps());
199        assertEquals(SelectorProvider.provider(), this.serverChannel.provider());
200    }
201
202    // -------------------------------------------------------------------
203    // Test for accept()
204    // -------------------------------------------------------------------
205
206    /*
207     * Test method for 'java.nio.channels.ServerSocketChannel.accept()'
208     */
209
210    public void testAccept_Block_NotYetBound() throws IOException {
211        assertTrue(this.serverChannel.isOpen());
212        assertTrue(this.serverChannel.isBlocking());
213        try {
214            this.serverChannel.accept();
215            fail("Should throw NotYetBoundException");
216        } catch (NotYetBoundException e) {
217            // correct
218        }
219    }
220
221    public void testAccept_NonBlock_NotYetBound() throws IOException {
222        assertTrue(this.serverChannel.isOpen());
223        this.serverChannel.configureBlocking(false);
224        try {
225            this.serverChannel.accept();
226            fail("Should throw NotYetBoundException");
227        } catch (NotYetBoundException e) {
228            // correct
229        }
230    }
231
232    public void testAccept_ClosedChannel() throws Exception {
233        this.serverChannel.close();
234        assertFalse(this.serverChannel.isOpen());
235        try {
236            this.serverChannel.accept();
237            fail("Should throw ClosedChannelException");
238        } catch (ClosedChannelException e) {
239            // OK.
240        }
241    }
242
243    public void testAccept_Block_NoConnect() throws IOException {
244        assertTrue(this.serverChannel.isBlocking());
245        ServerSocket gotSocket = this.serverChannel.socket();
246        gotSocket.bind(localAddr1);
247        // blocking mode , will block and wait for ever...
248        // so must close the server channel with another thread.
249        new Thread() {
250            public void run() {
251                try {
252                    Thread.sleep(TIME_UNIT);
253                    ServerSocketChannelTest.this.serverChannel.close();
254                } catch (Exception e) {
255                    fail("Fail to close the server channel because of"
256                            + e.getClass().getName());
257                }
258            }
259        }.start();
260        try {
261            this.serverChannel.accept();
262            fail("Should throw a AsynchronousCloseException");
263        } catch (AsynchronousCloseException e) {
264            // OK.
265        }
266    }
267
268    public void testAccept_NonBlock_NoConnect() throws IOException {
269        ServerSocket gotSocket = this.serverChannel.socket();
270        gotSocket.bind(localAddr1);
271        this.serverChannel.configureBlocking(false);
272        // non-blocking mode , will immediately return
273        assertNull(this.serverChannel.accept());
274    }
275
276    /**
277     * @tests ServerSocketChannel#accept().socket()
278     */
279    public void test_read_Blocking_RealData() throws IOException {
280        serverChannel.socket().bind(localAddr1);
281        ByteBuffer buf = ByteBuffer.allocate(CAPACITY_NORMAL);
282
283        for (int i = 0; i < CAPACITY_NORMAL; i++) {
284            buf.put((byte) i);
285        }
286        clientChannel.connect(localAddr1);
287        Socket serverSocket = serverChannel.accept().socket();
288        InputStream in = serverSocket.getInputStream();
289        buf.flip();
290        clientChannel.write(buf);
291        clientChannel.close();
292        assertReadResult(in,CAPACITY_NORMAL);
293    }
294
295    /**
296     * Asserts read content. The read content should contain <code>size</code>
297     * bytes, and the value should be a sequence from 0 to size-1
298     * ([0,1,...size-1]). Otherwise, the method throws Exception.
299     *
300     */
301    private void assertReadResult(InputStream in, int size) throws IOException{
302        byte[] readContent = new byte[size + 1];
303        int count = 0;
304        int total = 0;
305        while ((count = in.read(readContent, total, size + 1 - total)) != -1) {
306            total = total + count;
307        }
308        assertEquals(size, total);
309        for (int i = 0; i < size; i++) {
310            assertEquals((byte) i, readContent[i]);
311        }
312    }
313
314    /**
315     * @tests ServerSocketChannel#accept().socket()
316     */
317    public void test_read_NonBlocking_RealData() throws Exception {
318        serverChannel.configureBlocking(false);
319        serverChannel.socket().bind(localAddr1);
320        ByteBuffer buf = ByteBuffer.allocate(CAPACITY_NORMAL);
321        for (int i = 0; i < CAPACITY_NORMAL; i++) {
322            buf.put((byte) i);
323        }
324        buf.flip();
325        clientChannel.connect(localAddr1);
326        Socket serverSocket = serverChannel.accept().socket();
327        InputStream in = serverSocket.getInputStream();
328        clientChannel.write(buf);
329        clientChannel.close();
330        assertReadResult(in,CAPACITY_NORMAL);
331    }
332
333    /**
334     * @tests ServerSocketChannel#accept().socket()
335     */
336    public void test_write_Blocking_RealData() throws IOException {
337        assertTrue(serverChannel.isBlocking());
338        ServerSocket serverSocket = serverChannel.socket();
339        serverSocket.bind(localAddr1);
340
341        byte[] writeContent = new byte[CAPACITY_NORMAL];
342        for (int i = 0; i < writeContent.length; i++) {
343            writeContent[i] = (byte) i;
344        }
345        clientChannel.connect(localAddr1);
346        Socket socket = serverChannel.accept().socket();
347        OutputStream out = socket.getOutputStream();
348        out.write(writeContent);
349        out.flush();
350        socket.close();
351        assertWriteResult(CAPACITY_NORMAL);
352    }
353
354
355    /**
356     * @tests ServerSocketChannel#accept().socket()
357     */
358    public void test_write_NonBlocking_RealData() throws Exception {
359        serverChannel.configureBlocking(false);
360        ServerSocket serverSocket = serverChannel.socket();
361        serverSocket.bind(localAddr1);
362
363        byte[] writeContent = new byte[CAPACITY_NORMAL];
364        for (int i = 0; i < CAPACITY_NORMAL; i++) {
365            writeContent[i] = (byte) i;
366        }
367        clientChannel.connect(localAddr1);
368        Socket clientSocket = serverChannel.accept().socket();
369        OutputStream out = clientSocket.getOutputStream();
370        out.write(writeContent);
371        clientSocket.close();
372        assertWriteResult(CAPACITY_NORMAL);
373    }
374
375    /**
376     * @throws InterruptedException
377     * @tests ServerSocketChannel#accept().socket()
378     */
379    public void test_read_LByteBuffer_Blocking_ReadWriteRealLargeData()
380            throws IOException, InterruptedException {
381        serverChannel.socket().bind(localAddr1);
382        ByteBuffer buf = ByteBuffer.allocate(CAPACITY_64KB);
383        for (int i = 0; i < CAPACITY_64KB; i++) {
384            buf.put((byte) i);
385        }
386        buf.flip();
387        clientChannel.connect(localAddr1);
388        WriteChannelThread writeThread = new WriteChannelThread(clientChannel, buf);
389        writeThread.start();
390        Socket socket = serverChannel.accept().socket();
391        InputStream in = socket.getInputStream();
392        assertReadResult(in,CAPACITY_64KB);
393        writeThread.join();
394        // check if the thread threw any exceptions
395        if (writeThread.exception != null) {
396            throw writeThread.exception;
397        }
398    }
399
400    class WriteChannelThread extends Thread {
401        SocketChannel channel;
402        ByteBuffer buffer;
403        IOException exception;
404
405        public WriteChannelThread(SocketChannel channel, ByteBuffer buffer) {
406            this.channel = channel;
407            this.buffer = buffer;
408        }
409
410        public void run() {
411            try {
412                channel.write(buffer);
413                channel.close();
414            } catch (IOException e) {
415                exception = e;
416            }
417        }
418    }
419
420    /**
421     * @tests ServerSocketChannel#accept().socket()
422     */
423    public void test_read_LByteBuffer_NonBlocking_ReadWriteRealLargeData()
424            throws Exception {
425        serverChannel.configureBlocking(false);
426        serverChannel.socket().bind(localAddr1);
427        ByteBuffer buf = ByteBuffer.allocate(CAPACITY_64KB);
428        for (int i = 0; i < CAPACITY_64KB; i++) {
429            buf.put((byte) i);
430        }
431        buf.flip();
432        clientChannel.connect(localAddr1);
433        WriteChannelThread writeThread = new WriteChannelThread(clientChannel, buf);
434        writeThread.start();
435        Socket socket = serverChannel.accept().socket();
436        InputStream in = socket.getInputStream();
437        assertReadResult(in,CAPACITY_64KB);
438        writeThread.join();
439        // check if the thread threw any exceptions
440        if (writeThread.exception != null) {
441            throw writeThread.exception;
442        }
443    }
444
445    /**
446     * @tests ServerSocketChannel#accept().socket()
447     */
448    public void test_write_LByteBuffer_NonBlocking_ReadWriteRealLargeData()
449            throws Exception {
450        serverChannel.configureBlocking(false);
451        serverChannel.socket().bind(localAddr1);
452        byte[] writeContent = new byte[CAPACITY_64KB];
453        for (int i = 0; i < writeContent.length; i++) {
454            writeContent[i] = (byte) i;
455        }
456        clientChannel.connect(localAddr1);
457        Socket socket = serverChannel.accept().socket();
458        WriteSocketThread writeThread = new WriteSocketThread(socket, writeContent);
459        writeThread.start();
460        assertWriteResult(CAPACITY_64KB);
461        writeThread.join();
462        // check if the thread threw any exceptions
463        if (writeThread.exception != null) {
464            throw writeThread.exception;
465        }
466    }
467
468    class WriteSocketThread extends Thread {
469        Socket socket;
470        byte[] buffer;
471        IOException exception;
472
473        public WriteSocketThread(Socket socket, byte[] buffer) {
474            this.socket = socket;
475            this.buffer = buffer;
476        }
477
478        public void run() {
479            try {
480                OutputStream out = socket.getOutputStream();
481                out.write(buffer);
482                socket.close();
483            } catch (IOException e) {
484                exception = e;
485            }
486        }
487    }
488
489    /**
490     * @tests ServerSocketChannel#accept().socket()
491     */
492    public void test_write_LByteBuffer_Blocking_ReadWriteRealLargeData()
493            throws Exception {
494        serverChannel.socket().bind(localAddr1);
495        byte[] writeContent = new byte[CAPACITY_64KB];
496        for (int i = 0; i < writeContent.length; i++) {
497            writeContent[i] = (byte) i;
498        }
499        clientChannel.connect(localAddr1);
500        Socket socket = serverChannel.accept().socket();
501        WriteSocketThread writeThread = new WriteSocketThread(socket, writeContent);
502        writeThread.start();
503        assertWriteResult(CAPACITY_64KB);
504        writeThread.join();
505        // check if the thread threw any exceptions
506        if (writeThread.exception != null) {
507            throw writeThread.exception;
508        }
509    }
510
511    /**
512     * Uses SocketChannel.read(ByteBuffer) to verify write result.
513     */
514    private void assertWriteResult(int size) throws IOException{
515        ByteBuffer buf = ByteBuffer.allocate(size + 1);
516        int count = 0;
517        int total = 0;
518        long beginTime = System.currentTimeMillis();
519        while ((count = clientChannel.read(buf)) != -1) {
520            total = total + count;
521            // 10s timeout to avoid dead loop
522            if (System.currentTimeMillis() - beginTime > 10000){
523                break;
524            }
525        }
526        assertEquals(total, size);
527        buf.flip();
528        for (int i = 0; i < count; i++) {
529            assertEquals((byte) i, buf.get(i));
530        }
531    }
532
533    /**
534     * @tests ServerSocketChannel#socket().getSoTimeout()
535     */
536    public void test_accept_SOTIMEOUT() throws IOException {
537        // regression test for Harmony-707
538        final int SO_TIMEOUT = 10;
539        ServerSocketChannel sc = ServerSocketChannel.open();
540        try {
541            ServerSocket ss = sc.socket();
542            ss.bind(localAddr1);
543            sc.configureBlocking(false);
544            ss.setSoTimeout(SO_TIMEOUT);
545            SocketChannel client = sc.accept();
546            // non blocking mode, returns null since there are no pending connections.
547            assertNull(client);
548            int soTimeout = ss.getSoTimeout();
549            // Harmony fails here.
550            assertEquals(SO_TIMEOUT, soTimeout);
551        } finally {
552            sc.close();
553        }
554    }
555
556    /**
557     * @tests ServerSocket#socket().accept()
558     */
559    public void test_socket_accept_Blocking_NotBound() throws IOException {
560        // regression test for Harmony-748
561        ServerSocket gotSocket = serverChannel.socket();
562        serverChannel.configureBlocking(true);
563        try {
564            gotSocket.accept();
565            fail("Should throw an IllegalBlockingModeException");
566        } catch (IllegalBlockingModeException e) {
567            // expected
568        }
569        serverChannel.close();
570        try {
571            gotSocket.accept();
572            fail("Should throw an IllegalBlockingModeException");
573        } catch (IllegalBlockingModeException e) {
574            // expected
575        }
576    }
577
578    /**
579     * @tests ServerSocket#socket().accept()
580     */
581    public void test_socket_accept_Nonblocking_NotBound() throws IOException {
582        // regression test for Harmony-748
583        ServerSocket gotSocket = serverChannel.socket();
584        serverChannel.configureBlocking(false);
585        try {
586            gotSocket.accept();
587            fail("Should throw an IllegalBlockingModeException");
588        } catch (IllegalBlockingModeException e) {
589            // expected
590        }
591        serverChannel.close();
592        try {
593            gotSocket.accept();
594            fail("Should throw an IllegalBlockingModeException");
595        } catch (IllegalBlockingModeException e) {
596            // expected
597        }
598    }
599
600    /**
601     * @tests ServerSocket#socket().accept()
602     */
603    public void test_socket_accept_Nonblocking_Bound() throws IOException {
604        // regression test for Harmony-748
605        serverChannel.configureBlocking(false);
606        ServerSocket gotSocket = serverChannel.socket();
607        gotSocket.bind(localAddr1);
608        try {
609            gotSocket.accept();
610            fail("Should throw an IllegalBlockingModeException");
611        } catch (IllegalBlockingModeException e) {
612            // expected
613        }
614        serverChannel.close();
615        try {
616            gotSocket.accept();
617            fail("Should throw a ClosedChannelException");
618        } catch (ClosedChannelException e) {
619            // expected
620        }
621    }
622
623    /**
624     * @tests ServerSocket#socket().accept()
625     */
626    public void test_socket_accept_Blocking_Bound() throws IOException {
627        // regression test for Harmony-748
628        serverChannel.configureBlocking(true);
629        ServerSocket gotSocket = serverChannel.socket();
630        gotSocket.bind(localAddr1);
631        serverChannel.close();
632        try {
633            gotSocket.accept();
634            fail("Should throw a ClosedChannelException");
635        } catch (ClosedChannelException e) {
636            // expected
637        }
638    }
639    /**
640     * Regression test for HARMONY-4961
641     */
642    public void test_socket_getLocalPort() throws IOException {
643        serverChannel.socket().bind(localAddr1);
644        clientChannel.connect(localAddr1);
645        SocketChannel myChannel = serverChannel.accept();
646        int port = myChannel.socket().getLocalPort();
647        assertEquals(localAddr1.getPort(), port);
648        myChannel.close();
649        clientChannel.close();
650        serverChannel.close();
651    }
652
653    /**
654     * Regression test for HARMONY-6375
655     */
656    public void test_accept_configureBlocking() throws Exception {
657        InetSocketAddress localAddr = new InetSocketAddress("localhost", 0);
658        serverChannel.socket().bind(localAddr);
659
660        // configure the channel non-blocking
661        // when it is accepting in main thread
662        new Thread() {
663            public void run() {
664                try {
665                    Thread.sleep(TIME_UNIT);
666                    serverChannel.configureBlocking(false);
667                    serverChannel.close();
668                } catch (Exception e) {
669                    e.printStackTrace();
670                }
671            }
672        }.start();
673
674        try {
675            serverChannel.accept();
676            fail("should throw AsynchronousCloseException");
677        } catch (AsynchronousCloseException e) {
678            // expected
679        }
680        serverChannel.close();
681    }
682}
683