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 */
16package libcore.java.nio.channels;
17
18import android.system.OsConstants;
19import java.io.IOException;
20import java.net.InetSocketAddress;
21import java.net.ServerSocket;
22import java.nio.ByteBuffer;
23import java.nio.channels.NoConnectionPendingException;
24import java.nio.channels.SelectionKey;
25import java.nio.channels.Selector;
26import java.nio.channels.ServerSocketChannel;
27import java.nio.channels.SocketChannel;
28import java.util.concurrent.CountDownLatch;
29import java.util.concurrent.TimeUnit;
30import junit.framework.TestCase;
31import libcore.io.Libcore;
32import tests.net.StuckServer;
33
34public class SelectorTest extends TestCase {
35    public void testNonBlockingConnect_immediate() throws Exception {
36        // Test the case where we [probably] connect immediately.
37        Selector selector = Selector.open();
38        ServerSocketChannel ssc = ServerSocketChannel.open();
39        try {
40            ssc.configureBlocking(false);
41            ssc.socket().bind(null);
42
43            SocketChannel sc = SocketChannel.open();
44            sc.configureBlocking(false);
45            sc.connect(ssc.socket().getLocalSocketAddress());
46            SelectionKey key = sc.register(selector, SelectionKey.OP_CONNECT);
47            assertEquals(1, selector.select());
48            assertEquals(SelectionKey.OP_CONNECT, key.readyOps());
49            sc.finishConnect();
50        } finally {
51            selector.close();
52            ssc.close();
53        }
54    }
55
56    public void testNonBlockingConnect_slow() throws Exception {
57        // Test the case where we have to wait for the connection.
58        Selector selector = Selector.open();
59        StuckServer ss = new StuckServer(true);
60        try {
61            SocketChannel sc = SocketChannel.open();
62            sc.configureBlocking(false);
63            sc.connect(ss.getLocalSocketAddress());
64            SelectionKey key = sc.register(selector, SelectionKey.OP_CONNECT);
65            assertEquals(1, selector.select());
66            assertEquals(SelectionKey.OP_CONNECT, key.readyOps());
67            sc.finishConnect();
68        } finally {
69            selector.close();
70            ss.close();
71        }
72    }
73
74    // http://b/6453247
75    // This test won't work on the host until/unless we start using libcorkscrew there.
76    // The runtime itself blocks SIGQUIT, so that doesn't cause poll(2) to EINTR directly.
77    // The EINTR is caused by the way libcorkscrew works.
78    public void testEINTR() throws Exception {
79        Selector selector = Selector.open();
80        new Thread(new Runnable() {
81            @Override public void run() {
82                try {
83                    Thread.sleep(2000);
84                    Libcore.os.kill(Libcore.os.getpid(), OsConstants.SIGQUIT);
85                } catch (Exception ex) {
86                    fail();
87                }
88            }
89        }).start();
90        assertEquals(0, selector.select());
91    }
92
93    // http://code.google.com/p/android/issues/detail?id=15388
94    public void testInterrupted() throws IOException {
95        Selector selector = Selector.open();
96        Thread.currentThread().interrupt();
97        try {
98            int count = selector.select();
99            assertEquals(0, count);
100            assertTrue(Thread.currentThread().isInterrupted());
101        } finally {
102            // Clear the interrupted thread state so that it does not interfere with later tests.
103            Thread.interrupted();
104
105            selector.close();
106        }
107    }
108
109    public void testManyWakeupCallsTriggerOnlyOneWakeup() throws Exception {
110        final Selector selector = Selector.open();
111        try {
112            selector.wakeup();
113            selector.wakeup();
114            selector.wakeup();
115            selector.select();
116
117            // create a latch that will reach 0 when select returns
118            final CountDownLatch selectReturned = new CountDownLatch(1);
119            Thread thread = new Thread(new Runnable() {
120                @Override public void run() {
121                    try {
122                        selector.select();
123                        selectReturned.countDown();
124                    } catch (IOException ignored) {
125                    }
126                }
127            });
128            thread.start();
129
130            // select doesn't ever return, so await() times out and returns false
131            assertFalse(selectReturned.await(2, TimeUnit.SECONDS));
132        } finally {
133            selector.close();
134        }
135    }
136
137    // We previously leaked a file descriptor for each selector instance created.
138    //
139    // http://code.google.com/p/android/issues/detail?id=5993
140    // http://code.google.com/p/android/issues/detail?id=4825
141    public void testLeakingPipes() throws IOException {
142        for (int i = 0; i < 2000; i++) {
143            Selector selector = Selector.open();
144            selector.close();
145        }
146    }
147
148    public void test_57456() throws Exception {
149        Selector selector = Selector.open();
150        ServerSocketChannel ssc = ServerSocketChannel.open();
151
152        try {
153            // Connect.
154            ssc.configureBlocking(false);
155            ssc.socket().bind(null);
156            SocketChannel sc = SocketChannel.open();
157            sc.connect(ssc.socket().getLocalSocketAddress());
158            sc.finishConnect();
159
160            // Switch to non-blocking so we can use a Selector.
161            sc.configureBlocking(false);
162
163            // Have the 'server' write something.
164            ssc.accept().write(ByteBuffer.allocate(128));
165
166            // At this point, the client should be able to read or write immediately.
167            // (It shouldn't be able to connect because it's already connected.)
168            SelectionKey key = sc.register(selector,
169                    SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE);
170            assertEquals(1, selector.select());
171            assertEquals(SelectionKey.OP_READ | SelectionKey.OP_WRITE, key.readyOps());
172            assertEquals(0, selector.select());
173        } finally {
174            selector.close();
175            ssc.close();
176        }
177    }
178
179    // http://code.google.com/p/android/issues/detail?id=80785
180    public void test_80785() throws Exception {
181        Selector selector = Selector.open();
182        selector.close();
183
184        // Historically on android this did not throw an exception. Due to the bug it would throw
185        // an (undeclared) IOException.
186        selector.wakeup();
187    }
188}
189