| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.ratis.util; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.io.Closeable; |
| import java.io.IOException; |
| import java.io.UncheckedIOException; |
| import java.net.*; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| public interface NetUtils { |
| Logger LOG = LoggerFactory.getLogger(NetUtils.class); |
| |
| abstract class StaticResolution { |
| /** Host -> resolved name */ |
| private static final Map<String, String> HOST_TO_RESOLVED = new ConcurrentHashMap<>(); |
| |
| /** Adds a static resolution for host. */ |
| public static void put(String host, String resolvedName) { |
| HOST_TO_RESOLVED.put(host, resolvedName); |
| } |
| |
| /** @return the resolved name, or null if the host is not found. */ |
| public static String get(String host) { |
| return HOST_TO_RESOLVED.get(host); |
| } |
| } |
| |
| /** The same as createSocketAddr(target, -1). */ |
| static InetSocketAddress createSocketAddr(String target) { |
| return createSocketAddr(target, -1); |
| } |
| |
| /** |
| * Create an InetSocketAddress from the given target and default port. |
| * @param target a string of either "host", "host:port" or "scheme://host:port/path" |
| * @param defaultPort the default port if <code>target</code> does not |
| * include a port number |
| */ |
| static InetSocketAddress createSocketAddr(String target, int defaultPort) { |
| target = Objects.requireNonNull(target, "target == null").trim(); |
| boolean hasScheme = target.contains("://"); |
| if (!hasScheme && target.charAt(0) == '/') { |
| target = target.substring(1); |
| } |
| final URI uri; |
| try { |
| uri = new URI(hasScheme? target: "dummy://"+target); |
| } catch (URISyntaxException e) { |
| throw new IllegalArgumentException("Failed to create URI from target " + target, e); |
| } |
| |
| final String host = uri.getHost(); |
| int port = uri.getPort(); |
| if (port == -1) { |
| port = defaultPort; |
| } |
| final String path = uri.getPath(); |
| |
| if (host == null) { |
| throw new IllegalArgumentException("Host is null in " + target); |
| } else if (port < 0) { |
| throw new IllegalArgumentException("Port = " + port + " < 0 in " + target); |
| } else if (!hasScheme && path != null && !path.isEmpty()) { |
| throw new IllegalArgumentException("Unexpected path in " + target); |
| } |
| return createSocketAddrForHost(host, port); |
| } |
| |
| /** |
| * Create a socket address with the given host and port. The hostname |
| * might be replaced with another host that was set via |
| * {@link StaticResolution#put(String, String)}. |
| * @param host the hostname or IP use to instantiate the object |
| * @param port the port number |
| * @return InetSocketAddress |
| */ |
| static InetSocketAddress createSocketAddrForHost(String host, int port) { |
| String staticHost = StaticResolution.get(host); |
| String resolveHost = (staticHost != null) ? staticHost : host; |
| |
| InetSocketAddress addr; |
| try { |
| InetAddress iaddr = InetAddress.getByName(resolveHost); |
| // if there is a static entry for the host, make the returned |
| // address look like the original given host |
| if (staticHost != null) { |
| iaddr = InetAddress.getByAddress(host, iaddr.getAddress()); |
| } |
| addr = new InetSocketAddress(iaddr, port); |
| } catch (UnknownHostException e) { |
| addr = InetSocketAddress.createUnresolved(host, port); |
| } |
| return addr; |
| } |
| |
| /** |
| * Creates {@code count} unique local addresses. They may conflict with |
| * addresses created later, but not with one another. Addresses are |
| * guaranteed to be bound to the loopback interface. |
| * @param count number of unique local addresses to create |
| * @return {@code count} number of unique local addresses |
| */ |
| static List<InetSocketAddress> createLocalServerAddress(int count) { |
| List<InetSocketAddress> list = new ArrayList<>(count); |
| List<ServerSocket> sockets = new ArrayList<>(count); |
| try { |
| for (int i = 0; i < count; i++) { |
| ServerSocket s = new ServerSocket(); |
| sockets.add(s); |
| s.setReuseAddress(true); |
| s.bind(new InetSocketAddress(InetAddress.getByName(null), 0), 1); |
| list.add((InetSocketAddress) s.getLocalSocketAddress()); |
| } |
| } catch (IOException e) { |
| throw new UncheckedIOException(e); |
| } finally { |
| IOUtils.cleanup(null, sockets.toArray(new Closeable[0])); |
| } |
| return list; |
| } |
| |
| /** |
| * Creates a unique local address. Addresses are guaranteed to be bound to |
| * the loopback interface. |
| * @return unique local address |
| */ |
| static InetSocketAddress createLocalServerAddress() { |
| try(ServerSocket s = new ServerSocket()) { |
| s.setReuseAddress(true); |
| s.bind(new InetSocketAddress(InetAddress.getByName(null), 0), 1); |
| return (InetSocketAddress) s.getLocalSocketAddress(); |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| static String address2String(InetSocketAddress address) { |
| if (address == null) { |
| return null; |
| } |
| final StringBuilder b = new StringBuilder(address.getHostName()); |
| if (address.getAddress() instanceof Inet6Address) { |
| b.insert(0, '[').append(']'); |
| } |
| return b.append(':').append(address.getPort()).toString(); |
| } |
| } |