1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty.resolver.dns;
18
19 import io.netty.util.internal.PlatformDependent;
20 import io.netty.util.internal.ThreadLocalRandom;
21 import io.netty.util.internal.logging.InternalLogger;
22 import io.netty.util.internal.logging.InternalLoggerFactory;
23
24 import java.lang.reflect.Method;
25 import java.net.InetAddress;
26 import java.net.InetSocketAddress;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.NoSuchElementException;
33 import java.util.Random;
34 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
35
36
37
38
39
40
41 @SuppressWarnings("IteratorNextCanNotThrowNoSuchElementException")
42 public final class DnsServerAddresses {
43
44 private static final InternalLogger logger = InternalLoggerFactory.getInstance(DnsServerAddresses.class);
45
46 private static final List<InetSocketAddress> DEFAULT_NAME_SERVER_LIST;
47 private static final InetSocketAddress[] DEFAULT_NAME_SERVER_ARRAY;
48
49 static {
50 final int DNS_PORT = 53;
51 final List<InetSocketAddress> defaultNameServers = new ArrayList<InetSocketAddress>(2);
52 try {
53 Class<?> configClass = Class.forName("sun.net.dns.ResolverConfiguration");
54 Method open = configClass.getMethod("open");
55 Method nameservers = configClass.getMethod("nameservers");
56 Object instance = open.invoke(null);
57
58 @SuppressWarnings("unchecked")
59 final List<String> list = (List<String>) nameservers.invoke(instance);
60 final int size = list.size();
61 for (int i = 0; i < size; i ++) {
62 String dnsAddr = list.get(i);
63 if (dnsAddr != null) {
64 defaultNameServers.add(new InetSocketAddress(InetAddress.getByName(dnsAddr), DNS_PORT));
65 }
66 }
67 } catch (Exception ignore) {
68
69
70 }
71
72 if (!defaultNameServers.isEmpty()) {
73 if (logger.isDebugEnabled()) {
74 logger.debug(
75 "Default DNS servers: {} (sun.net.dns.ResolverConfiguration)", defaultNameServers);
76 }
77 } else {
78 Collections.addAll(
79 defaultNameServers,
80 new InetSocketAddress("8.8.8.8", DNS_PORT),
81 new InetSocketAddress("8.8.4.4", DNS_PORT));
82
83 if (logger.isWarnEnabled()) {
84 logger.warn(
85 "Default DNS servers: {} (Google Public DNS as a fallback)", defaultNameServers);
86 }
87 }
88
89 DEFAULT_NAME_SERVER_LIST = Collections.unmodifiableList(defaultNameServers);
90 DEFAULT_NAME_SERVER_ARRAY = defaultNameServers.toArray(new InetSocketAddress[defaultNameServers.size()]);
91 }
92
93
94
95
96
97
98
99
100
101
102 public static List<InetSocketAddress> defaultAddresses() {
103 return DEFAULT_NAME_SERVER_LIST;
104 }
105
106
107
108
109
110 public static Iterable<InetSocketAddress> sequential(Iterable<? extends InetSocketAddress> addresses) {
111 return sequential0(sanitize(addresses));
112 }
113
114
115
116
117
118 public static Iterable<InetSocketAddress> sequential(InetSocketAddress... addresses) {
119 return sequential0(sanitize(addresses));
120 }
121
122 private static Iterable<InetSocketAddress> sequential0(final InetSocketAddress[] addresses) {
123 return new Iterable<InetSocketAddress>() {
124 @Override
125 public Iterator<InetSocketAddress> iterator() {
126 return new SequentialAddressIterator(addresses, 0);
127 }
128 };
129 }
130
131
132
133
134
135 public static Iterable<InetSocketAddress> shuffled(Iterable<? extends InetSocketAddress> addresses) {
136 return shuffled0(sanitize(addresses));
137 }
138
139
140
141
142
143 public static Iterable<InetSocketAddress> shuffled(InetSocketAddress... addresses) {
144 return shuffled0(sanitize(addresses));
145 }
146
147 private static Iterable<InetSocketAddress> shuffled0(final InetSocketAddress[] addresses) {
148 if (addresses.length == 1) {
149 return singleton(addresses[0]);
150 }
151
152 return new Iterable<InetSocketAddress>() {
153 @Override
154 public Iterator<InetSocketAddress> iterator() {
155 return new ShuffledAddressIterator(addresses);
156 }
157 };
158 }
159
160
161
162
163
164
165
166
167 public static Iterable<InetSocketAddress> rotational(Iterable<? extends InetSocketAddress> addresses) {
168 return rotational0(sanitize(addresses));
169 }
170
171
172
173
174
175
176
177
178 public static Iterable<InetSocketAddress> rotational(InetSocketAddress... addresses) {
179 return rotational0(sanitize(addresses));
180 }
181
182 private static Iterable<InetSocketAddress> rotational0(final InetSocketAddress[] addresses) {
183 return new RotationalAddresses(addresses);
184 }
185
186
187
188
189
190 public static Iterable<InetSocketAddress> singleton(final InetSocketAddress address) {
191 if (address == null) {
192 throw new NullPointerException("address");
193 }
194 if (address.isUnresolved()) {
195 throw new IllegalArgumentException("cannot use an unresolved DNS server address: " + address);
196 }
197
198 return new Iterable<InetSocketAddress>() {
199
200 private final Iterator<InetSocketAddress> iterator = new Iterator<InetSocketAddress>() {
201 @Override
202 public boolean hasNext() {
203 return true;
204 }
205
206 @Override
207 public InetSocketAddress next() {
208 return address;
209 }
210
211 @Override
212 public void remove() {
213 throw new UnsupportedOperationException();
214 }
215 };
216
217 @Override
218 public Iterator<InetSocketAddress> iterator() {
219 return iterator;
220 }
221 };
222 }
223
224 private static InetSocketAddress[] sanitize(Iterable<? extends InetSocketAddress> addresses) {
225 if (addresses == null) {
226 throw new NullPointerException("addresses");
227 }
228
229 final List<InetSocketAddress> list;
230 if (addresses instanceof Collection) {
231 list = new ArrayList<InetSocketAddress>(((Collection<?>) addresses).size());
232 } else {
233 list = new ArrayList<InetSocketAddress>(4);
234 }
235
236 for (InetSocketAddress a : addresses) {
237 if (a == null) {
238 break;
239 }
240 if (a.isUnresolved()) {
241 throw new IllegalArgumentException("cannot use an unresolved DNS server address: " + a);
242 }
243 list.add(a);
244 }
245
246 if (list.isEmpty()) {
247 return DEFAULT_NAME_SERVER_ARRAY;
248 }
249
250 return list.toArray(new InetSocketAddress[list.size()]);
251 }
252
253 private static InetSocketAddress[] sanitize(InetSocketAddress[] addresses) {
254 if (addresses == null) {
255 throw new NullPointerException("addresses");
256 }
257
258 List<InetSocketAddress> list = new ArrayList<InetSocketAddress>(addresses.length);
259 for (InetSocketAddress a: addresses) {
260 if (a == null) {
261 break;
262 }
263 if (a.isUnresolved()) {
264 throw new IllegalArgumentException("cannot use an unresolved DNS server address: " + a);
265 }
266 list.add(a);
267 }
268
269 if (list.isEmpty()) {
270 return DEFAULT_NAME_SERVER_ARRAY;
271 }
272
273 return list.toArray(new InetSocketAddress[list.size()]);
274 }
275
276 private DnsServerAddresses() { }
277
278 private static final class SequentialAddressIterator implements Iterator<InetSocketAddress> {
279
280 private final InetSocketAddress[] addresses;
281 private int i;
282
283 SequentialAddressIterator(InetSocketAddress[] addresses, int startIdx) {
284 this.addresses = addresses;
285 i = startIdx;
286 }
287
288 @Override
289 public boolean hasNext() {
290 return true;
291 }
292
293 @Override
294 public InetSocketAddress next() {
295 int i = this.i;
296 InetSocketAddress next = addresses[i];
297 if (++ i < addresses.length) {
298 this.i = i;
299 } else {
300 this.i = 0;
301 }
302 return next;
303 }
304
305 @Override
306 public void remove() {
307 throw new UnsupportedOperationException();
308 }
309 }
310
311 private static final class ShuffledAddressIterator implements Iterator<InetSocketAddress> {
312
313 private final InetSocketAddress[] addresses;
314 private int i;
315
316 ShuffledAddressIterator(InetSocketAddress[] addresses) {
317 this.addresses = addresses.clone();
318
319 shuffle();
320 }
321
322 private void shuffle() {
323 final InetSocketAddress[] addresses = this.addresses;
324 final Random r = ThreadLocalRandom.current();
325
326 for (int i = addresses.length - 1; i >= 0; i --) {
327 InetSocketAddress tmp = addresses[i];
328 int j = r.nextInt(i + 1);
329 addresses[i] = addresses[j];
330 addresses[j] = tmp;
331 }
332 }
333
334 @Override
335 public boolean hasNext() {
336 return true;
337 }
338
339 @Override
340 public InetSocketAddress next() {
341 int i = this.i;
342 InetSocketAddress next = addresses[i];
343 if (++ i < addresses.length) {
344 this.i = i;
345 } else {
346 this.i = 0;
347 shuffle();
348 }
349 return next;
350 }
351
352 @Override
353 public void remove() {
354 throw new UnsupportedOperationException();
355 }
356 }
357
358 private static final class RotationalAddresses implements Iterable<InetSocketAddress> {
359
360 private static final AtomicIntegerFieldUpdater<RotationalAddresses> startIdxUpdater;
361
362 static {
363 AtomicIntegerFieldUpdater<RotationalAddresses> updater =
364 PlatformDependent.newAtomicIntegerFieldUpdater(RotationalAddresses.class, "startIdx");
365
366 if (updater == null) {
367 updater = AtomicIntegerFieldUpdater.newUpdater(RotationalAddresses.class, "startIdx");
368 }
369
370 startIdxUpdater = updater;
371 }
372
373 private final InetSocketAddress[] addresses;
374 @SuppressWarnings("UnusedDeclaration")
375 private volatile int startIdx;
376
377 RotationalAddresses(InetSocketAddress[] addresses) {
378 this.addresses = addresses;
379 }
380
381 @Override
382 public Iterator<InetSocketAddress> iterator() {
383 for (;;) {
384 int curStartIdx = startIdx;
385 int nextStartIdx = curStartIdx + 1;
386 if (nextStartIdx >= addresses.length) {
387 nextStartIdx = 0;
388 }
389 if (startIdxUpdater.compareAndSet(this, curStartIdx, nextStartIdx)) {
390 return new SequentialAddressIterator(addresses, curStartIdx);
391 }
392 }
393 }
394 }
395 }