001 package org.apache.jcs.utils.net;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.net.InetAddress;
023 import java.net.NetworkInterface;
024 import java.net.UnknownHostException;
025 import java.util.Enumeration;
026
027 import org.apache.commons.logging.Log;
028 import org.apache.commons.logging.LogFactory;
029
030 /**
031 * Simple utility for getting the local host name.
032 * <p>
033 * @author Aaron Smuts
034 */
035 public class HostNameUtil
036 {
037 /** The logger. */
038 private final static Log log = LogFactory.getLog( HostNameUtil.class );
039
040 /**
041 * Gets the address for the local machine.
042 * <p>
043 * @return InetAddress.getLocalHost().getHostAddress()
044 * @throws UnknownHostException
045 */
046 public static String getLocalHostAddress() throws UnknownHostException
047 {
048 try
049 {
050 String hostAddress = getLocalHostLANAddress().getHostAddress();
051 if ( log.isDebugEnabled() )
052 {
053 log.debug( "hostAddress = [" + hostAddress + "]" );
054 }
055 return hostAddress;
056 }
057 catch ( UnknownHostException e1 )
058 {
059 log.error( "Couldn't get localhost address", e1 );
060 throw e1;
061 }
062 }
063
064 /**
065 * Returns an <code>InetAddress</code> object encapsulating what is most likely the machine's
066 * LAN IP address.
067 * <p>
068 * This method is intended for use as a replacement of JDK method
069 * <code>InetAddress.getLocalHost</code>, because that method is ambiguous on Linux systems.
070 * Linux systems enumerate the loopback network interface the same way as regular LAN network
071 * interfaces, but the JDK <code>InetAddress.getLocalHost</code> method does not specify the
072 * algorithm used to select the address returned under such circumstances, and will often return
073 * the loopback address, which is not valid for network communication. Details <a
074 * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4665037">here</a>.
075 * <p>
076 * This method will scan all IP addresses on all network interfaces on the host machine to
077 * determine the IP address most likely to be the machine's LAN address. If the machine has
078 * multiple IP addresses, this method will prefer a site-local IP address (e.g. 192.168.x.x or
079 * 10.10.x.x, usually IPv4) if the machine has one (and will return the first site-local address
080 * if the machine has more than one), but if the machine does not hold a site-local address,
081 * this method will return simply the first non-loopback address found (IPv4 or IPv6). <p/> If
082 * this method cannot find a non-loopback address using this selection algorithm, it will fall
083 * back to calling and returning the result of JDK method <code>InetAddress.getLocalHost</code>.
084 * <p>
085 * <a href="http://issues.apache.org/jira/browse/JCS-40">JIR ISSUE JCS-40</a>
086 * <p>
087 * @return InetAddress
088 * @throws UnknownHostException If the LAN address of the machine cannot be found.
089 */
090 private static InetAddress getLocalHostLANAddress()
091 throws UnknownHostException
092 {
093 try
094 {
095 InetAddress candidateAddress = null;
096 // Iterate all NICs (network interface cards)...
097 for ( Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); )
098 {
099 NetworkInterface iface = ifaces.nextElement();
100 // Iterate all IP addresses assigned to each card...
101 for ( Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); )
102 {
103 InetAddress inetAddr = inetAddrs.nextElement();
104 if ( !inetAddr.isLoopbackAddress() )
105 {
106 if ( inetAddr.isSiteLocalAddress() )
107 {
108 // Found non-loopback site-local address. Return it immediately...
109 return inetAddr;
110 }
111 else if ( candidateAddress == null )
112 {
113 // Found non-loopback address, but not necessarily site-local.
114 // Store it as a candidate to be returned if site-local address is not subsequently found...
115 candidateAddress = inetAddr;
116 // Note that we don't repeatedly assign non-loopback non-site-local addresses as candidates,
117 // only the first. For subsequent iterations, candidate will be non-null.
118 }
119 }
120 }
121 }
122 if ( candidateAddress != null )
123 {
124 // We did not find a site-local address, but we found some other non-loopback address.
125 // Server might have a non-site-local address assigned to its NIC (or it might be running
126 // IPv6 which deprecates the "site-local" concept).
127 // Return this non-loopback candidate address...
128 return candidateAddress;
129 }
130 // At this point, we did not find a non-loopback address.
131 // Fall back to returning whatever InetAddress.getLocalHost() returns...
132 InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
133 if ( jdkSuppliedAddress == null )
134 {
135 throw new UnknownHostException( "The JDK InetAddress.getLocalHost() method unexpectedly returned null." );
136 }
137 return jdkSuppliedAddress;
138 }
139 catch ( Exception e )
140 {
141 UnknownHostException unknownHostException = new UnknownHostException( "Failed to determine LAN address: "
142 + e );
143 unknownHostException.initCause( e );
144 throw unknownHostException;
145 }
146 }
147 }