View Javadoc
1   /*
2    * Copyright 2020 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty5.util;
17  
18  import io.netty5.util.internal.PlatformDependent;
19  import io.netty5.util.internal.SocketUtils;
20  import io.netty5.util.internal.logging.InternalLogger;
21  import io.netty5.util.internal.logging.InternalLoggerFactory;
22  
23  import java.net.Inet4Address;
24  import java.net.Inet6Address;
25  import java.net.InetAddress;
26  import java.net.NetworkInterface;
27  import java.net.SocketException;
28  import java.util.ArrayList;
29  import java.util.Enumeration;
30  import java.util.List;
31  
32  final class NetUtilInitializations {
33      /**
34       * The logger being used by this class
35       */
36      private static final InternalLogger logger = InternalLoggerFactory.getInstance(NetUtilInitializations.class);
37  
38      private NetUtilInitializations() {
39      }
40  
41      static Inet4Address createLocalhost4() {
42          byte[] LOCALHOST4_BYTES = {127, 0, 0, 1};
43  
44          Inet4Address localhost4 = null;
45          try {
46              localhost4 = (Inet4Address) InetAddress.getByAddress("localhost", LOCALHOST4_BYTES);
47          } catch (Exception e) {
48              // We should not get here as long as the length of the address is correct.
49              PlatformDependent.throwException(e);
50          }
51  
52          return localhost4;
53      }
54  
55      static Inet6Address createLocalhost6() {
56          byte[] LOCALHOST6_BYTES = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
57  
58          Inet6Address localhost6 = null;
59          try {
60              localhost6 = (Inet6Address) InetAddress.getByAddress("localhost", LOCALHOST6_BYTES);
61          } catch (Exception e) {
62              // We should not get here as long as the length of the address is correct.
63              PlatformDependent.throwException(e);
64          }
65  
66          return localhost6;
67      }
68  
69      static NetworkIfaceAndInetAddress determineLoopback(Inet4Address localhost4, Inet6Address localhost6) {
70          // Retrieve the list of available network interfaces.
71          List<NetworkInterface> ifaces = new ArrayList<>();
72          try {
73              Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
74              if (interfaces != null) {
75                  while (interfaces.hasMoreElements()) {
76                      NetworkInterface iface = interfaces.nextElement();
77                      // Use the interface with proper INET addresses only.
78                      if (SocketUtils.addressesFromNetworkInterface(iface).hasMoreElements()) {
79                          ifaces.add(iface);
80                      }
81                  }
82              }
83          } catch (SocketException e) {
84              logger.warn("Failed to retrieve the list of available network interfaces", e);
85          }
86  
87          // Find the first loopback interface available from its INET address (127.0.0.1 or ::1)
88          // Note that we do not use NetworkInterface.isLoopback() in the first place because it takes long time
89          // on a certain environment. (e.g. Windows with -Djava.net.preferIPv4Stack=true)
90          NetworkInterface loopbackIface = null;
91          InetAddress loopbackAddr = null;
92          loop: for (NetworkInterface iface: ifaces) {
93              for (Enumeration<InetAddress> i = SocketUtils.addressesFromNetworkInterface(iface); i.hasMoreElements();) {
94                  InetAddress addr = i.nextElement();
95                  if (addr.isLoopbackAddress()) {
96                      // Found
97                      loopbackIface = iface;
98                      loopbackAddr = addr;
99                      break loop;
100                 }
101             }
102         }
103 
104         // If failed to find the loopback interface from its INET address, fall back to isLoopback().
105         if (loopbackIface == null) {
106             try {
107                 for (NetworkInterface iface: ifaces) {
108                     if (iface.isLoopback()) {
109                         Enumeration<InetAddress> i = SocketUtils.addressesFromNetworkInterface(iface);
110                         if (i.hasMoreElements()) {
111                             // Found the one with INET address.
112                             loopbackIface = iface;
113                             loopbackAddr = i.nextElement();
114                             break;
115                         }
116                     }
117                 }
118 
119                 if (loopbackIface == null) {
120                     logger.warn("Failed to find the loopback interface");
121                 }
122             } catch (SocketException e) {
123                 logger.warn("Failed to find the loopback interface", e);
124             }
125         }
126 
127         if (loopbackIface != null) {
128             // Found the loopback interface with an INET address.
129             logger.debug(
130                     "Loopback interface: {} ({}, {})",
131                     loopbackIface.getName(), loopbackIface.getDisplayName(), loopbackAddr.getHostAddress());
132         } else {
133             // Could not find the loopback interface, but we can't leave LOCALHOST as null.
134             // Use LOCALHOST6 or LOCALHOST4, preferably the IPv6 one.
135             if (loopbackAddr == null) {
136                 try {
137                     if (NetworkInterface.getByInetAddress(localhost6) != null) {
138                         logger.debug("Using hard-coded IPv6 localhost address: {}", localhost6);
139                         loopbackAddr = localhost6;
140                     }
141                 } catch (Exception e) {
142                     // Ignore
143                 } finally {
144                     if (loopbackAddr == null) {
145                         logger.debug("Using hard-coded IPv4 localhost address: {}", localhost4);
146                         loopbackAddr = localhost4;
147                     }
148                 }
149             }
150         }
151 
152         return new NetworkIfaceAndInetAddress(loopbackIface, loopbackAddr);
153     }
154 
155     static final class NetworkIfaceAndInetAddress {
156         private final NetworkInterface iface;
157         private final InetAddress address;
158 
159         NetworkIfaceAndInetAddress(NetworkInterface iface, InetAddress address) {
160             this.iface = iface;
161             this.address = address;
162         }
163 
164         public NetworkInterface iface() {
165             return iface;
166         }
167 
168         public InetAddress address() {
169             return address;
170         }
171     }
172 }