All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.netty.resolver.dns.DnsServerAddresses Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package io.netty.resolver.dns;

import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.ThreadLocalRandom;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

/**
 * Provides a sequence of DNS server addresses to {@link DnsNameResolver}.  The {@link Iterator} created by the
 * {@link Iterable}s returned by the factory methods of this class is infinite, which means {@link Iterator#hasNext()}
 * will never return {@code false} and {@link Iterator#next()} will never raise a {@link NoSuchElementException}.
 */
@SuppressWarnings("IteratorNextCanNotThrowNoSuchElementException")
public final class DnsServerAddresses {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(DnsServerAddresses.class);

    private static final List DEFAULT_NAME_SERVER_LIST;
    private static final InetSocketAddress[] DEFAULT_NAME_SERVER_ARRAY;

    static {
        final int DNS_PORT = 53;
        final List defaultNameServers = new ArrayList(2);
        try {
            Class configClass = Class.forName("sun.net.dns.ResolverConfiguration");
            Method open = configClass.getMethod("open");
            Method nameservers = configClass.getMethod("nameservers");
            Object instance = open.invoke(null);

            @SuppressWarnings("unchecked")
            final List list = (List) nameservers.invoke(instance);
            final int size = list.size();
            for (int i = 0; i < size; i ++) {
                String dnsAddr = list.get(i);
                if (dnsAddr != null) {
                    defaultNameServers.add(new InetSocketAddress(InetAddress.getByName(dnsAddr), DNS_PORT));
                }
            }
        } catch (Exception ignore) {
            // Failed to get the system name server list.
            // Will add the default name servers afterwards.
        }

        if (!defaultNameServers.isEmpty()) {
            if (logger.isDebugEnabled()) {
                logger.debug(
                        "Default DNS servers: {} (sun.net.dns.ResolverConfiguration)", defaultNameServers);
            }
        } else {
            Collections.addAll(
                    defaultNameServers,
                    new InetSocketAddress("8.8.8.8", DNS_PORT),
                    new InetSocketAddress("8.8.4.4", DNS_PORT));

            if (logger.isWarnEnabled()) {
                logger.warn(
                        "Default DNS servers: {} (Google Public DNS as a fallback)", defaultNameServers);
            }
        }

        DEFAULT_NAME_SERVER_LIST = Collections.unmodifiableList(defaultNameServers);
        DEFAULT_NAME_SERVER_ARRAY = defaultNameServers.toArray(new InetSocketAddress[defaultNameServers.size()]);
    }

