diff --git a/common/src/main/java/io/netty/util/NetUtil.java b/common/src/main/java/io/netty/util/NetUtil.java index 0ae1922ac5..42cb89e947 100644 --- a/common/src/main/java/io/netty/util/NetUtil.java +++ b/common/src/main/java/io/netty/util/NetUtil.java @@ -28,6 +28,7 @@ import java.net.NetworkInterface; import java.net.SocketException; import java.util.ArrayList; import java.util.Enumeration; +import java.util.List; import java.util.StringTokenizer; /** @@ -56,7 +57,7 @@ public final class NetUtil { public static final InetAddress LOCALHOST; /** - * The loopback {@link NetworkInterface} on the current machine + * The loopback {@link NetworkInterface} of the current machine */ public static final NetworkInterface LOOPBACK_IF; @@ -72,48 +73,13 @@ public final class NetUtil { private static final InternalLogger logger = InternalLoggerFactory.getInstance(NetUtil.class); static { - // Find the first loopback interface available. - NetworkInterface loopbackIface = null; - try { - for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); - ifaces.hasMoreElements();) { - - NetworkInterface iface = ifaces.nextElement(); - if (iface.isLoopback()) { - // Found - loopbackIface = iface; - break; - } - } - if (loopbackIface == null) { - logger.warn("Failed to find the loopback interface"); - } - } catch (SocketException e) { - logger.warn("Failed to find the loopback interface", e); - } - - LOOPBACK_IF = loopbackIface; - - // Find the localhost address - InetAddress localhost = null; - if (LOOPBACK_IF != null) { - logger.debug("Loopback interface: {}", LOOPBACK_IF.getDisplayName()); - for (Enumeration addrs = LOOPBACK_IF.getInetAddresses(); - addrs.hasMoreElements();) { - InetAddress a = addrs.nextElement(); - if (localhost == null) { - logger.debug("Loopback address: {} (primary)", a); - localhost = a; - } else { - logger.debug("Loopback address: {}", a); - } - } - } + byte[] LOCALHOST4_BYTES = {127, 0, 0, 1}; + byte[] LOCALHOST6_BYTES = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; // Create IPv4 loopback address. Inet4Address localhost4 = null; try { - localhost4 = (Inet4Address) InetAddress.getByAddress(new byte[]{127, 0, 0, 1}); + localhost4 = (Inet4Address) InetAddress.getByAddress(LOCALHOST4_BYTES); } catch (Exception e) { // We should not get here as long as the length of the address is correct. PlatformDependent.throwException(e); @@ -123,33 +89,96 @@ public final class NetUtil { // Create IPv6 loopback address. Inet6Address localhost6 = null; try { - localhost6 = (Inet6Address) InetAddress.getByAddress( - new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}); + localhost6 = (Inet6Address) InetAddress.getByAddress(LOCALHOST6_BYTES); } catch (Exception e) { // We should not get here as long as the length of the address is correct. PlatformDependent.throwException(e); } LOCALHOST6 = localhost6; - // Try to determine the default loopback address if we couldn't yet. - if (localhost == null) { - try { - if (NetworkInterface.getByInetAddress(LOCALHOST6) != null) { - logger.debug("Using hard-coded IPv6 localhost address: {}", localhost6); - localhost = localhost6; + // Retrieve the list of available network interfaces. + List ifaces = new ArrayList(); + try { + for (Enumeration i = NetworkInterface.getNetworkInterfaces(); i.hasMoreElements();) { + NetworkInterface iface = i.nextElement(); + // Use the interface with proper INET addresses only. + if (iface.getInetAddresses().hasMoreElements()) { + ifaces.add(iface); } - } catch (Exception e) { - // Ignore - } finally { - if (localhost == null) { - logger.debug("Using hard-coded IPv4 localhost address: {}", localhost4); - localhost = localhost4; + } + } catch (SocketException e) { + logger.warn("Failed to retrieve the list of available network interfaces", e); + } + + // Find the first loopback interface available from its INET address (127.0.0.1 or ::1) + // Note that we do not use NetworkInterface.isLoopback() in the first place because it takes long time + // on a certain environment. (e.g. Windows with -Djava.net.preferIPv4Stack=true) + NetworkInterface loopbackIface = null; + InetAddress loopbackAddr = null; + loop: for (NetworkInterface iface: ifaces) { + for (Enumeration i = iface.getInetAddresses(); i.hasMoreElements();) { + InetAddress addr = i.nextElement(); + if (addr.isLoopbackAddress()) { + // Found + loopbackIface = iface; + loopbackAddr = addr; + break loop; } } } - LOCALHOST = localhost; + // If failed to find the loopback interface from its INET address, fall back to isLoopback(). + if (loopbackIface == null) { + try { + for (NetworkInterface iface: ifaces) { + if (iface.isLoopback()) { + Enumeration i = iface.getInetAddresses(); + if (i.hasMoreElements()) { + // Found the one with INET address. + loopbackIface = iface; + loopbackAddr = i.nextElement(); + break; + } + } + } + if (loopbackIface == null) { + logger.warn("Failed to find the loopback interface"); + } + } catch (SocketException e) { + logger.warn("Failed to find the loopback interface", e); + } + } + + if (loopbackIface != null) { + // Found the loopback interface with an INET address. + logger.debug( + "Loopback interface: {} ({}, {})", + loopbackIface.getName(), loopbackIface.getDisplayName(), loopbackAddr.getHostAddress()); + } else { + // Could not find the loopback interface, but we can't leave LOCALHOST as null. + // Use LOCALHOST6 or LOCALHOST4, preferably the IPv6 one. + if (loopbackAddr == null) { + try { + if (NetworkInterface.getByInetAddress(LOCALHOST6) != null) { + logger.debug("Using hard-coded IPv6 localhost address: {}", localhost6); + loopbackAddr = localhost6; + } + } catch (Exception e) { + // Ignore + } finally { + if (loopbackAddr == null) { + logger.debug("Using hard-coded IPv4 localhost address: {}", localhost4); + loopbackAddr = localhost4; + } + } + } + } + + LOOPBACK_IF = loopbackIface; + LOCALHOST = loopbackAddr; + + // Determine the default somaxconn (server socket backlog) value of the platform. int somaxconn = 3072; BufferedReader in = null; try { @@ -446,7 +475,9 @@ public final class NetUtil { return false; } try { - Integer.parseInt(ipAddress.substring(i + 1)); + if (Integer.parseInt(ipAddress.substring(i + 1)) < 0) { + return false; + } } catch (NumberFormatException e) { // right now we just support an integer after the % so if // this is not @@ -506,10 +537,7 @@ public final class NetUtil { return false; } } - if (Integer.parseInt(word) > 255) { - return false; - } - return true; + return Integer.parseInt(word) <= 255; } static boolean isValidHexChar(char c) { @@ -560,10 +588,8 @@ public final class NetUtil { if (word.length() == 0 || Integer.parseInt(word.toString()) > 255) { return false; } - if (periods != 3) { - return false; - } - return true; + + return periods == 3; } /** diff --git a/transport/src/main/java/io/netty/channel/DefaultChannelId.java b/transport/src/main/java/io/netty/channel/DefaultChannelId.java index 4e9e799e45..aa05e09744 100644 --- a/transport/src/main/java/io/netty/channel/DefaultChannelId.java +++ b/transport/src/main/java/io/netty/channel/DefaultChannelId.java @@ -23,10 +23,13 @@ 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.NetworkInterface; import java.net.SocketException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; +import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; @@ -123,36 +126,36 @@ final class DefaultChannelId implements ChannelId { final byte[] NOT_FOUND = { -1 }; byte[] bestMacAddr = NOT_FOUND; - Enumeration ifaces = null; + // Retrieve the list of available network interfaces. + List ifaces = new ArrayList(); try { - ifaces = NetworkInterface.getNetworkInterfaces(); + for (Enumeration i = NetworkInterface.getNetworkInterfaces(); i.hasMoreElements();) { + NetworkInterface iface = i.nextElement(); + // Use the interface with proper INET addresses only. + Enumeration addrs = iface.getInetAddresses(); + if (addrs.hasMoreElements() && !addrs.nextElement().isLoopbackAddress()) { + ifaces.add(iface); + } + } } catch (SocketException e) { - logger.warn("Failed to find the loopback interface", e); + logger.warn("Failed to retrieve the list of available network interfaces", e); } - if (ifaces != null) { - while (ifaces.hasMoreElements()) { - NetworkInterface iface = ifaces.nextElement(); - try { - if (iface.isLoopback() || iface.isPointToPoint() || iface.isVirtual()) { - continue; - } - } catch (SocketException e) { - logger.debug("Failed to determine the type of a network interface: {}", iface, e); - continue; - } + for (NetworkInterface iface: ifaces) { + if (iface.isVirtual()) { + continue; + } - byte[] macAddr; - try { - macAddr = iface.getHardwareAddress(); - } catch (SocketException e) { - logger.debug("Failed to get the hardware address of a network interface: {}", iface, e); - continue; - } + byte[] macAddr; + try { + macAddr = iface.getHardwareAddress(); + } catch (SocketException e) { + logger.debug("Failed to get the hardware address of a network interface: {}", iface, e); + continue; + } - if (isBetterAddress(bestMacAddr, macAddr)) { - bestMacAddr = macAddr; - } + if (isBetterAddress(bestMacAddr, macAddr)) { + bestMacAddr = macAddr; } } @@ -164,8 +167,17 @@ final class DefaultChannelId implements ChannelId { formatAddress(bestMacAddr)); } - if (bestMacAddr.length != MACHINE_ID_LEN) { - bestMacAddr = Arrays.copyOf(bestMacAddr, MACHINE_ID_LEN); + switch (bestMacAddr.length) { + case 6: // EUI-48 - convert to EUI-64 + byte[] newAddr = new byte[MACHINE_ID_LEN]; + System.arraycopy(bestMacAddr, 0, newAddr, 0, 3); + newAddr[3] = (byte) 0xFF; + newAddr[4] = (byte) 0xFE; + System.arraycopy(bestMacAddr, 3, newAddr, 5, 3); + bestMacAddr = newAddr; + break; + default: // Unknown + bestMacAddr = Arrays.copyOf(bestMacAddr, MACHINE_ID_LEN); } return bestMacAddr; @@ -181,20 +193,16 @@ final class DefaultChannelId implements ChannelId { return false; } - // Must not be filled with only 0 or 1. - boolean onlyZero = true; - boolean onlyOne = true; + // Must not be filled with only 0 and 1. + boolean onlyZeroAndOne = true; for (byte b: candidate) { - if (b != 0) { - onlyZero = false; - } - - if (b != -1) { - onlyOne = false; + if (b != 0 && b != 1) { + onlyZeroAndOne = false; + break; } } - if (onlyZero || onlyOne) { + if (onlyZeroAndOne) { return false; }