8293696: java/nio/channels/DatagramChannel/SelectWhenRefused.java fails with "Unexpected wakeup"
Reviewed-by: dfuchs, msheppar
This commit is contained in:
parent
4a300818fe
commit
fdabd37960
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2022, 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
|
||||
@ -25,16 +25,25 @@
|
||||
* @bug 6935563 7044870
|
||||
* @summary Test that Selector does not select an unconnected DatagramChannel when
|
||||
* ICMP port unreachable received
|
||||
* @run junit/othervm SelectWhenRefused
|
||||
*/
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.*;
|
||||
import java.net.*;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
|
||||
public class SelectWhenRefused {
|
||||
static final int MAX_TRIES = 3;
|
||||
static final String GREETINGS_MESSAGE = "Greetings from SelectWhenRefused!";
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
@Test
|
||||
public void test() throws IOException {
|
||||
DatagramChannel dc1 = DatagramChannel.open().bind(new InetSocketAddress(0));
|
||||
int port = dc1.socket().getLocalPort();
|
||||
|
||||
@ -50,53 +59,193 @@ public class SelectWhenRefused {
|
||||
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) {
|
||||
sel.selectedKeys().clear();
|
||||
// BindException will be thrown if another service is using
|
||||
// our expected refuser port, cannot run just exit.
|
||||
DatagramChannel.open().bind(refuser).close();
|
||||
throw new RuntimeException("Unexpected wakeup");
|
||||
for (int i = 1; i <= MAX_TRIES; i++) {
|
||||
if (testNoPUEBeforeConnection(dc, refuser, sel, i)) {
|
||||
break; // test succeeded
|
||||
}
|
||||
assertNotEquals(i, MAX_TRIES, "testNoPUEBeforeConnection: too many retries");
|
||||
}
|
||||
|
||||
/* 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
|
||||
for (int i = 1; i <= MAX_TRIES; i++) {
|
||||
if (testPUEOnConnect(dc, refuser, sel, i)) {
|
||||
break; // test passed
|
||||
}
|
||||
assertNotEquals(i, MAX_TRIES, "testPUEOnConnect: too many retries");
|
||||
}
|
||||
} 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");
|
||||
for (int i = 1; i <= MAX_TRIES; i++) {
|
||||
if (testNoPUEAfterDisconnect(dc, refuser, sel, i)) {
|
||||
break; // test passed
|
||||
}
|
||||
assertNotEquals(i, MAX_TRIES, "testNoPUEAfterDisconnect: too many retries");
|
||||
}
|
||||
|
||||
} catch(BindException e) {
|
||||
} catch (BindException e) {
|
||||
// Do nothing, some other test has used this port
|
||||
System.out.println("Skipping test: refuser port has been reused: " + e);
|
||||
} finally {
|
||||
sel.close();
|
||||
dc.close();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a datagram to non existent unconnected UDP end point
|
||||
* This shouldn't result in an PortUnreachableException
|
||||
* Handle unexpected read events on the senders DC with
|
||||
* retry when message received is external and Throw Exception
|
||||
* on receipt of own message
|
||||
*/
|
||||
static boolean testNoPUEBeforeConnection(DatagramChannel dc,
|
||||
SocketAddress refuser,
|
||||
Selector sel,
|
||||
int retryCount) throws IOException {
|
||||
sendDatagram(dc, refuser);
|
||||
int n = sel.select(2000);
|
||||
if (n > 0) {
|
||||
boolean mayRetry = checkUnexpectedWakeup(sel.selectedKeys());
|
||||
boolean tooManyRetries = retryCount >= MAX_TRIES;
|
||||
sel.selectedKeys().clear();
|
||||
|
||||
if (mayRetry && !tooManyRetries) {
|
||||
return false; // will retry
|
||||
}
|
||||
|
||||
// BindException will be thrown if another service is using
|
||||
// our expected refuser port, cannot run just exit.
|
||||
DatagramChannel.open().bind(refuser).close();
|
||||
throw new RuntimeException("Unexpected wakeup");
|
||||
}
|
||||
return true; // test passed
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a datagram to a connected UDP end point
|
||||
* This should result in an PortUnreachableException
|
||||
* Handle unexpected read events on the senders DC with
|
||||
* retry when message received is external and Throw Exception
|
||||
* on receipt of own message
|
||||
*/
|
||||
static boolean testPUEOnConnect(DatagramChannel dc,
|
||||
SocketAddress refuser,
|
||||
Selector sel,
|
||||
int retryCount) throws IOException {
|
||||
sendDatagram(dc, refuser);
|
||||
int n = sel.select(2000);
|
||||
if (n > 0) {
|
||||
sel.selectedKeys().clear();
|
||||
|
||||
try {
|
||||
// Attempt to read from Selected Key
|
||||
ByteBuffer buf = ByteBuffer.allocate(100);
|
||||
SocketAddress sa = dc.receive(buf);
|
||||
|
||||
if (sa != null) {
|
||||
buf.flip();
|
||||
byte[] bytes = new byte[buf.remaining()];
|
||||
buf.get(bytes);
|
||||
String message = new String(bytes);
|
||||
System.out.format("received %s at %s from %s%n", message, dc.getLocalAddress(), sa);
|
||||
|
||||
// If any received data contains the message from sendDatagram then throw exception
|
||||
if (message.contains(GREETINGS_MESSAGE)) {
|
||||
throw new RuntimeException("Unexpected datagram received");
|
||||
}
|
||||
}
|
||||
|
||||
boolean mayRetry = retryCount < MAX_TRIES;
|
||||
if (mayRetry) {
|
||||
return false; // will retry
|
||||
}
|
||||
|
||||
// BindException will be thrown if another service is using
|
||||
// our expected refuser port, cannot run just exit.
|
||||
DatagramChannel.open().bind(refuser).close();
|
||||
throw new RuntimeException("PortUnreachableException not raised");
|
||||
} catch (PortUnreachableException pue) {
|
||||
System.out.println("Got expected PortUnreachableException " + pue);
|
||||
}
|
||||
}
|
||||
return true; // test passed
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a datagram to a disconnected UDP end point
|
||||
* This should result in an PortUnreachableException
|
||||
* Handle unexpected read events on the senders DC with
|
||||
* retry when message received is external and Throw Exception
|
||||
* on receipt of own message
|
||||
*/
|
||||
static boolean testNoPUEAfterDisconnect(DatagramChannel dc,
|
||||
SocketAddress refuser,
|
||||
Selector sel,
|
||||
int retryCount) throws IOException {
|
||||
sendDatagram(dc, refuser);
|
||||
int n = sel.select(2000);
|
||||
if (n > 0) {
|
||||
boolean mayRetry = checkUnexpectedWakeup(sel.selectedKeys());
|
||||
boolean tooManyRetries = retryCount >= MAX_TRIES;
|
||||
sel.selectedKeys().clear();
|
||||
|
||||
if (mayRetry && !tooManyRetries) {
|
||||
return false; // will retry
|
||||
}
|
||||
|
||||
throw new RuntimeException("Unexpected wakeup after disconnect");
|
||||
}
|
||||
return true; // test passed
|
||||
}
|
||||
|
||||
static void sendDatagram(DatagramChannel dc, SocketAddress remote)
|
||||
throws IOException
|
||||
{
|
||||
ByteBuffer bb = ByteBuffer.wrap("Greetings!".getBytes());
|
||||
throws IOException {
|
||||
ByteBuffer bb = ByteBuffer.wrap(GREETINGS_MESSAGE.getBytes());
|
||||
dc.send(bb, remote);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to read and Log the data from SelectedKeys,
|
||||
* If a message can be received, and it came from
|
||||
* another test return True
|
||||
*
|
||||
*/
|
||||
static boolean checkUnexpectedWakeup(Set<SelectionKey> selectedKeys) {
|
||||
System.out.format("Received %d keys%n", selectedKeys.size());
|
||||
|
||||
for (SelectionKey key : selectedKeys) {
|
||||
if (!key.isValid() || !key.isReadable()) {
|
||||
System.out.println("Invalid or unreadable key: " + key);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
System.out.println("Attempting to read datagram from key: " + key);
|
||||
DatagramChannel datagramChannel = (DatagramChannel) key.channel();
|
||||
ByteBuffer buf = ByteBuffer.allocate(100);
|
||||
SocketAddress sa = datagramChannel.receive(buf);
|
||||
|
||||
if (sa != null) {
|
||||
buf.flip();
|
||||
byte[] bytes = new byte[buf.remaining()];
|
||||
buf.get(bytes);
|
||||
String message = new String(bytes);
|
||||
System.out.format("received %s at %s from %s%n", message, datagramChannel.getLocalAddress(), sa);
|
||||
|
||||
// If any received data contains the message from sendDatagram then return false
|
||||
if (message.contains(GREETINGS_MESSAGE)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException io) {
|
||||
System.out.println("Unable to read from datagram " + io);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user