/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gradle.internal.remote.internal.inet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
/**
* Provides some information about the network addresses of the local machine.
*/
class InetAddresses {
private final Logger logger = LoggerFactory.getLogger(getClass());
private List<InetAddress> loopback = new ArrayList<InetAddress>();
private List<InetAddress> remote = new ArrayList<InetAddress>();
private List<NetworkInterface> multicastInterfaces = new ArrayList<NetworkInterface>();
InetAddresses() throws SocketException {
analyzeNetworkInterfaces();
if (multicastInterfaces.isEmpty()) {
useMulticastFallback();
}
}
private void analyzeNetworkInterfaces() throws SocketException {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
analyzeNetworkInterface(interfaces.nextElement());
}
}
private void analyzeNetworkInterface(NetworkInterface networkInterface) {
logger.debug("Adding IP addresses for network interface {}", networkInterface.getDisplayName());
try {
boolean isLoopbackInterface = networkInterface.isLoopback();
logger.debug("Is this a loopback interface? {}", isLoopbackInterface);
boolean isMulticast = networkInterface.supportsMulticast();
logger.debug("Is this a multicast interface? {}", isMulticast);
boolean isRemote = false;
Enumeration<InetAddress> candidates = networkInterface.getInetAddresses();
while (candidates.hasMoreElements()) {
InetAddress candidate = candidates.nextElement();
if (isLoopbackInterface) {
if (candidate.isLoopbackAddress()) {
logger.debug("Adding loopback address {}", candidate);
loopback.add(candidate);
} else {
logger.debug("Ignoring remote address on loopback interface {}", candidate);
}
} else {
if (candidate.isLoopbackAddress()) {
logger.debug("Ignoring loopback address on remote interface {}", candidate);
} else {
logger.debug("Adding remote address {}", candidate);
remote.add(candidate);
isRemote = true;
}
}
}
if (isMulticast) {
// Prefer remotely reachable interfaces over loopback interfaces for multicast
if (isRemote) {
logger.debug("Adding remote multicast interface {}", networkInterface.getDisplayName());
multicastInterfaces.add(0, networkInterface);
} else {
logger.debug("Adding loopback multicast interface {}", networkInterface.getDisplayName());
multicastInterfaces.add(networkInterface);
}
}
} catch (SocketException e) {
// Log the error but analyze the remaining interfaces. We could for example run into https://bugs.openjdk.java.net/browse/JDK-7032558
logger.debug("Error while querying interface {} for IP addresses", networkInterface, e);
} catch (Throwable e) {
throw new RuntimeException(String.format("Could not determine the IP addresses for network interface %s", networkInterface.getName()), e);
}
}
private void useMulticastFallback() throws SocketException {
logger.debug("No multicast interfaces, using fallbacks");
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
while (networkInterfaces.hasMoreElements()) {
multicastInterfaces.add(networkInterfaces.nextElement());
}
}
public List<InetAddress> getLoopback() {
return loopback;
}
public List<InetAddress> getRemote() {
return remote;
}
/**
* Locates the network interfaces that should be used for multicast, in order of preference.
*/
public List<NetworkInterface> getMulticastInterfaces() {
return multicastInterfaces;
}
}