blob: 4b866466332c64d13dc65abd306f91ccee04b607 [file] [log] [blame]
// Copyright (C) 2017 The Android Open Source Project
//
// 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 com.ericsson.gerrit.plugins.highavailability.peers.jgroups;
import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Optional;
@Singleton
class InetAddressFinder {
private final boolean preferIPv4;
private final Configuration.JGroups jgroupsConfig;
@Inject
InetAddressFinder(Configuration pluginConfiguration) {
preferIPv4 = Boolean.getBoolean("java.net.preferIPv4Stack");
jgroupsConfig = pluginConfiguration.jgroups();
}
/**
* Iterate over all network interfaces and return the first appropriate address. Interfaces which
* are loopback interfaces, or down or which don't support multicast are not inspected. Interfaces
* whose name matches a {@code #skipInterface} are also ignored. By that it is possible to skip
* interfaces which should not be used by jgroups (e.g. 'lo0', 'utun0' on MacOS).
*
* @return an Optional<InetAddress>
*/
Optional<InetAddress> findAddress() throws SocketException {
return findFirstAppropriateAddress(Collections.list(NetworkInterface.getNetworkInterfaces()));
}
@VisibleForTesting
Optional<InetAddress> findFirstAppropriateAddress(List<NetworkInterface> networkInterfaces)
throws SocketException {
for (NetworkInterface ni : networkInterfaces) {
if (ni.isLoopback() || !ni.isUp() || !ni.supportsMulticast() || shouldSkip(ni.getName())) {
continue;
}
Enumeration<InetAddress> inetAddresses = ni.getInetAddresses();
while (inetAddresses.hasMoreElements()) {
InetAddress a = inetAddresses.nextElement();
if (preferIPv4 && a instanceof Inet4Address) {
return Optional.of(a);
}
if (!preferIPv4 && a instanceof Inet6Address) {
return Optional.of(a);
}
}
}
return Optional.empty();
}
@VisibleForTesting
boolean shouldSkip(String name) {
for (String s : jgroupsConfig.skipInterface()) {
if (s.endsWith("*") && name.startsWith(s.substring(0, s.length() - 1))) {
return true;
}
if (name.equals(s)) {
return true;
}
}
return false;
}
}