Improve localhost / local interface detection mechanism in NetUtil

- Do not attempt to validate localhost by binding a socket because it can fail when SecurityManager is in use
- Find loopback interface first and get address from there instead of getting loopback address from InetAddress.getLocalHost() (because it's more reliable)
- Instead of throwing an Error, just log and fall back to 127.0.0.1 while determining localhost address
This commit is contained in:
Trustin Lee 2013-04-24 11:28:42 +09:00
parent b5989e2449
commit 656d7ca054

View File

@ -15,17 +15,14 @@
*/
package io.netty.util;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
@ -66,75 +63,84 @@ public final class NetUtil {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(NetUtil.class);
static {
//Start the process of discovering localhost
InetAddress localhost;
// Find the first loopback interface available.
NetworkInterface loopbackIface = null;
try {
localhost = InetAddress.getLocalHost();
validateHost(localhost);
} catch (IOException e0) {
// The default local host names did not work. Try hard-coded IPv4 address.
for (Enumeration<NetworkInterface> 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<InetAddress> 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);
}
}
}
if (localhost == null) {
InetAddress localhost6 = null;
try {
localhost = InetAddress.getByAddress(new byte[]{ 127, 0, 0, 1 });
validateHost(localhost);
} catch (IOException e1) {
// The hard-coded IPv4 address did not work. Try hard coded IPv6 address.
try {
localhost = InetAddress.getByAddress(new byte[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 });
validateHost(localhost);
} catch (IOException e2) {
// Log all exceptions we caught so far for easier diagnosis.
logger.warn("Failed to resolve localhost with InetAddress.getLocalHost():", e0);
logger.warn("Failed to resolve localhost with InetAddress.getByAddress(127.0.0.1):", e1);
logger.warn("Failed to resolve localhost with InetAddress.getByAddress(::1)", e2);
throw new Error("failed to resolve localhost; incorrect network configuration?");
localhost6 = InetAddress.getByAddress(new byte[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 });
} catch (Exception e) {
// We should not get here as long as the length of the address is correct.
PlatformDependent.throwException(e);
}
try {
if (NetworkInterface.getByInetAddress(localhost6) != null) {
logger.debug("Using hard-coded IPv6 localhost address: {}", localhost6);
localhost = localhost6;
}
} catch (Exception e) {
// Ignore
} finally {
if (localhost == null) {
InetAddress localhost4 = null;
try {
localhost4 = InetAddress.getByAddress(new byte[]{ 127, 0, 0, 1 });
} catch (Exception e) {
// We should not get here as long as the length of the address is correct.
PlatformDependent.throwException(e);
}
logger.debug("Using hard-coded IPv4 localhost address: {}", localhost4);
localhost = localhost4;
}
}
}
LOCALHOST = localhost;
//Prepare to get the local NetworkInterface
NetworkInterface loopbackInterface;
try {
//Automatically get the loopback interface
loopbackInterface = NetworkInterface.getByInetAddress(LOCALHOST);
} catch (SocketException e) {
//No? Alright. There is a backup!
loopbackInterface = null;
}
//Check to see if a network interface was not found
if (loopbackInterface == null) {
try {
//Start iterating over all network interfaces
for (Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
interfaces.hasMoreElements();) {
//Get the "next" interface
NetworkInterface networkInterface = interfaces.nextElement();
//Check to see if the interface is a loopback interface
if (networkInterface.isLoopback()) {
//Phew! The loopback interface was found.
loopbackInterface = networkInterface;
//No need to keep iterating
break;
}
}
} catch (SocketException e) {
//Nope. Can't do anything else, sorry!
logger.warn("Failed to enumerate network interfaces", e);
}
}
//Set the loopback interface constant
LOOPBACK_IF = loopbackInterface;
int somaxconn = 3072;
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader("/proc/sys/net/core/somaxconn"));
somaxconn = Integer.parseInt(in.readLine());
logger.debug("/proc/sys/net/core/somaxconn: {}", somaxconn);
} catch (Exception e) {
// Failed to get SOMAXCONN
} finally {
@ -150,51 +156,14 @@ public final class NetUtil {
SOMAXCONN = somaxconn;
}
private static void validateHost(InetAddress host) throws IOException {
ServerSocket ss = null;
Socket s1 = null;
Socket s2 = null;
try {
ss = new ServerSocket();
ss.setReuseAddress(false);
ss.bind(new InetSocketAddress(host, 0));
s1 = new Socket(host, ss.getLocalPort());
s2 = ss.accept();
} finally {
if (s2 != null) {
try {
s2.close();
} catch (IOException e) {
// Ignore
}
}
if (s1 != null) {
try {
s1.close();
} catch (IOException e) {
// Ignore
}
}
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
// Ignore
}
}
}
}
/**
* Creates an byte[] based on an ipAddressString. No error handling is
* performed here.
*/
public static byte[] createByteArrayFromIpAddressString(
String ipAddressString) {
public static byte[] createByteArrayFromIpAddressString(String ipAddressString) {
if (isValidIpV4Address(ipAddressString)) {
StringTokenizer tokenizer = new StringTokenizer(ipAddressString,
".");
StringTokenizer tokenizer = new StringTokenizer(ipAddressString, ".");
String token;
int tempInt;
byte[] byteAddress = new byte[4];