diff --git a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsAddressResolveContext.java b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsAddressResolveContext.java index 85078c6792..a7c780eeac 100644 --- a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsAddressResolveContext.java +++ b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsAddressResolveContext.java @@ -19,7 +19,7 @@ import static io.netty.resolver.dns.DnsAddressDecoder.decodeAddress; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; import io.netty.channel.EventLoop; @@ -56,27 +56,8 @@ final class DnsAddressResolveContext extends DnsResolveContext { @Override List filterResults(List unfiltered) { - final Class inetAddressType = parent.preferredAddressType().addressType(); - final int size = unfiltered.size(); - int numExpected = 0; - for (int i = 0; i < size; i++) { - InetAddress address = unfiltered.get(i); - if (inetAddressType.isInstance(address)) { - numExpected++; - } - } - if (numExpected == size || numExpected == 0) { - // If all the results are the preferred type, or none of them are, then we don't need to do any filtering. - return unfiltered; - } - List filtered = new ArrayList(numExpected); - for (int i = 0; i < size; i++) { - InetAddress address = unfiltered.get(i); - if (inetAddressType.isInstance(address)) { - filtered.add(address); - } - } - return filtered; + Collections.sort(unfiltered, PreferredAddressTypeComparator.comparator(parent.preferredAddressType())); + return unfiltered; } @Override diff --git a/resolver-dns/src/main/java/io/netty/resolver/dns/PreferredAddressTypeComparator.java b/resolver-dns/src/main/java/io/netty/resolver/dns/PreferredAddressTypeComparator.java new file mode 100644 index 0000000000..bcf4dc7aa5 --- /dev/null +++ b/resolver-dns/src/main/java/io/netty/resolver/dns/PreferredAddressTypeComparator.java @@ -0,0 +1,54 @@ +/* + * Copyright 2019 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.channel.socket.InternetProtocolFamily; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.util.Comparator; + +final class PreferredAddressTypeComparator implements Comparator { + + private static final PreferredAddressTypeComparator IPv4 = new PreferredAddressTypeComparator(Inet4Address.class); + private static final PreferredAddressTypeComparator IPv6 = new PreferredAddressTypeComparator(Inet6Address.class); + + static PreferredAddressTypeComparator comparator(InternetProtocolFamily family) { + switch (family) { + case IPv4: + return IPv4; + case IPv6: + return IPv6; + default: + throw new IllegalArgumentException(); + } + } + + private final Class preferredAddressType; + + private PreferredAddressTypeComparator(Class preferredAddressType) { + this.preferredAddressType = preferredAddressType; + } + + @Override + public int compare(InetAddress o1, InetAddress o2) { + if (o1.getClass() == o2.getClass()) { + return 0; + } + return preferredAddressType.isAssignableFrom(o1.getClass()) ? -1 : 1; + } +} diff --git a/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java b/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java index 694667e49c..87458afe4e 100644 --- a/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java +++ b/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java @@ -1233,6 +1233,15 @@ public class DnsNameResolverTest { } else { assertEquals(ipv6Address, resolved.getHostAddress()); } + InetAddress ipv4InetAddress = InetAddress.getByAddress("netty.com", + InetAddress.getByName(ipv4Address).getAddress()); + InetAddress ipv6InetAddress = InetAddress.getByAddress("netty.com", + InetAddress.getByName(ipv6Address).getAddress()); + + List resolvedAll = resolver.resolveAll("netty.com").syncUninterruptibly().getNow(); + List expected = types == ResolvedAddressTypes.IPV4_PREFERRED ? + Arrays.asList(ipv4InetAddress, ipv6InetAddress) : Arrays.asList(ipv6InetAddress, ipv4InetAddress); + assertEquals(expected, resolvedAll); } finally { nonCompliantDnsServer.stop(); } @@ -2611,5 +2620,4 @@ public class DnsNameResolverTest { } } } - } diff --git a/resolver-dns/src/test/java/io/netty/resolver/dns/PreferredAddressTypeComparatorTest.java b/resolver-dns/src/test/java/io/netty/resolver/dns/PreferredAddressTypeComparatorTest.java new file mode 100644 index 0000000000..7dcaba871d --- /dev/null +++ b/resolver-dns/src/test/java/io/netty/resolver/dns/PreferredAddressTypeComparatorTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2019 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.channel.socket.InternetProtocolFamily; +import org.junit.Assert; +import org.junit.Test; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class PreferredAddressTypeComparatorTest { + + @Test + public void testIpv4() throws UnknownHostException { + InetAddress ipv4Address1 = InetAddress.getByName("10.0.0.1"); + InetAddress ipv4Address2 = InetAddress.getByName("10.0.0.2"); + InetAddress ipv4Address3 = InetAddress.getByName("10.0.0.3"); + InetAddress ipv6Address1 = InetAddress.getByName("::1"); + InetAddress ipv6Address2 = InetAddress.getByName("::2"); + InetAddress ipv6Address3 = InetAddress.getByName("::3"); + + PreferredAddressTypeComparator ipv4 = PreferredAddressTypeComparator.comparator(InternetProtocolFamily.IPv4); + + List addressList = new ArrayList(); + Collections.addAll(addressList, ipv4Address1, ipv4Address2, ipv6Address1, + ipv6Address2, ipv4Address3, ipv6Address3); + Collections.sort(addressList, ipv4); + + Assert.assertEquals(Arrays.asList(ipv4Address1, ipv4Address2, ipv4Address3, ipv6Address1, + ipv6Address2, ipv6Address3), addressList); + } + + @Test + public void testIpv6() throws UnknownHostException { + InetAddress ipv4Address1 = InetAddress.getByName("10.0.0.1"); + InetAddress ipv4Address2 = InetAddress.getByName("10.0.0.2"); + InetAddress ipv4Address3 = InetAddress.getByName("10.0.0.3"); + InetAddress ipv6Address1 = InetAddress.getByName("::1"); + InetAddress ipv6Address2 = InetAddress.getByName("::2"); + InetAddress ipv6Address3 = InetAddress.getByName("::3"); + + PreferredAddressTypeComparator ipv4 = PreferredAddressTypeComparator.comparator(InternetProtocolFamily.IPv6); + + List addressList = new ArrayList(); + Collections.addAll(addressList, ipv4Address1, ipv4Address2, ipv6Address1, + ipv6Address2, ipv4Address3, ipv6Address3); + Collections.sort(addressList, ipv4); + + Assert.assertEquals(Arrays.asList(ipv6Address1, + ipv6Address2, ipv6Address3, ipv4Address1, ipv4Address2, ipv4Address3), addressList); + } +}