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 libcore.java.nio.channels;
19
20import dalvik.annotation.BrokenTest;
21import java.io.IOException;
22import java.net.InetAddress;
23import java.net.InetSocketAddress;
24import java.net.ServerSocket;
25import java.net.Socket;
26import java.net.SocketAddress;
27import java.net.SocketException;
28import java.nio.ByteBuffer;
29import java.nio.channels.NoConnectionPendingException;
30import java.nio.channels.NotYetConnectedException;
31import java.nio.channels.SelectionKey;
32import java.nio.channels.ServerSocketChannel;
33import java.nio.channels.SocketChannel;
34import java.nio.channels.UnresolvedAddressException;
35import java.nio.channels.UnsupportedAddressTypeException;
36import java.nio.channels.spi.SelectorProvider;
37import junit.framework.TestCase;
38
39public class OldSocketChannelTest extends TestCase {
40
41    private static final int CAPACITY_NORMAL = 200;
42
43    private static final int CAPACITY_HUGE = 512 * 1024;
44
45    private InetSocketAddress localAddr1;
46
47    private SocketChannel channel1;
48
49    private SocketChannel channel2;
50
51    private ServerSocket server1;
52
53    private final static int TIMEOUT = 60000;
54
55    protected void setUp() throws Exception {
56        super.setUp();
57        this.channel1 = SocketChannel.open();
58        this.channel2 = SocketChannel.open();
59        this.server1 = new ServerSocket(0);
60        this.localAddr1 = (InetSocketAddress) server1.getLocalSocketAddress();
61    }
62
63    protected void tearDown() throws Exception {
64        super.tearDown();
65        if (null != this.channel1) {
66            try {
67                this.channel1.close();
68            } catch (Exception e) {
69                // ignore
70            }
71        }
72        if (null != this.channel2) {
73            try {
74                this.channel2.close();
75            } catch (Exception e) {
76                // ignore
77            }
78        }
79        if (null != this.server1) {
80            try {
81                this.server1.close();
82            } catch (Exception e) {
83                // ignore
84            }
85        }
86    }
87
88    // -------------------------------------------------------------------
89    // Test for methods in abstract class.
90    // -------------------------------------------------------------------
91    public void testConstructor() throws IOException {
92        SocketChannel channel =
93                SelectorProvider.provider().openSocketChannel();
94        assertNotNull(channel);
95        assertSame(SelectorProvider.provider(), channel.provider());
96        channel = SocketChannel.open();
97        assertNotNull(channel);
98        assertSame(SelectorProvider.provider(), channel.provider());
99        MockSocketChannel chan = new MockSocketChannel(
100                SelectorProvider.provider());
101        assertTrue(chan.isConstructorCalled);
102    }
103
104    public void testValidOps() {
105        MockSocketChannel testMSChannel = new MockSocketChannel(null);
106        assertEquals(13, this.channel1.validOps());
107        assertEquals(13, testMSChannel.validOps());
108    }
109
110    public void testOpen() throws IOException {
111        java.nio.ByteBuffer[] buf = new java.nio.ByteBuffer[1];
112        buf[0] = java.nio.ByteBuffer.allocateDirect(CAPACITY_NORMAL);
113        MockSocketChannel testMSChannel = new MockSocketChannel(null);
114        MockSocketChannel testMSChannelnotnull = new MockSocketChannel(
115                SelectorProvider.provider());
116        SocketChannel testSChannel = MockSocketChannel.open();
117        assertTrue(testSChannel.isOpen());
118        assertNull(testMSChannel.provider());
119        assertNotNull(testSChannel.provider());
120        assertEquals(SelectorProvider.provider(), testSChannel.provider());
121        assertNotNull(testMSChannelnotnull.provider());
122        assertEquals(this.channel1.provider(), testMSChannelnotnull.provider());
123        try {
124            this.channel1.write(buf);
125            fail("Should throw NotYetConnectedException");
126        } catch (NotYetConnectedException e) {
127            // correct
128        }
129    }
130
131    public void testIsOpen() throws Exception {
132        assertTrue(this.channel1.isOpen());
133        this.channel1.close();
134        assertFalse(this.channel1.isOpen());
135    }
136
137    public void testIsConnected() throws Exception {
138        assertFalse(this.channel1.isConnected());// not connected
139        this.channel1.configureBlocking(false);
140        assertFalse(this.channel1.connect(localAddr1));
141        assertFalse(this.channel1.isConnected());
142        assertTrue(this.channel1.isConnectionPending());
143        assertTrue(tryFinish());
144        assertTrue(this.channel1.isConnected());
145        this.channel1.close();
146        assertFalse(this.channel1.isConnected());
147    }
148
149    public void testIsConnectionPending() throws Exception {
150        // ensure
151        ensureServerClosed();
152        this.channel1.configureBlocking(false);
153        assertFalse(this.channel1.isConnectionPending());
154        // finish
155        try {
156            this.channel1.finishConnect();
157            fail("Should throw NoConnectionPendingException");
158        } catch (NoConnectionPendingException e) {
159            // OK.
160        }
161        assertFalse(this.channel1.isConnectionPending());
162        // connect
163        assertFalse(this.channel1.connect(localAddr1));
164        assertTrue(this.channel1.isConnectionPending());
165        this.channel1.close();
166
167        assertFalse(this.channel1.isConnectionPending());
168    }
169
170    public void testChannelBasicStatus() {
171        Socket gotSocket = this.channel1.socket();
172        assertFalse(gotSocket.isClosed());
173        assertTrue(this.channel1.isBlocking());
174        assertFalse(this.channel1.isRegistered());
175        assertEquals((SelectionKey.OP_CONNECT | SelectionKey.OP_READ |
176                SelectionKey.OP_WRITE), this.channel1.validOps());
177        assertEquals(SelectorProvider.provider(), this.channel1.provider());
178    }
179
180    public void testOpenSocketAddress() throws IOException {
181        this.channel1 = SocketChannel.open(localAddr1);
182        assertTrue(this.channel1.isConnected());
183
184        SocketAddress newTypeAddress = new SubSocketAddress();
185        try {
186            this.channel1 = SocketChannel.open(newTypeAddress);
187            fail("Should throw UnexpectedAddressTypeException");
188        } catch (UnsupportedAddressTypeException e) {
189            // expected
190        }
191
192        SocketAddress unresolvedAddress =
193                InetSocketAddress.createUnresolved("127.0.0.1", 8080);
194        try {
195            this.channel1 = SocketChannel.open(unresolvedAddress);
196            fail("Should throw UnresolvedAddressException");
197        } catch (UnresolvedAddressException e) {
198            // expected
199        }
200
201        SocketChannel channel1IP = null;
202        try {
203            channel1IP = SocketChannel.open(null);
204            fail("Should throw an IllegalArgumentException");
205        } catch (IllegalArgumentException e) {
206            // correct
207        }
208        assertNull(channel1IP);
209    }
210
211    private void ensureServerClosed() throws IOException {
212        if (null != this.server1) {
213            this.server1.close();
214            assertTrue(this.server1.isClosed());
215        }
216    }
217
218    private void statusConnected_NotPending() {
219        assertTrue(this.channel1.isConnected());
220        assertFalse(this.channel1.isConnectionPending());
221        assertTrue(this.channel1.isOpen());
222    }
223
224    private boolean tryFinish() throws IOException {
225        /*
226         * the result of finish will be asserted in multi-thread tests.
227         */
228        boolean connected = false;
229        assertTrue(this.channel1.isOpen());
230        try {
231            connected = this.channel1.finishConnect();
232        } catch (SocketException e) {
233            // Finish connection failed, probably due to reset by peer error.
234        }
235        if (connected) {
236            statusConnected_NotPending();
237        }
238        return connected;
239    }
240
241    @BrokenTest("Occasionally fail in CTS, but works in CoreTestRunner")
242    public void test_writeLjava_nio_ByteBuffer_Nonblocking_HugeData() throws IOException {
243        // initialize write content
244        ByteBuffer writeContent = ByteBuffer.allocate(CAPACITY_HUGE);
245        for (int i = 0; i < CAPACITY_HUGE; i++) {
246            writeContent.put((byte) i);
247        }
248        writeContent.flip();
249
250        // establish connection
251        channel1.connect(localAddr1);
252        Socket acceptedSocket = server1.accept();
253
254        channel1.configureBlocking(false);
255        int writtenTotalCount = 0;
256        int writtenCount = 1;
257        long startTime = System.currentTimeMillis();
258        // use SocketChannel.write(ByteBuffer) to try to write CAPACITY_HUGE bytes
259        while (writtenTotalCount < CAPACITY_HUGE && writtenCount > 0) {
260            writtenCount = channel1.write(writeContent);
261            if (writtenCount == 0 && writtenTotalCount < CAPACITY_HUGE) {
262                assertEquals(0, channel1.write(writeContent));
263                break;
264            }
265            writtenTotalCount += writtenCount;
266            // if the channel could not finish writing in TIMEOUT ms, the
267            // test fails. It is used to guarantee the test never hangs even
268            // if there are bugs of SocketChannel implementation.
269            assertTimeout(startTime, TIMEOUT);
270        }
271    }
272
273    /*
274     * Fails if the difference between current time and start time is greater
275     * than timeout.
276     */
277    private void assertTimeout(long startTime, long timeout) {
278        long currentTime = System.currentTimeMillis();
279        if ((currentTime - startTime) > timeout) {
280            fail("Timeout");
281        }
282    }
283
284    public void test_socketChannel_read_DirectByteBuffer() throws InterruptedException, IOException {
285        final ServerSocketChannel ssc = ServerSocketChannel.open();
286        ssc.socket().bind(null, 0);
287
288        Thread server = new Thread() {
289            @Override public void run() {
290                try {
291                    for (int i = 0; i < 2; ++i) {
292                        ByteBuffer buf = ByteBuffer.allocate(10);
293                        buf.put(data);
294                        buf.rewind();
295                        ssc.accept().write(buf);
296                    }
297                } catch (Exception ignored) {
298                }
299            }
300        };
301        server.start();
302
303        // First test with array based byte buffer
304        SocketChannel sc = SocketChannel.open();
305        sc.connect(ssc.socket().getLocalSocketAddress());
306
307        ByteBuffer buf = ByteBuffer.allocate(data.length);
308        buf.limit(data.length / 2);
309        sc.read(buf);
310
311        buf.limit(buf.capacity());
312        sc.read(buf);
313        sc.close();
314
315        // Make sure the buffer is filled correctly
316        buf.rewind();
317        assertSameContent(data, buf);
318
319        // Now test with direct byte buffer
320        sc = SocketChannel.open();
321        sc.connect(ssc.socket().getLocalSocketAddress());
322
323        buf = ByteBuffer.allocateDirect(data.length);
324        buf.limit(data.length / 2);
325        sc.read(buf);
326
327        buf.limit(buf.capacity());
328        sc.read(buf);
329        sc.close();
330
331        // Make sure the buffer is filled correctly
332        buf.rewind();
333        assertSameContent(data, buf);
334    }
335
336    private void assertSameContent(byte[] data, ByteBuffer buf) {
337        for (byte b : data) {
338            if (b != buf.get()) {
339                int pos = buf.position() - 1;
340                fail("Content not equal. Buffer position: " +
341                        (pos) + " expected: " + b + " was: " + buf.get(pos));
342            }
343        }
344    }
345
346    public static boolean done = false;
347    public static byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
348
349    class MockSocketChannel extends SocketChannel {
350
351        private boolean isConstructorCalled = false;
352
353        public MockSocketChannel(SelectorProvider provider) {
354            super(provider);
355            isConstructorCalled = true;
356        }
357
358        public Socket socket() {
359            return null;
360        }
361
362        public boolean isConnected() {
363            return false;
364        }
365
366        public boolean isConnectionPending() {
367            return false;
368        }
369
370        public boolean connect(SocketAddress address) throws IOException {
371            return false;
372        }
373
374        public boolean finishConnect() throws IOException {
375            return false;
376        }
377
378        public int read(ByteBuffer target) throws IOException {
379            return 0;
380        }
381
382        public long read(ByteBuffer[] targets, int offset, int length)
383                throws IOException {
384            return 0;
385        }
386
387        public int write(ByteBuffer source) throws IOException {
388            return 0;
389        }
390
391        public long write(ByteBuffer[] sources, int offset, int length)
392                throws IOException {
393            return 0;
394        }
395
396        protected void implCloseSelectableChannel() throws IOException {
397            // empty
398        }
399
400        protected void implConfigureBlocking(boolean blockingMode)
401                throws IOException {
402            // empty
403        }
404    }
405
406    class SubSocketAddress extends SocketAddress {
407        private static final long serialVersionUID = 1L;
408
409        // empty
410        public SubSocketAddress() {
411            super();
412        }
413    }
414}
415