27
27
import java .io .IOException ;
28
28
import java .net .DatagramSocket ;
29
29
import java .net .ProtocolFamily ;
30
- import java .net .SocketException ;
31
30
import java .net .InetSocketAddress ;
32
31
import java .nio .channels .DatagramChannel ;
33
32
import java .security .AccessController ;
34
33
import java .security .PrivilegedExceptionAction ;
35
34
import java .util .Objects ;
36
35
import java .util .Random ;
37
36
38
- class DNSDatagramSocketFactory {
37
+ class DNSDatagramChannelFactory {
39
38
static final int DEVIATION = 3 ;
40
39
static final int THRESHOLD = 6 ;
41
40
static final int BIT_DEVIATION = 2 ;
@@ -120,17 +119,17 @@ public boolean offer(int port) {
120
119
final Random random ;
121
120
final PortHistory history ;
122
121
123
- DNSDatagramSocketFactory () {
122
+ DNSDatagramChannelFactory () {
124
123
this (new Random ());
125
124
}
126
125
127
- DNSDatagramSocketFactory (Random random ) {
126
+ DNSDatagramChannelFactory (Random random ) {
128
127
this (Objects .requireNonNull (random ), null , DEVIATION , THRESHOLD );
129
128
}
130
- DNSDatagramSocketFactory (Random random ,
131
- ProtocolFamily family ,
132
- int deviation ,
133
- int threshold ) {
129
+ DNSDatagramChannelFactory (Random random ,
130
+ ProtocolFamily family ,
131
+ int deviation ,
132
+ int threshold ) {
134
133
this .random = Objects .requireNonNull (random );
135
134
this .history = new PortHistory (HISTORY , random );
136
135
this .family = family ;
@@ -145,12 +144,13 @@ public boolean offer(int port) {
145
144
* port) then the underlying OS implementation is used. Otherwise, this
146
145
* method will allocate and bind a socket on a randomly selected ephemeral
147
146
* port in the dynamic range.
148
- * @return A new DatagramSocket bound to a random port.
149
- * @throws SocketException if the socket cannot be created.
147
+ *
148
+ * @return A new DatagramChannel bound to a random port.
149
+ * @throws IOException if the socket cannot be created.
150
150
*/
151
- public synchronized DatagramSocket open () throws SocketException {
151
+ public synchronized DatagramChannel open () throws IOException {
152
152
int lastseen = lastport ;
153
- DatagramSocket s ;
153
+ DatagramChannel s ;
154
154
155
155
boolean thresholdCrossed = unsuitablePortCount > thresholdCount ;
156
156
if (thresholdCrossed ) {
@@ -166,7 +166,7 @@ public synchronized DatagramSocket open() throws SocketException {
166
166
167
167
// Allocate an ephemeral port (port 0)
168
168
s = openDefault ();
169
- lastport = s . getLocalPort ();
169
+ lastport = getLocalPort (s );
170
170
if (lastseen == 0 ) {
171
171
lastSystemAllocated = lastport ;
172
172
history .offer (lastport );
@@ -199,36 +199,27 @@ public synchronized DatagramSocket open() throws SocketException {
199
199
// Undecided... the new port was too close. Let's allocate a random
200
200
// port using our own algorithm
201
201
assert !thresholdCrossed ;
202
- DatagramSocket ss = openRandom ();
202
+ DatagramChannel ss = openRandom ();
203
203
if (ss == null ) return s ;
204
204
unsuitablePortCount ++;
205
205
s .close ();
206
206
return ss ;
207
207
}
208
208
209
- private DatagramSocket openDefault () throws SocketException {
210
- if (family != null ) {
211
- try {
212
- DatagramChannel c = DatagramChannel .open (family );
213
- try {
214
- DatagramSocket s = c .socket ();
215
- s .bind (null );
216
- return s ;
217
- } catch (Throwable x ) {
218
- c .close ();
219
- throw x ;
220
- }
221
- } catch (SocketException x ) {
222
- throw x ;
223
- } catch (IOException x ) {
224
- throw new SocketException (x .getMessage (), x );
225
- }
209
+ private DatagramChannel openDefault () throws IOException {
210
+ DatagramChannel c = family != null ? DatagramChannel .open (family )
211
+ : DatagramChannel .open ();
212
+ try {
213
+ c .bind (null );
214
+ return c ;
215
+ } catch (Throwable x ) {
216
+ c .close ();
217
+ throw x ;
226
218
}
227
- return new DatagramSocket ();
228
219
}
229
220
230
221
synchronized boolean isUsingNativePortRandomization () {
231
- return unsuitablePortCount <= thresholdCount
222
+ return unsuitablePortCount <= thresholdCount
232
223
&& suitablePortCount > thresholdCount ;
233
224
}
234
225
@@ -246,7 +237,7 @@ private boolean farEnough(int port) {
246
237
&& Math .abs (port - lastport ) > deviation ;
247
238
}
248
239
249
- private DatagramSocket openRandom () {
240
+ private DatagramChannel openRandom () throws IOException {
250
241
int maxtries = MAX_RANDOM_TRIES ;
251
242
while (maxtries -- > 0 ) {
252
243
int port ;
@@ -265,29 +256,24 @@ private DatagramSocket openRandom() {
265
256
// times - but that should be OK with MAX_RANDOM_TRIES = 5.
266
257
if (!suitable ) continue ;
267
258
259
+ DatagramChannel dc = (family != null )
260
+ ? DatagramChannel .open (family )
261
+ : DatagramChannel .open ();
268
262
try {
269
- if (family != null ) {
270
- DatagramChannel c = DatagramChannel .open (family );
271
- try {
272
- DatagramSocket s = c .socket ();
273
- s .bind (new InetSocketAddress (port ));
274
- lastport = s .getLocalPort ();
275
- if (!recycled ) history .add (port );
276
- return s ;
277
- } catch (Throwable x ) {
278
- c .close ();
279
- throw x ;
280
- }
281
- }
282
- DatagramSocket s = new DatagramSocket (port );
283
- lastport = s .getLocalPort ();
263
+ dc .bind (new InetSocketAddress (port ));
264
+ lastport = getLocalPort (dc );
284
265
if (!recycled ) history .add (port );
285
- return s ;
266
+ return dc ;
286
267
} catch (IOException x ) {
268
+ dc .close ();
287
269
// try again until maxtries == 0;
288
270
}
289
271
}
290
272
return null ;
291
273
}
292
274
275
+ private static int getLocalPort (DatagramChannel dc ) throws IOException {
276
+ return ((InetSocketAddress ) dc .getLocalAddress ()).getPort ();
277
+ }
278
+
293
279
}
0 commit comments