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 }