Skip to content

Commit fdabd37

Browse files
DarraghClarkeAlekseiEfimov
authored andcommitted
8293696: java/nio/channels/DatagramChannel/SelectWhenRefused.java fails with "Unexpected wakeup"
Reviewed-by: dfuchs, msheppar
1 parent 4a30081 commit fdabd37

File tree

1 file changed

+177
-28
lines changed

1 file changed

+177
-28
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,16 +25,25 @@
2525
* @bug 6935563 7044870
2626
* @summary Test that Selector does not select an unconnected DatagramChannel when
2727
* ICMP port unreachable received
28+
* @run junit/othervm SelectWhenRefused
2829
*/
2930

3031
import java.nio.ByteBuffer;
3132
import java.nio.channels.*;
3233
import java.net.*;
3334
import java.io.IOException;
35+
import java.util.Set;
36+
37+
import org.junit.jupiter.api.Test;
38+
39+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
3440

3541
public class SelectWhenRefused {
42+
static final int MAX_TRIES = 3;
43+
static final String GREETINGS_MESSAGE = "Greetings from SelectWhenRefused!";
3644

37-
public static void main(String[] args) throws IOException {
45+
@Test
46+
public void test() throws IOException {
3847
DatagramChannel dc1 = DatagramChannel.open().bind(new InetSocketAddress(0));
3948
int port = dc1.socket().getLocalPort();
4049

@@ -50,53 +59,193 @@ public static void main(String[] args) throws IOException {
5059
dc.register(sel, SelectionKey.OP_READ);
5160

5261
/* Test 1: not connected so ICMP port unreachable should not be received */
53-
sendDatagram(dc, refuser);
54-
int n = sel.select(2000);
55-
if (n > 0) {
56-
sel.selectedKeys().clear();
57-
// BindException will be thrown if another service is using
58-
// our expected refuser port, cannot run just exit.
59-
DatagramChannel.open().bind(refuser).close();
60-
throw new RuntimeException("Unexpected wakeup");
62+
for (int i = 1; i <= MAX_TRIES; i++) {
63+
if (testNoPUEBeforeConnection(dc, refuser, sel, i)) {
64+
break; // test succeeded
65+
}
66+
assertNotEquals(i, MAX_TRIES, "testNoPUEBeforeConnection: too many retries");
6167
}
6268

6369
/* Test 2: connected so ICMP port unreachable may be received */
6470
dc.connect(refuser);
6571
try {
66-
sendDatagram(dc, refuser);
67-
n = sel.select(2000);
68-
if (n > 0) {
69-
sel.selectedKeys().clear();
70-
try {
71-
n = dc.read(ByteBuffer.allocate(100));
72-
throw new RuntimeException("Unexpected datagram received");
73-
} catch (PortUnreachableException pue) {
74-
// expected
72+
for (int i = 1; i <= MAX_TRIES; i++) {
73+
if (testPUEOnConnect(dc, refuser, sel, i)) {
74+
break; // test passed
7575
}
76+
assertNotEquals(i, MAX_TRIES, "testPUEOnConnect: too many retries");
7677
}
7778
} finally {
7879
dc.disconnect();
7980
}
8081

8182
/* Test 3: not connected so ICMP port unreachable should not be received */
82-
sendDatagram(dc, refuser);
83-
n = sel.select(2000);
84-
if (n > 0) {
85-
throw new RuntimeException("Unexpected wakeup after disconnect");
83+
for (int i = 1; i <= MAX_TRIES; i++) {
84+
if (testNoPUEAfterDisconnect(dc, refuser, sel, i)) {
85+
break; // test passed
86+
}
87+
assertNotEquals(i, MAX_TRIES, "testNoPUEAfterDisconnect: too many retries");
8688
}
87-
88-
} catch(BindException e) {
89+
} catch (BindException e) {
8990
// Do nothing, some other test has used this port
91+
System.out.println("Skipping test: refuser port has been reused: " + e);
9092
} finally {
9193
sel.close();
9294
dc.close();
9395
}
9496
}
9597

98+
/*
99+
* Send a datagram to non existent unconnected UDP end point
100+
* This shouldn't result in an PortUnreachableException
101+
* Handle unexpected read events on the senders DC with
102+
* retry when message received is external and Throw Exception
103+
* on receipt of own message
104+
*/
105+
static boolean testNoPUEBeforeConnection(DatagramChannel dc,
106+
SocketAddress refuser,
107+
Selector sel,
108+
int retryCount) throws IOException {
109+
sendDatagram(dc, refuser);
110+
int n = sel.select(2000);
111+
if (n > 0) {
112+
boolean mayRetry = checkUnexpectedWakeup(sel.selectedKeys());
113+
boolean tooManyRetries = retryCount >= MAX_TRIES;
114+
sel.selectedKeys().clear();
115+
116+
if (mayRetry && !tooManyRetries) {
117+
return false; // will retry
118+
}
119+
120+
// BindException will be thrown if another service is using
121+
// our expected refuser port, cannot run just exit.
122+
DatagramChannel.open().bind(refuser).close();
123+
throw new RuntimeException("Unexpected wakeup");
124+
}
125+
return true; // test passed
126+
}
127+
128+
/*
129+
* Send a datagram to a connected UDP end point
130+
* This should result in an PortUnreachableException
131+
* Handle unexpected read events on the senders DC with
132+
* retry when message received is external and Throw Exception
133+
* on receipt of own message
134+
*/
135+
static boolean testPUEOnConnect(DatagramChannel dc,
136+
SocketAddress refuser,
137+
Selector sel,
138+
int retryCount) throws IOException {
139+
sendDatagram(dc, refuser);
140+
int n = sel.select(2000);
141+
if (n > 0) {
142+
sel.selectedKeys().clear();
143+
144+
try {
145+
// Attempt to read from Selected Key
146+
ByteBuffer buf = ByteBuffer.allocate(100);
147+
SocketAddress sa = dc.receive(buf);
148+
149+
if (sa != null) {
150+
buf.flip();
151+
byte[] bytes = new byte[buf.remaining()];
152+
buf.get(bytes);
153+
String message = new String(bytes);
154+
System.out.format("received %s at %s from %s%n", message, dc.getLocalAddress(), sa);
155+
156+
// If any received data contains the message from sendDatagram then throw exception
157+
if (message.contains(GREETINGS_MESSAGE)) {
158+
throw new RuntimeException("Unexpected datagram received");
159+
}
160+
}
161+
162+
boolean mayRetry = retryCount < MAX_TRIES;
163+
if (mayRetry) {
164+
return false; // will retry
165+
}
166+
167+
// BindException will be thrown if another service is using
168+
// our expected refuser port, cannot run just exit.
169+
DatagramChannel.open().bind(refuser).close();
170+
throw new RuntimeException("PortUnreachableException not raised");
171+
} catch (PortUnreachableException pue) {
172+
System.out.println("Got expected PortUnreachableException " + pue);
173+
}
174+
}
175+
return true; // test passed
176+
}
177+
178+
/*
179+
* Send a datagram to a disconnected UDP end point
180+
* This should result in an PortUnreachableException
181+
* Handle unexpected read events on the senders DC with
182+
* retry when message received is external and Throw Exception
183+
* on receipt of own message
184+
*/
185+
static boolean testNoPUEAfterDisconnect(DatagramChannel dc,
186+
SocketAddress refuser,
187+
Selector sel,
188+
int retryCount) throws IOException {
189+
sendDatagram(dc, refuser);
190+
int n = sel.select(2000);
191+
if (n > 0) {
192+
boolean mayRetry = checkUnexpectedWakeup(sel.selectedKeys());
193+
boolean tooManyRetries = retryCount >= MAX_TRIES;
194+
sel.selectedKeys().clear();
195+
196+
if (mayRetry && !tooManyRetries) {
197+
return false; // will retry
198+
}
199+
200+
throw new RuntimeException("Unexpected wakeup after disconnect");
201+
}
202+
return true; // test passed
203+
}
204+
96205
static void sendDatagram(DatagramChannel dc, SocketAddress remote)
97-
throws IOException
98-
{
99-
ByteBuffer bb = ByteBuffer.wrap("Greetings!".getBytes());
206+
throws IOException {
207+
ByteBuffer bb = ByteBuffer.wrap(GREETINGS_MESSAGE.getBytes());
100208
dc.send(bb, remote);
101209
}
210+
211+
/*
212+
* Attempt to read and Log the data from SelectedKeys,
213+
* If a message can be received, and it came from
214+
* another test return True
215+
*
216+
*/
217+
static boolean checkUnexpectedWakeup(Set<SelectionKey> selectedKeys) {
218+
System.out.format("Received %d keys%n", selectedKeys.size());
219+
220+
for (SelectionKey key : selectedKeys) {
221+
if (!key.isValid() || !key.isReadable()) {
222+
System.out.println("Invalid or unreadable key: " + key);
223+
continue;
224+
}
225+
226+
try {
227+
System.out.println("Attempting to read datagram from key: " + key);
228+
DatagramChannel datagramChannel = (DatagramChannel) key.channel();
229+
ByteBuffer buf = ByteBuffer.allocate(100);
230+
SocketAddress sa = datagramChannel.receive(buf);
231+
232+
if (sa != null) {
233+
buf.flip();
234+
byte[] bytes = new byte[buf.remaining()];
235+
buf.get(bytes);
236+
String message = new String(bytes);
237+
System.out.format("received %s at %s from %s%n", message, datagramChannel.getLocalAddress(), sa);
238+
239+
// If any received data contains the message from sendDatagram then return false
240+
if (message.contains(GREETINGS_MESSAGE)) {
241+
return false;
242+
}
243+
}
244+
245+
} catch (IOException io) {
246+
System.out.println("Unable to read from datagram " + io);
247+
}
248+
}
249+
return true;
250+
}
102251
}

0 commit comments

Comments
 (0)