    /**
     * Returns the list of the system DNS server addresses.  If it failed to retrieve the list of the system DNS server
     * addresses from the environment, it will return {@code "8.8.8.8"} and {@code "8.8.4.4"}, the addresses of the
     * Google public DNS servers.  Note that the {@code Iterator} of the returned list is not infinite unlike other
     * factory methods in this class.  To make the returned list infinite, pass it to the other factory method. e.g.
     * 
     * addresses = {@link #sequential(Iterable) sequential}({@link #defaultAddresses()});
     * 
*/ public static List defaultAddresses() { return DEFAULT_NAME_SERVER_LIST; } /** * Returns an infinite {@link Iterable} of the specified DNS server addresses, whose {@link Iterator} iterates * the DNS server addresses in a sequential order. */ public static Iterable sequential(Iterable addresses) { return sequential0(sanitize(addresses)); } /** * Returns an infinite {@link Iterable} of the specified DNS server addresses, whose {@link Iterator} iterates * the DNS server addresses in a sequential order. */ public static Iterable sequential(InetSocketAddress... addresses) { return sequential0(sanitize(addresses)); } private static Iterable sequential0(final InetSocketAddress[] addresses) { return new Iterable() { @Override public Iterator iterator() { return new SequentialAddressIterator(addresses, 0); } }; } /** * Returns an infinite {@link Iterable} of the specified DNS server addresses, whose {@link Iterator} iterates * the DNS server addresses in a shuffled order. */ public static Iterable shuffled(Iterable addresses) { return shuffled0(sanitize(addresses)); } /** * Returns an infinite {@link Iterable} of the specified DNS server addresses, whose {@link Iterator} iterates * the DNS server addresses in a shuffled order. */ public static Iterable shuffled(InetSocketAddress... addresses) { return shuffled0(sanitize(addresses)); } private static Iterable shuffled0(final InetSocketAddress[] addresses) { if (addresses.length == 1) { return singleton(addresses[0]); } return new Iterable() { @Override public Iterator iterator() { return new ShuffledAddressIterator(addresses); } }; } /** * Returns an infinite {@link Iterable} of the specified DNS server addresses, whose {@link Iterator} iterates * the DNS server addresses in a rotational order. It is similar to {@link #sequential(Iterable)}, but each * {@link Iterator} starts from a different starting point. For example, the first {@link Iterable#iterator()} * will iterate from the first DNS server address, the second one will iterate from the second DNS server address, * and so on. */ public static Iterable rotational(Iterable addresses) { return rotational0(sanitize(addresses)); } /** * Returns an infinite {@link Iterable} of the specified DNS server addresses, whose {@link Iterator} iterates * the DNS server addresses in a rotational order. It is similar to {@link #sequential(Iterable)}, but each * {@link Iterator} starts from a different starting point. For example, the first {@link Iterable#iterator()} * will iterate from the first DNS server address, the second one will iterate from the second DNS server address, * and so on. */ public static Iterable rotational(InetSocketAddress... addresses) { return rotational0(sanitize(addresses)); } private static Iterable rotational0(final InetSocketAddress[] addresses) { return new RotationalAddresses(addresses); } /** * Returns an infinite {@link Iterable} of the specified DNS server address, whose {@link Iterator} always * return the same DNS server address. */ public static Iterable singleton(final InetSocketAddress address) { if (address == null) { throw new NullPointerException("address"); } if (address.isUnresolved()) { throw new IllegalArgumentException("cannot use an unresolved DNS server address: " + address); } return new Iterable() { private final Iterator iterator = new Iterator() { @Override public boolean hasNext() { return true; } @Override public InetSocketAddress next() { return address; } @Override public void remove() { throw new UnsupportedOperationException(); } }; @Override public Iterator iterator() { return iterator; } }; } private static InetSocketAddress[] sanitize(Iterable addresses) { if (addresses == null) { throw new NullPointerException("addresses"); } final List list; if (addresses instanceof Collection) { list = new ArrayList(((Collection) addresses).size()); } else { list = new ArrayList(4); } for (InetSocketAddress a : addresses) { if (a == null) { break; } if (a.isUnresolved()) { throw new IllegalArgumentException("cannot use an unresolved DNS server address: " + a); } list.add(a); } if (list.isEmpty()) { return DEFAULT_NAME_SERVER_ARRAY; } return list.toArray(new InetSocketAddress[list.size()]); } private static InetSocketAddress[] sanitize(InetSocketAddress[] addresses) { if (addresses == null) { throw new NullPointerException("addresses"); } List list = new ArrayList(addresses.length); for (InetSocketAddress a: addresses) { if (a == null) { break; } if (a.isUnresolved()) { throw new IllegalArgumentException("cannot use an unresolved DNS server address: " + a); } list.add(a); } if (list.isEmpty()) { return DEFAULT_NAME_SERVER_ARRAY; } return list.toArray(new InetSocketAddress[list.size()]); } private DnsServerAddresses() { } private static final class SequentialAddressIterator implements Iterator { private final InetSocketAddress[] addresses; private int i; SequentialAddressIterator(InetSocketAddress[] addresses, int startIdx) { this.addresses = addresses; i = startIdx; } @Override public boolean hasNext() { return true; } @Override public InetSocketAddress next() { int i = this.i; InetSocketAddress next = addresses[i]; if (++ i < addresses.length) { this.i = i; } else { this.i = 0; } return next; } @Override public void remove() { throw new UnsupportedOperationException(); } } private static final class ShuffledAddressIterator implements Iterator { private final InetSocketAddress[] addresses; private int i; ShuffledAddressIterator(InetSocketAddress[] addresses) { this.addresses = addresses.clone(); shuffle(); } private void shuffle() { final InetSocketAddress[] addresses = this.addresses; final Random r = ThreadLocalRandom.current(); for (int i = addresses.length - 1; i >= 0; i --) { InetSocketAddress tmp = addresses[i]; int j = r.nextInt(i + 1); addresses[i] = addresses[j]; addresses[j] = tmp; } } @Override public boolean hasNext() { return true; } @Override public InetSocketAddress next() { int i = this.i; InetSocketAddress next = addresses[i]; if (++ i < addresses.length) { this.i = i; } else { this.i = 0; shuffle(); } return next; } @Override public void remove() { throw new UnsupportedOperationException(); } } private static final class RotationalAddresses implements Iterable { private static final AtomicIntegerFieldUpdater startIdxUpdater; static { AtomicIntegerFieldUpdater updater = PlatformDependent.newAtomicIntegerFieldUpdater(RotationalAddresses.class, "startIdx"); if (updater == null) { updater = AtomicIntegerFieldUpdater.newUpdater(RotationalAddresses.class, "startIdx"); } startIdxUpdater = updater; } private final InetSocketAddress[] addresses; @SuppressWarnings("UnusedDeclaration") private volatile int startIdx; RotationalAddresses(InetSocketAddress[] addresses) { this.addresses = addresses; } @Override public Iterator iterator() { for (;;) { int curStartIdx = startIdx; int nextStartIdx = curStartIdx + 1; if (nextStartIdx >= addresses.length) { nextStartIdx = 0; } if (startIdxUpdater.compareAndSet(this, curStartIdx, nextStartIdx)) { return new SequentialAddressIterator(addresses, curStartIdx); } } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy