# HG changeset patch # User alanb # Date 1277827872 -3600 # Node ID b5bc332cd233fb14e266a87d9a59b94175d6eff2 # Parent de622fe4f7d8f5481fe4afb839b0d90e43bc54b9 6213702: (so) non-blocking sockets with TCP urgent disabled get still selected for read ops (win) Reviewed-by: michaelm, chegar diff -r de622fe4f7d8 -r b5bc332cd233 jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java --- a/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java Mon Jun 28 18:25:03 2010 -0700 +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java Tue Jun 29 17:11:12 2010 +0100 @@ -312,14 +312,17 @@ private int processSelectedKeys(long updateCount) { int numKeysUpdated = 0; numKeysUpdated += processFDSet(updateCount, readFds, - PollArrayWrapper.POLLIN); + PollArrayWrapper.POLLIN, + false); numKeysUpdated += processFDSet(updateCount, writeFds, PollArrayWrapper.POLLCONN | - PollArrayWrapper.POLLOUT); + PollArrayWrapper.POLLOUT, + false); numKeysUpdated += processFDSet(updateCount, exceptFds, PollArrayWrapper.POLLIN | PollArrayWrapper.POLLCONN | - PollArrayWrapper.POLLOUT); + PollArrayWrapper.POLLOUT, + true); return numKeysUpdated; } @@ -331,7 +334,9 @@ * * me.updateCount <= me.clearedCount <= updateCount */ - private int processFDSet(long updateCount, int[] fds, int rOps) { + private int processFDSet(long updateCount, int[] fds, int rOps, + boolean isExceptFds) + { int numKeysUpdated = 0; for (int i = 1; i <= fds[0]; i++) { int desc = fds[i]; @@ -347,6 +352,17 @@ if (me == null) continue; SelectionKeyImpl sk = me.ski; + + // The descriptor may be in the exceptfds set because there is + // OOB data queued to the socket. If there is OOB data then it + // is discarded and the key is not added to the selected set. + if (isExceptFds && + (sk.channel() instanceof SocketChannelImpl) && + discardUrgentData(desc)) + { + continue; + } + if (selectedKeys.contains(sk)) { // Key in selected set if (me.clearedCount != updateCount) { if (sk.channel.translateAndSetReadyOps(rOps, sk) && @@ -460,6 +476,8 @@ private native void resetWakeupSocket0(int wakeupSourceFd); + private native boolean discardUrgentData(int fd); + // We increment this counter on each call to updateSelectedKeys() // each entry in SubSelector.fdsMap has a memorized value of // updateCount. When we increment numKeysUpdated we set updateCount diff -r de622fe4f7d8 -r b5bc332cd233 jdk/src/windows/native/sun/nio/ch/WindowsSelectorImpl.c --- a/jdk/src/windows/native/sun/nio/ch/WindowsSelectorImpl.c Mon Jun 28 18:25:03 2010 -0700 +++ b/jdk/src/windows/native/sun/nio/ch/WindowsSelectorImpl.c Tue Jun 29 17:11:12 2010 +0100 @@ -214,3 +214,19 @@ recv(scinFd, bytes, WAKEUP_SOCKET_BUF_SIZE, 0); } } + +JNIEXPORT jboolean JNICALL +Java_sun_nio_ch_WindowsSelectorImpl_discardUrgentData(JNIEnv* env, jobject this, + jint s) +{ + char data[8]; + jboolean discarded = JNI_FALSE; + int n; + do { + n = recv(s, &data, sizeof(data), MSG_OOB); + if (n > 0) { + discarded = JNI_TRUE; + } + } while (n > 0); + return discarded; +} diff -r de622fe4f7d8 -r b5bc332cd233 jdk/test/java/nio/channels/Selector/OutOfBand.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/Selector/OutOfBand.java Tue Jun 29 17:11:12 2010 +0100 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 6213702 + * @summary OOB data causes a SocketChannel, with OOBINLINE disabled, to be + * selected + */ + +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.io.IOException; + +public class OutOfBand { + + public static void main(String[] args) throws Exception { + ServerSocketChannel ssc = null; + SocketChannel sc = null; + Selector sel = null; + Socket s = null; + + try { + // establish loopback connection. + ssc = ServerSocketChannel.open().bind(new InetSocketAddress(0)); + s = new Socket(InetAddress.getLocalHost(), + ssc.socket().getLocalPort()); + sc = ssc.accept(); + + sel = Selector.open(); + sc.configureBlocking(false); + sc.register(sel, SelectionKey.OP_READ); + + // OOB data should be disabled by default + if (sc.socket().getOOBInline()) + throw new RuntimeException("SO_OOBINLINE enabled"); + test(s, false, 0, 0, sel); + test(s, false, 512, 0, sel); + test(s, false, 0, 512, sel); + test(s, false, 512, 512, sel); + + // enable SO_OOBINLINE + sc.socket().setOOBInline(true); + + // OOB data should be received + test(s, true, 0, 0, sel); + test(s, true, 512, 0, sel); + test(s, true, 0, 512, sel); + test(s, true, 512, 512, sel); + + } finally { + if (sel != null) sel.close(); + if (sc != null) sc.close(); + if (ssc != null) ssc.close(); + if (s != null) sc.close(); + } + } + + static void test(Socket s, boolean urgentExpected, + int bytesBefore, int bytesAfter, + Selector sel) + throws IOException + { + // send data + int bytesExpected = 0; + if (bytesBefore > 0) { + s.getOutputStream().write(new byte[bytesBefore]); + bytesExpected += bytesBefore; + } + s.sendUrgentData(0xff); + if (urgentExpected) + bytesExpected++; + if (bytesAfter > 0) { + s.getOutputStream().write(new byte[bytesAfter]); + bytesExpected += bytesAfter; + } + + // receive data, checking for spurious wakeups and reads + int spuriousWakeups = 0; + int spuriousReads = 0; + int bytesRead = 0; + ByteBuffer bb = ByteBuffer.allocate(100); + for (;;) { + int n = sel.select(2000); + if (n == 0) { + if (bytesRead == bytesExpected) { + System.out.format("Selector wakeups %d\tSpurious reads %d%n", + spuriousWakeups, spuriousReads); + return; + } + if (++spuriousWakeups >= 3) + throw new RuntimeException("Selector appears to be spinning" + + " or data not received"); + continue; + } + if (n > 1) + throw new RuntimeException("More than one key selected????"); + SelectionKey key = sel.selectedKeys().iterator().next(); + bb.clear(); + n = ((SocketChannel)key.channel()).read(bb); + if (n == 0) { + if (++spuriousReads >=3) + throw new RuntimeException("Too many spurious reads"); + } else { + bytesRead += n; + if (bytesRead > bytesExpected) + throw new RuntimeException("Received more than expected"); + } + sel.selectedKeys().clear(); + } + } +}