1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.omid.tso; 19 20 import org.apache.phoenix.thirdparty.com.google.common.net.HostAndPort; 21 import org.slf4j.Logger; 22 import org.slf4j.LoggerFactory; 23 24 import java.net.InetAddress; 25 import java.net.NetworkInterface; 26 import java.net.SocketException; 27 import java.net.UnknownHostException; 28 import java.util.Enumeration; 29 30 final public class NetworkInterfaceUtils { 31 32 private static final Logger LOG = LoggerFactory.getLogger(NetworkInterfaceUtils.class); 33 34 /** 35 * Returns an <code>InetAddress</code> object encapsulating what is most 36 * likely the machine's LAN IP address. 37 * <p/> 38 * This method is intended for use as a replacement of JDK method 39 * <code>InetAddress.getLocalHost</code>, because that method is ambiguous 40 * on Linux systems. Linux systems enumerate the loopback network 41 * interface the same way as regular LAN network interfaces, but the JDK 42 * <code>InetAddress.getLocalHost</code> method does not specify the 43 * algorithm used to select the address returned under such circumstances, 44 * and will often return the loopback address, which is not valid for 45 * network communication. Details 46 * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4665037">here</a>. 47 * <p/> 48 * This method will scan all IP addresses on a particular network interface 49 * specified as parameter on the host machine to determine the IP address 50 * most likely to be the machine's LAN address. If the machine has multiple 51 * IP addresses, this method will prefer a site-local IP address (e.g. 52 * 192.168.x.x or 10.10.x.x, usually IPv4) if the machine has one (and will 53 * return the first site-local address if the machine has more than one), 54 * but if the machine does not hold a site-local address, this method will 55 * return simply the first non-loopback address found (IPv4 or IPv6). 56 * <p/> 57 * If this method cannot find a non-loopback address using this selection 58 * algorithm, it will fall back to calling and returning the result of JDK 59 * method <code>InetAddress.getLocalHost()</code>. 60 * <p/> 61 * 62 * @param ifaceName 63 * The name of the network interface to extract the IP address 64 * from 65 * @throws UnknownHostException 66 * If the LAN address of the machine cannot be found. 67 */ 68 static InetAddress getIPAddressFromNetworkInterface(String ifaceName) 69 throws SocketException, UnknownHostException { 70 71 NetworkInterface iface = NetworkInterface.getByName(ifaceName); 72 if (iface == null) { 73 throw new IllegalArgumentException( 74 "Network interface " + ifaceName + " not found"); 75 } 76 77 InetAddress candidateAddress = null; 78 Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); 79 while (inetAddrs.hasMoreElements()) { 80 InetAddress inetAddr = inetAddrs.nextElement(); 81 if (!inetAddr.isLoopbackAddress()) { 82 if (inetAddr.isSiteLocalAddress()) { 83 return inetAddr; // Return non-loopback site-local address 84 } else if (candidateAddress == null) { 85 // Found non-loopback address, but not necessarily site-local 86 candidateAddress = inetAddr; 87 } 88 } 89 } 90 91 if (candidateAddress != null) { 92 // Site-local address not found, but found other non-loopback addr 93 // Server might have a non-site-local address assigned to its NIC 94 // (or might be running IPv6 which deprecates "site-local" concept) 95 return candidateAddress; 96 } 97 98 // At this point, we did not find a non-loopback address. 99 // Fall back to returning whatever InetAddress.getLocalHost() returns 100 InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); 101 if (jdkSuppliedAddress == null) { 102 throw new UnknownHostException( 103 "InetAddress.getLocalHost() unexpectedly returned null."); 104 } 105 return jdkSuppliedAddress; 106 } 107 108 public static String getTSOHostAndPort(TSOServerConfig config) throws SocketException, UnknownHostException { 109 110 // Build TSO host:port string and validate it 111 final String tsoNetIfaceName = config.getNetworkIfaceName(); 112 InetAddress addr = getIPAddressFromNetworkInterface(tsoNetIfaceName); 113 final int tsoPort = config.getPort(); 114 115 String tsoHostAndPortAsString = "N/A"; 116 try { 117 tsoHostAndPortAsString = HostAndPort.fromParts(addr.getHostAddress(), tsoPort).toString(); 118 } catch (IllegalArgumentException e) { 119 LOG.error("Cannot parse TSO host:port string {}", tsoHostAndPortAsString); 120 throw e; 121 } 122 return tsoHostAndPortAsString; 123 124 } 125 126 }