Skip to content

Commit

Permalink
[CORE] Make network interface iteration order consistent
Browse files Browse the repository at this point in the history
Today the iteration order of the interfaces might change across JVMs
this commit cleans up the NetworkUtils class and attempts to ensure
consistent iteration order across JVMs.
  • Loading branch information
s1monw committed Aug 28, 2014
1 parent c93e6e3 commit cc37ae1
Showing 1 changed file with 42 additions and 36 deletions.
78 changes: 42 additions & 36 deletions src/main/java/org/elasticsearch/common/network/NetworkUtils.java
Expand Up @@ -20,6 +20,7 @@
package org.elasticsearch.common.network;

import com.google.common.collect.Lists;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.CollectionUtil;
import org.elasticsearch.ElasticsearchIllegalStateException;
import org.elasticsearch.common.logging.ESLogger;
Expand Down Expand Up @@ -119,35 +120,8 @@ public static boolean canBindToMcastAddress() {
* @param ip_version Constraint on IP version of address to be returned, 4 or 6
*/
public static InetAddress getFirstNonLoopbackAddress(StackType ip_version) throws SocketException {
InetAddress address = null;

Enumeration intfs = NetworkInterface.getNetworkInterfaces();

List<NetworkInterface> intfsList = Lists.newArrayList();
while (intfs.hasMoreElements()) {
intfsList.add((NetworkInterface) intfs.nextElement());
}

// order by index, assuming first ones are more interesting
try {
final Method getIndexMethod = NetworkInterface.class.getDeclaredMethod("getIndex");
getIndexMethod.setAccessible(true);

CollectionUtil.timSort(intfsList, new Comparator<NetworkInterface>() {
@Override
public int compare(NetworkInterface o1, NetworkInterface o2) {
try {
return ((Integer) getIndexMethod.invoke(o1)).intValue() - ((Integer) getIndexMethod.invoke(o2)).intValue();
} catch (Exception e) {
throw new ElasticsearchIllegalStateException("failed to fetch index of network interface");
}
}
});
} catch (Exception e) {
// ignore
}

for (NetworkInterface intf : intfsList) {
InetAddress address;
for (NetworkInterface intf : getInterfaces()) {
try {
if (!intf.isUp() || intf.isLoopback())
continue;
Expand All @@ -164,6 +138,28 @@ public int compare(NetworkInterface o1, NetworkInterface o2) {
return null;
}

private static List<NetworkInterface> getInterfaces() throws SocketException {
Enumeration intfs = NetworkInterface.getNetworkInterfaces();

List<NetworkInterface> intfsList = Lists.newArrayList();
while (intfs.hasMoreElements()) {
intfsList.add((NetworkInterface) intfs.nextElement());
}

This comment has been minimized.

Copy link
@jpountz

jpountz Aug 28, 2014

Contributor

FYI you could have used Collections.list(intfs) instead to avoid dealing with this crappy Enumeration interface :)

This comment has been minimized.

Copy link
@s1monw

s1monw Aug 28, 2014

Author Contributor

good call I will do another round of refactoring soong


sortInterfaces(intfsList);
return intfsList;
}

private static void sortInterfaces(List<NetworkInterface> intfsList) {
// order by index, assuming first ones are more interesting
CollectionUtil.timSort(intfsList, new Comparator<NetworkInterface>() {
@Override
public int compare(NetworkInterface o1, NetworkInterface o2) {
return Integer.compare (o1.getIndex(), o2.getIndex());
}
});
}


/**
* Returns the first non-loopback address on the given interface on the current host.
Expand Down Expand Up @@ -291,19 +287,29 @@ public static List<NetworkInterface> getAllAvailableInterfaces() throws SocketEx
}
}
}
sortInterfaces(allInterfaces);
return allInterfaces;
}

public static Collection<InetAddress> getAllAvailableAddresses() {
Set<InetAddress> retval = new HashSet<>();
Enumeration en;
// we want consistent order here.
final Set<InetAddress> retval = new TreeSet<>(new Comparator<InetAddress>() {
BytesRef left = new BytesRef();
BytesRef right = new BytesRef();
@Override
public int compare(InetAddress o1, InetAddress o2) {
return set(left, o1).compareTo(set(right, o1));
}

private BytesRef set(BytesRef ref, InetAddress addr) {
ref.bytes = addr.getAddress();
ref.offset = 0;
ref.length = ref.bytes.length;
return ref;
}
});
try {
en = NetworkInterface.getNetworkInterfaces();
if (en == null)
return retval;
while (en.hasMoreElements()) {
NetworkInterface intf = (NetworkInterface) en.nextElement();
for (NetworkInterface intf : getInterfaces()) {
Enumeration<InetAddress> addrs = intf.getInetAddresses();
while (addrs.hasMoreElements())
retval.add(addrs.nextElement());
Expand Down

0 comments on commit cc37ae1

Please sign in to comment.