1 package org.apache.commons.jcs.utils.net;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24
25 import java.net.InetAddress;
26 import java.net.NetworkInterface;
27 import java.net.UnknownHostException;
28 import java.util.Enumeration;
29
30 /**
31 * Simple utility for getting the local host name.
32 * <p>
33 * @author Aaron Smuts
34 */
35 public class HostNameUtil
36 {
37 /** The logger. */
38 private static final Log log = LogFactory.getLog( HostNameUtil.class );
39
40 /**
41 * Gets the address for the local machine.
42 * <p>
43 * @return InetAddress.getLocalHost().getHostAddress()
44 * @throws UnknownHostException
45 */
46 public static String getLocalHostAddress() throws UnknownHostException
47 {
48 try
49 {
50 String hostAddress = getLocalHostLANAddress().getHostAddress();
51 if ( log.isDebugEnabled() )
52 {
53 log.debug( "hostAddress = [" + hostAddress + "]" );
54 }
55 return hostAddress;
56 }
57 catch ( UnknownHostException e1 )
58 {
59 log.error( "Couldn't get localhost address", e1 );
60 throw e1;
61 }
62 }
63
64 /**
65 * Returns an <code>InetAddress</code> object encapsulating what is most likely the machine's
66 * LAN IP address.
67 * <p>
68 * This method is intended for use as a replacement of JDK method
69 * <code>InetAddress.getLocalHost</code>, because that method is ambiguous on Linux systems.
70 * Linux systems enumerate the loopback network interface the same way as regular LAN network
71 * interfaces, but the JDK <code>InetAddress.getLocalHost</code> method does not specify the
72 * algorithm used to select the address returned under such circumstances, and will often return
73 * the loopback address, which is not valid for network communication. Details <a
74 * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4665037">here</a>.
75 * <p>
76 * This method will scan all IP addresses on all network interfaces on the host machine to
77 * determine the IP address most likely to be the machine's LAN address. If the machine has
78 * multiple IP addresses, this method will prefer a site-local IP address (e.g. 192.168.x.x or
79 * 10.10.x.x, usually IPv4) if the machine has one (and will return the first site-local address
80 * if the machine has more than one), but if the machine does not hold a site-local address,
81 * this method will return simply the first non-loopback address found (IPv4 or IPv6).</p>
82 * <p>
83 * If this method cannot find a non-loopback address using this selection algorithm, it will
84 * fall back to calling and returning the result of JDK method
85 * <code>InetAddress.getLocalHost</code>.
86 * <p>
87 * <a href="http://issues.apache.org/jira/browse/JCS-40">JIR ISSUE JCS-40</a>
88 * <p>
89 * @return InetAddress
90 * @throws UnknownHostException If the LAN address of the machine cannot be found.
91 */
92 public static InetAddress getLocalHostLANAddress()
93 throws UnknownHostException
94 {
95 try
96 {
97 InetAddress candidateAddress = null;
98 // Iterate all NICs (network interface cards)...
99 for ( Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); )
100 {
101 NetworkInterface iface = ifaces.nextElement();
102 // Iterate all IP addresses assigned to each card...
103 for ( Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); )
104 {
105 InetAddress inetAddr = inetAddrs.nextElement();
106 if ( !inetAddr.isLoopbackAddress() )
107 {
108 if ( inetAddr.isSiteLocalAddress() )
109 {
110 // Found non-loopback site-local address. Return it immediately...
111 return inetAddr;
112 }
113 else if ( candidateAddress == null )
114 {
115 // Found non-loopback address, but not necessarily site-local.
116 // Store it as a candidate to be returned if site-local address is not subsequently found...
117 candidateAddress = inetAddr;
118 // Note that we don't repeatedly assign non-loopback non-site-local addresses as candidates,
119 // only the first. For subsequent iterations, candidate will be non-null.
120 }
121 }
122 }
123 }
124 if ( candidateAddress != null )
125 {
126 // We did not find a site-local address, but we found some other non-loopback address.
127 // Server might have a non-site-local address assigned to its NIC (or it might be running
128 // IPv6 which deprecates the "site-local" concept).
129 // Return this non-loopback candidate address...
130 return candidateAddress;
131 }
132 // At this point, we did not find a non-loopback address.
133 // Fall back to returning whatever InetAddress.getLocalHost() returns...
134 InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
135 if ( jdkSuppliedAddress == null )
136 {
137 throw new UnknownHostException( "The JDK InetAddress.getLocalHost() method unexpectedly returned null." );
138 }
139 return jdkSuppliedAddress;
140 }
141 catch ( Exception e )
142 {
143 UnknownHostException unknownHostException = new UnknownHostException( "Failed to determine LAN address: "
144 + e );
145 unknownHostException.initCause( e );
146 throw unknownHostException;
147 }
148 }
149 }