Skip to content

Commit

Permalink
Prefer the NIC with global IP address when getting the default machin…
Browse files Browse the repository at this point in the history
…e ID

Motivation:

When there are two MAC addresses which are good enough, we can choose the one with better IP address rather than just choosing the first appeared one.

Modification:

Replace isBetterAddress() with compareAddresses() to make it return if both addresses are in the same preference level.
Add compareAddresses() which compare InetAddresses and use it when compareAddress(byte[], byte[]) returns 0 (same preference)

Result:

More correct primary MAC address detection
  • Loading branch information
trustin committed Mar 21, 2014
1 parent 3621a01 commit 6cb238a
Showing 1 changed file with 65 additions and 16 deletions.
81 changes: 65 additions & 16 deletions transport/src/main/java/io/netty/channel/DefaultChannelId.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package io.netty.channel;

import io.netty.buffer.ByteBufUtil;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.SystemPropertyUtil;
import io.netty.util.internal.ThreadLocalRandom;
import io.netty.util.internal.logging.InternalLogger;
Expand All @@ -26,10 +27,12 @@
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -125,23 +128,35 @@ private static byte[] defaultMachineId() {
// Find the best MAC address available.
final byte[] NOT_FOUND = { -1 };
byte[] bestMacAddr = NOT_FOUND;
InetAddress bestInetAddr = null;
try {
bestInetAddr = InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 });
} catch (UnknownHostException e) {
// Never happens.
PlatformDependent.throwException(e);
}

// Retrieve the list of available network interfaces.
List<NetworkInterface> ifaces = new ArrayList<NetworkInterface>();
Map<NetworkInterface, InetAddress> ifaces = new LinkedHashMap<NetworkInterface, InetAddress>();
try {
for (Enumeration<NetworkInterface> i = NetworkInterface.getNetworkInterfaces(); i.hasMoreElements();) {
NetworkInterface iface = i.nextElement();
// Use the interface with proper INET addresses only.
Enumeration<InetAddress> addrs = iface.getInetAddresses();
if (addrs.hasMoreElements() && !addrs.nextElement().isLoopbackAddress()) {
ifaces.add(iface);
if (addrs.hasMoreElements()) {
InetAddress a = addrs.nextElement();
if (!a.isLoopbackAddress()) {
ifaces.put(iface, a);
}
}
}
} catch (SocketException e) {
logger.warn("Failed to retrieve the list of available network interfaces", e);
}

for (NetworkInterface iface: ifaces) {
for (Entry<NetworkInterface, InetAddress> entry: ifaces.entrySet()) {
NetworkInterface iface = entry.getKey();
InetAddress inetAddr = entry.getValue();
if (iface.isVirtual()) {
continue;
}
Expand All @@ -154,8 +169,15 @@ private static byte[] defaultMachineId() {
continue;
}

if (isBetterAddress(bestMacAddr, macAddr)) {
int res = compareAddresses(bestMacAddr, macAddr);
if (res < 0) {
bestMacAddr = macAddr;
bestInetAddr = inetAddr;
} else if (res == 0) {
if (compareAddresses(bestInetAddr, inetAddr) < 0) {
bestMacAddr = macAddr;
bestInetAddr = inetAddr;
}
}
}

Expand Down Expand Up @@ -183,14 +205,17 @@ private static byte[] defaultMachineId() {
return bestMacAddr;
}

private static boolean isBetterAddress(byte[] current, byte[] candidate) {
/**
* @return positive - current is better, 0 - cannot tell from MAC addr, negative - candidate is better.
*/
private static int compareAddresses(byte[] current, byte[] candidate) {
if (candidate == null) {
return false;
return 1;
}

// Must be EUI-48 or longer.
if (candidate.length < 6) {
return false;
return 1;
}

// Must not be filled with only 0 and 1.
Expand All @@ -203,30 +228,54 @@ private static boolean isBetterAddress(byte[] current, byte[] candidate) {
}

if (onlyZeroAndOne) {
return false;
return 1;
}

// Must not be a multicast address
if ((candidate[0] & 1) != 0) {
return false;
return 1;
}

// Prefer longer globally unique addresses.
if ((current[0] & 2) == 0) {
if ((candidate[0] & 2) == 0) {
return candidate.length > current.length;
return current.length - candidate.length;
} else {
return false;
return 1;
}
} else {
if ((candidate[0] & 2) == 0) {
return true;
return -1;
} else {
return candidate.length > current.length;
return current.length - candidate.length;
}
}
}

/**
* @return positive - current is better, 0 - cannot tell, negative - candidate is better
*/
private static int compareAddresses(InetAddress current, InetAddress candidate) {
return scoreAddress(current) - scoreAddress(candidate);
}

private static int scoreAddress(InetAddress addr) {
if (addr.isAnyLocalAddress()) {
return 0;
}
if (addr.isMulticastAddress()) {
return 1;
}
if (addr.isLinkLocalAddress()) {
return 2;
}
if (addr.isSiteLocalAddress()) {
return 3;
}

return 4;
}

private static String formatAddress(byte[] addr) {
StringBuilder buf = new StringBuilder(24);
for (byte b: addr) {
Expand Down

0 comments on commit 6cb238a

Please sign in to comment.