View Javadoc

1   package org.apache.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 java.net.InetAddress;
23  import java.net.NetworkInterface;
24  import java.net.UnknownHostException;
25  import java.util.Enumeration;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
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 final static 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/> If
82       * this method cannot find a non-loopback address using this selection algorithm, it will fall
83       * back to calling and returning the result of JDK method <code>InetAddress.getLocalHost</code>.
84       * <p>
85       * <a href="http://issues.apache.org/jira/browse/JCS-40">JIR ISSUE JCS-40</a>
86       * <p>
87       * @return InetAddress
88       * @throws UnknownHostException If the LAN address of the machine cannot be found.
89       */
90      private static InetAddress getLocalHostLANAddress()
91          throws UnknownHostException
92      {
93          try
94          {
95              InetAddress candidateAddress = null;
96              // Iterate all NICs (network interface cards)...
97              for ( Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); )
98              {
99                  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 }