From 0807c38b7b7e52bd47f2cbf62294f45489e3f7c7 Mon Sep 17 00:00:00 2001 From: alanb Date: Wed, 9 Jun 2010 18:51:32 +0100 Subject: [PATCH] 6935563: (dc) Improve connection reset/port unreachable handling [win] Reviewed-by: chegar --- .../native/sun/nio/ch/DatagramChannelImpl.c | 6 ++ src/windows/native/sun/nio/ch/Net.c | 24 ++++- .../DatagramChannel/SelectWhenRefused.java | 94 +++++++++++++++++++ 3 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 test/java/nio/channels/DatagramChannel/SelectWhenRefused.java diff --git a/src/windows/native/sun/nio/ch/DatagramChannelImpl.c b/src/windows/native/sun/nio/ch/DatagramChannelImpl.c index 3dfa490f5..64156b861 100644 --- a/src/windows/native/sun/nio/ch/DatagramChannelImpl.c +++ b/src/windows/native/sun/nio/ch/DatagramChannelImpl.c @@ -120,6 +120,12 @@ Java_sun_nio_ch_DatagramChannelImpl_disconnect0(JNIEnv *env, jobject this, rv = connect((SOCKET)fd, (struct sockaddr *)&sa, sa_len); if (rv == SOCKET_ERROR) { handleSocketError(env, WSAGetLastError()); + } else { + /* Disable WSAECONNRESET errors as socket is no longer connected */ + BOOL enable = FALSE; + DWORD bytesReturned = 0; + WSAIoctl((SOCKET)fd, SIO_UDP_CONNRESET, &enable, sizeof(enable), + NULL, 0, &bytesReturned, NULL, NULL); } } diff --git a/src/windows/native/sun/nio/ch/Net.c b/src/windows/native/sun/nio/ch/Net.c index da485d8e4..a145393e0 100644 --- a/src/windows/native/sun/nio/ch/Net.c +++ b/src/windows/native/sun/nio/ch/Net.c @@ -67,6 +67,14 @@ typedef struct my_group_source_req { #define COPY_INET6_ADDRESS(env, source, target) \ (*env)->GetByteArrayRegion(env, source, 0, 16, target) +/** + * Enable or disable receipt of WSAECONNRESET errors. + */ +static void setConnectionReset(SOCKET s, BOOL enable) { + DWORD bytesReturned = 0; + WSAIoctl(s, SIO_UDP_CONNRESET, &enable, sizeof(enable), + NULL, 0, &bytesReturned, NULL, NULL); +} JNIEXPORT void JNICALL @@ -109,6 +117,12 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&opt, sizeof(opt)); } + + /* Disable WSAECONNRESET errors for initially unconnected UDP sockets */ + if (!stream) { + setConnectionReset(s, FALSE); + } + } else { NET_ThrowNew(env, WSAGetLastError(), "socket"); } @@ -149,12 +163,13 @@ Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, job SOCKETADDRESS sa; int rv; int sa_len; + SOCKET s = (SOCKET)fdval(env, fdo); if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) { return IOS_THROWN; } - rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); + rv = connect(s, (struct sockaddr *)&sa, sa_len); if (rv != 0) { int err = WSAGetLastError(); if (err == WSAEINPROGRESS || err == WSAEWOULDBLOCK) { @@ -162,6 +177,13 @@ Java_sun_nio_ch_Net_connect0(JNIEnv *env, jclass clazz, jboolean preferIPv6, job } NET_ThrowNew(env, err, "connect"); return IOS_THROWN; + } else { + /* Enable WSAECONNRESET errors when a UDP socket is connected */ + int type = 0, optlen = sizeof(type); + rv = getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&type, &optlen); + if (rv == 0 && type == SOCK_DGRAM) { + setConnectionReset(s, TRUE); + } } return 1; } diff --git a/test/java/nio/channels/DatagramChannel/SelectWhenRefused.java b/test/java/nio/channels/DatagramChannel/SelectWhenRefused.java new file mode 100644 index 000000000..fdbbd3600 --- /dev/null +++ b/test/java/nio/channels/DatagramChannel/SelectWhenRefused.java @@ -0,0 +1,94 @@ +/* + * 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 6935563 + * @summary Test that Selector does not select an unconnected DatagramChannel when + * ICMP port unreachable received + */ + +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.net.*; +import java.io.IOException; + +public class SelectWhenRefused { + + public static void main(String[] args) throws IOException { + DatagramChannel dc = DatagramChannel.open().bind(new InetSocketAddress(0)); + int port = dc.socket().getLocalPort(); + dc.close(); + + // datagram sent to this address should be refused + SocketAddress refuser = new InetSocketAddress(InetAddress.getLocalHost(), port); + + dc = DatagramChannel.open().bind(new InetSocketAddress(0)); + try { + dc.configureBlocking(false); + Selector sel = Selector.open(); + dc.register(sel, SelectionKey.OP_READ); + + /* Test 1: not connected so ICMP port unreachable should not be received */ + sendDatagram(dc, refuser); + int n = sel.select(2000); + if (n > 0) { + throw new RuntimeException("Unexpected wakeup"); + } + + /* Test 2: connected so ICMP port unreachable may be received */ + dc.connect(refuser); + try { + sendDatagram(dc, refuser); + n = sel.select(2000); + if (n > 0) { + sel.selectedKeys().clear(); + try { + n = dc.read(ByteBuffer.allocate(100)); + throw new RuntimeException("Unexpected datagram received"); + } catch (PortUnreachableException pue) { + // expected + } + } + } finally { + dc.disconnect(); + } + + /* Test 3: not connected so ICMP port unreachable should not be received */ + sendDatagram(dc, refuser); + n = sel.select(2000); + if (n > 0) { + throw new RuntimeException("Unexpected wakeup after disconnect"); + } + + } finally { + dc.close(); + } + } + + static void sendDatagram(DatagramChannel dc, SocketAddress remote) + throws IOException + { + ByteBuffer bb = ByteBuffer.wrap("Greetings!".getBytes()); + dc.send(bb, remote); + } +} -- GitLab