View Javadoc

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 }