/*
* Copyright (c) 2013-2017 Cinchapi Inc.
*
* 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.cinchapi.concourse.util;
import java.io.IOException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.SocketException;
import java.net.URL;
import java.net.UnknownHostException;
import com.google.common.base.Throwables;
/**
* Utilities for dealing with networking.
*
* @author Jeff Nelson
*/
public final class Networking {
/**
* Return the <em>companion</em> port for the specified one. The companion
* port is one between {@value #MIN_PORT} and {@value #MAX_PORT} that is
* guaranteed to be different from {@code port}.
*
* @param port
* @return the companion port
*/
public static int getCompanionPort(int port) {
return port < PORT_RANGE ? MIN_PORT + port : (port % PORT_RANGE)
+ MIN_PORT;
}
/**
* Return the <em>companion</em> port for the specified one. The companion
* port is one between {@value #MIN_PORT} and {@value #MAX_PORT} that is
* guaranteed to be different from {@code port}.
*
* @param port
* @param rounds
* @return the companion port
*/
public static int getCompanionPort(int port, int rounds) {
for (int i = 0; i < rounds; i++) {
port = getCompanionPort(port);
}
return port;
}
/**
* Get the accessible IP Address for the {@code host}.
*
* @param host
* @return the ip address
*/
public static String getIpAddress(String host) {
try {
if(host.equalsIgnoreCase("localhost")
|| host.equalsIgnoreCase("127.0.0.1")
|| host.equalsIgnoreCase("0.0.0.0")) {
return InetAddress.getLocalHost().getHostAddress();
}
if(host.startsWith("http") || host.startsWith("https")) {
host = new URL(host).getHost();
}
return InetAddress.getByName(host).getHostAddress();
}
catch (UnknownHostException | MalformedURLException e) {
throw Throwables.propagate(e);
}
}
/**
* Get an open port on the local machine in the port range between
* {@value #MIN_PORT} and {@value #MAX_PORT}.
*
* @return the port
*/
public static int getOpenPort() {
int port = RAND.nextInt(MIN_PORT) + (PORT_RANGE);
return isOpenPort(port) ? port : getOpenPort();
}
/**
* Return {@code true} if the {@code host} belongs to the local machine.
*
* @param host
* @return {@code true} if the {@code host} is local
*/
public static boolean isLocalHost(String host) {
try {
InetAddress inet = InetAddress.getByName(host);
if(inet.isAnyLocalAddress() || inet.isLoopbackAddress()) {
return true;
}
else {
return NetworkInterface.getByInetAddress(inet) != null;
}
}
catch (SocketException | UnknownHostException e) {
return false;
}
}
/**
* Return {@code true} if the {@code port} is available on the local
* machine.
*
* @param port
* @return {@code true} if the port is available
*/
private static boolean isOpenPort(int port) {
try {
new ServerSocket(port).close();
return true;
}
catch (SocketException e) {
return false;
}
catch (IOException e) {
throw Throwables.propagate(e);
}
}
/**
* Regex to match an IP Address.
*/
public static final String IP_REGEX = "(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
/**
* The max port number that can be assigned from the
* {@link #getCompanionPort(int)} method.
*/
private static final int MAX_PORT = 65535;
/**
* The min port number that can be assigned from the
* {@link #getCompanionPort(int)} method.
*/
private static final int MIN_PORT = 49152;
/**
* The number of available ports that can be considered "companion" ports.
*/
private static final int PORT_RANGE = MAX_PORT - MIN_PORT;
/**
* Class wide random number generator
*/
private static final java.util.Random RAND = new java.util.Random();
private Networking() {/* noop */}
}