1
1
/*
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.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
25
25
* @bug 6935563 7044870
26
26
* @summary Test that Selector does not select an unconnected DatagramChannel when
27
27
* ICMP port unreachable received
28
+ * @run junit/othervm SelectWhenRefused
28
29
*/
29
30
30
31
import java .nio .ByteBuffer ;
31
32
import java .nio .channels .*;
32
33
import java .net .*;
33
34
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 ;
34
40
35
41
public class SelectWhenRefused {
42
+ static final int MAX_TRIES = 3 ;
43
+ static final String GREETINGS_MESSAGE = "Greetings from SelectWhenRefused!" ;
36
44
37
- public static void main (String [] args ) throws IOException {
45
+ @ Test
46
+ public void test () throws IOException {
38
47
DatagramChannel dc1 = DatagramChannel .open ().bind (new InetSocketAddress (0 ));
39
48
int port = dc1 .socket ().getLocalPort ();
40
49
@@ -50,53 +59,193 @@ public static void main(String[] args) throws IOException {
50
59
dc .register (sel , SelectionKey .OP_READ );
51
60
52
61
/* 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" );
61
67
}
62
68
63
69
/* Test 2: connected so ICMP port unreachable may be received */
64
70
dc .connect (refuser );
65
71
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
75
75
}
76
+ assertNotEquals (i , MAX_TRIES , "testPUEOnConnect: too many retries" );
76
77
}
77
78
} finally {
78
79
dc .disconnect ();
79
80
}
80
81
81
82
/* 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" );
86
88
}
87
-
88
- } catch (BindException e ) {
89
+ } catch (BindException e ) {
89
90
// Do nothing, some other test has used this port
91
+ System .out .println ("Skipping test: refuser port has been reused: " + e );
90
92
} finally {
91
93
sel .close ();
92
94
dc .close ();
93
95
}
94
96
}
95
97
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
+
96
205
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 ());
100
208
dc .send (bb , remote );
101
209
}
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
+ }
102
251
}
0 commit comments