Prefer the NIC with global IP address when getting the default machine 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
This commit is contained in:
parent
3621a0169c
commit
6cb238a673
@ -17,6 +17,7 @@
|
|||||||
package io.netty.channel;
|
package io.netty.channel;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBufUtil;
|
import io.netty.buffer.ByteBufUtil;
|
||||||
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
import io.netty.util.internal.ThreadLocalRandom;
|
import io.netty.util.internal.ThreadLocalRandom;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
@ -26,10 +27,12 @@ import java.lang.reflect.Method;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.util.ArrayList;
|
import java.net.UnknownHostException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Enumeration;
|
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.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@ -125,23 +128,35 @@ final class DefaultChannelId implements ChannelId {
|
|||||||
// Find the best MAC address available.
|
// Find the best MAC address available.
|
||||||
final byte[] NOT_FOUND = { -1 };
|
final byte[] NOT_FOUND = { -1 };
|
||||||
byte[] bestMacAddr = NOT_FOUND;
|
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.
|
// Retrieve the list of available network interfaces.
|
||||||
List<NetworkInterface> ifaces = new ArrayList<NetworkInterface>();
|
Map<NetworkInterface, InetAddress> ifaces = new LinkedHashMap<NetworkInterface, InetAddress>();
|
||||||
try {
|
try {
|
||||||
for (Enumeration<NetworkInterface> i = NetworkInterface.getNetworkInterfaces(); i.hasMoreElements();) {
|
for (Enumeration<NetworkInterface> i = NetworkInterface.getNetworkInterfaces(); i.hasMoreElements();) {
|
||||||
NetworkInterface iface = i.nextElement();
|
NetworkInterface iface = i.nextElement();
|
||||||
// Use the interface with proper INET addresses only.
|
// Use the interface with proper INET addresses only.
|
||||||
Enumeration<InetAddress> addrs = iface.getInetAddresses();
|
Enumeration<InetAddress> addrs = iface.getInetAddresses();
|
||||||
if (addrs.hasMoreElements() && !addrs.nextElement().isLoopbackAddress()) {
|
if (addrs.hasMoreElements()) {
|
||||||
ifaces.add(iface);
|
InetAddress a = addrs.nextElement();
|
||||||
|
if (!a.isLoopbackAddress()) {
|
||||||
|
ifaces.put(iface, a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
logger.warn("Failed to retrieve the list of available network interfaces", 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()) {
|
if (iface.isVirtual()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -154,8 +169,15 @@ final class DefaultChannelId implements ChannelId {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isBetterAddress(bestMacAddr, macAddr)) {
|
int res = compareAddresses(bestMacAddr, macAddr);
|
||||||
|
if (res < 0) {
|
||||||
bestMacAddr = macAddr;
|
bestMacAddr = macAddr;
|
||||||
|
bestInetAddr = inetAddr;
|
||||||
|
} else if (res == 0) {
|
||||||
|
if (compareAddresses(bestInetAddr, inetAddr) < 0) {
|
||||||
|
bestMacAddr = macAddr;
|
||||||
|
bestInetAddr = inetAddr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,14 +205,17 @@ final class DefaultChannelId implements ChannelId {
|
|||||||
return bestMacAddr;
|
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) {
|
if (candidate == null) {
|
||||||
return false;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be EUI-48 or longer.
|
// Must be EUI-48 or longer.
|
||||||
if (candidate.length < 6) {
|
if (candidate.length < 6) {
|
||||||
return false;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must not be filled with only 0 and 1.
|
// Must not be filled with only 0 and 1.
|
||||||
@ -203,30 +228,54 @@ final class DefaultChannelId implements ChannelId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (onlyZeroAndOne) {
|
if (onlyZeroAndOne) {
|
||||||
return false;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must not be a multicast address
|
// Must not be a multicast address
|
||||||
if ((candidate[0] & 1) != 0) {
|
if ((candidate[0] & 1) != 0) {
|
||||||
return false;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefer longer globally unique addresses.
|
// Prefer longer globally unique addresses.
|
||||||
if ((current[0] & 2) == 0) {
|
if ((current[0] & 2) == 0) {
|
||||||
if ((candidate[0] & 2) == 0) {
|
if ((candidate[0] & 2) == 0) {
|
||||||
return candidate.length > current.length;
|
return current.length - candidate.length;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((candidate[0] & 2) == 0) {
|
if ((candidate[0] & 2) == 0) {
|
||||||
return true;
|
return -1;
|
||||||
} else {
|
} 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) {
|
private static String formatAddress(byte[] addr) {
|
||||||
StringBuilder buf = new StringBuilder(24);
|
StringBuilder buf = new StringBuilder(24);
|
||||||
for (byte b: addr) {
|
for (byte b: addr) {
|
||||||
|
Loading…
Reference in New Issue
Block a user