blob: 72bb59b338e23ff5317d88f4bfcd5fc3621cab34 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.omid.tso;
import com.google.common.net.HostAndPort;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;
final public class NetworkInterfaceUtils {
private static final Logger LOG = LoggerFactory.getLogger(NetworkInterfaceUtils.class);
/**
* Returns an <code>InetAddress</code> object encapsulating what is most
* likely the machine's LAN IP address.
* <p/>
* This method is intended for use as a replacement of JDK method
* <code>InetAddress.getLocalHost</code>, because that method is ambiguous
* on Linux systems. Linux systems enumerate the loopback network
* interface the same way as regular LAN network interfaces, but the JDK
* <code>InetAddress.getLocalHost</code> method does not specify the
* algorithm used to select the address returned under such circumstances,
* and will often return the loopback address, which is not valid for
* network communication. Details
* <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4665037">here</a>.
* <p/>
* This method will scan all IP addresses on a particular network interface
* specified as parameter on the host machine to determine the IP address
* most likely to be the machine's LAN address. If the machine has multiple
* IP addresses, this method will prefer a site-local IP address (e.g.
* 192.168.x.x or 10.10.x.x, usually IPv4) if the machine has one (and will
* return the first site-local address if the machine has more than one),
* but if the machine does not hold a site-local address, this method will
* return simply the first non-loopback address found (IPv4 or IPv6).
* <p/>
* If this method cannot find a non-loopback address using this selection
* algorithm, it will fall back to calling and returning the result of JDK
* method <code>InetAddress.getLocalHost()</code>.
* <p/>
*
* @param ifaceName
* The name of the network interface to extract the IP address
* from
* @throws UnknownHostException
* If the LAN address of the machine cannot be found.
*/
static InetAddress getIPAddressFromNetworkInterface(String ifaceName)
throws SocketException, UnknownHostException {
NetworkInterface iface = NetworkInterface.getByName(ifaceName);
if (iface == null) {
throw new IllegalArgumentException(
"Network interface " + ifaceName + " not found");
}
InetAddress candidateAddress = null;
Enumeration<InetAddress> inetAddrs = iface.getInetAddresses();
while (inetAddrs.hasMoreElements()) {
InetAddress inetAddr = inetAddrs.nextElement();
if (!inetAddr.isLoopbackAddress()) {
if (inetAddr.isSiteLocalAddress()) {
return inetAddr; // Return non-loopback site-local address
} else if (candidateAddress == null) {
// Found non-loopback address, but not necessarily site-local
candidateAddress = inetAddr;
}
}
}
if (candidateAddress != null) {
// Site-local address not found, but found other non-loopback addr
// Server might have a non-site-local address assigned to its NIC
// (or might be running IPv6 which deprecates "site-local" concept)
return candidateAddress;
}
// At this point, we did not find a non-loopback address.
// Fall back to returning whatever InetAddress.getLocalHost() returns
InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
if (jdkSuppliedAddress == null) {
throw new UnknownHostException(
"InetAddress.getLocalHost() unexpectedly returned null.");
}
return jdkSuppliedAddress;
}
public static String getTSOHostAndPort(TSOServerConfig config) throws SocketException, UnknownHostException {
// Build TSO host:port string and validate it
final String tsoNetIfaceName = config.getNetworkIfaceName();
InetAddress addr = getIPAddressFromNetworkInterface(tsoNetIfaceName);
final int tsoPort = config.getPort();
String tsoHostAndPortAsString = "N/A";
try {
tsoHostAndPortAsString = HostAndPort.fromParts(addr.getHostAddress(), tsoPort).toString();
} catch (IllegalArgumentException e) {
LOG.error("Cannot parse TSO host:port string {}", tsoHostAndPortAsString);
throw e;
}
return tsoHostAndPortAsString;
}
}