001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase.util;
020
021import java.net.Inet4Address;
022import java.net.Inet6Address;
023import java.net.InetAddress;
024import java.net.InetSocketAddress;
025import java.net.NetworkInterface;
026import java.net.SocketException;
027import java.util.Enumeration;
028
029import org.apache.yetus.audience.InterfaceAudience;
030
031/**
032 * Utility for network addresses, resolving and naming.
033 */
034@InterfaceAudience.Private
035public class Addressing {
036  public static final String VALID_PORT_REGEX = "[\\d]+";
037  public static final String HOSTNAME_PORT_SEPARATOR = ":";
038
039  /**
040   * @param hostAndPort Formatted as <code>&lt;hostname&gt; ':' &lt;port&gt;</code>
041   * @return An InetSocketInstance
042   */
043  public static InetSocketAddress createInetSocketAddressFromHostAndPortStr(
044      final String hostAndPort) {
045    return new InetSocketAddress(parseHostname(hostAndPort), parsePort(hostAndPort));
046  }
047
048  /**
049   * @param hostname Server hostname
050   * @param port Server port
051   * @return Returns a concatenation of <code>hostname</code> and
052   * <code>port</code> in following
053   * form: <code>&lt;hostname&gt; ':' &lt;port&gt;</code>.  For example, if hostname
054   * is <code>example.org</code> and port is 1234, this method will return
055   * <code>example.org:1234</code>
056   */
057  public static String createHostAndPortStr(final String hostname, final int port) {
058    return hostname + HOSTNAME_PORT_SEPARATOR + port;
059  }
060
061  /**
062   * @param hostAndPort Formatted as <code>&lt;hostname&gt; ':' &lt;port&gt;</code>
063   * @return The hostname portion of <code>hostAndPort</code>
064   */
065  public static String parseHostname(final String hostAndPort) {
066    int colonIndex = hostAndPort.lastIndexOf(HOSTNAME_PORT_SEPARATOR);
067    if (colonIndex < 0) {
068      throw new IllegalArgumentException("Not a host:port pair: " + hostAndPort);
069    }
070    return hostAndPort.substring(0, colonIndex);
071  }
072
073  /**
074   * @param hostAndPort Formatted as <code>&lt;hostname&gt; ':' &lt;port&gt;</code>
075   * @return The port portion of <code>hostAndPort</code>
076   */
077  public static int parsePort(final String hostAndPort) {
078    int colonIndex = hostAndPort.lastIndexOf(HOSTNAME_PORT_SEPARATOR);
079    if (colonIndex < 0) {
080      throw new IllegalArgumentException("Not a host:port pair: " + hostAndPort);
081    }
082    return Integer.parseInt(hostAndPort.substring(colonIndex + 1));
083  }
084
085  public static InetAddress getIpAddress() throws SocketException {
086    return getIpAddress(new AddressSelectionCondition() {
087      @Override
088      public boolean isAcceptableAddress(InetAddress addr) {
089        return addr instanceof Inet4Address || addr instanceof Inet6Address;
090      }
091    });
092  }
093
094  public static InetAddress getIp4Address() throws SocketException {
095    return getIpAddress(new AddressSelectionCondition() {
096      @Override
097      public boolean isAcceptableAddress(InetAddress addr) {
098        return addr instanceof Inet4Address;
099      }
100    });
101  }
102
103  public static InetAddress getIp6Address() throws SocketException {
104    return getIpAddress(new AddressSelectionCondition() {
105      @Override
106      public boolean isAcceptableAddress(InetAddress addr) {
107        return addr instanceof Inet6Address;
108      }
109    });
110  }
111
112  private static InetAddress getIpAddress(AddressSelectionCondition condition) throws
113      SocketException {
114    // Before we connect somewhere, we cannot be sure about what we'd be bound to; however,
115    // we only connect when the message where client ID is, is long constructed. Thus,
116    // just use whichever IP address we can find.
117    Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
118    while (interfaces.hasMoreElements()) {
119      NetworkInterface current = interfaces.nextElement();
120      if (!current.isUp() || current.isLoopback() || current.isVirtual()) continue;
121      Enumeration<InetAddress> addresses = current.getInetAddresses();
122      while (addresses.hasMoreElements()) {
123        InetAddress addr = addresses.nextElement();
124        if (addr.isLoopbackAddress()) continue;
125        if (condition.isAcceptableAddress(addr)) {
126          return addr;
127        }
128      }
129    }
130
131    throw new SocketException("Can't get our ip address, interfaces are: " + interfaces);
132  }
133
134  /**
135   * Given an InetAddress, checks to see if the address is a local address, by comparing the address
136   * with all the interfaces on the node.
137   * @param addr address to check if it is local node's address
138   * @return true if the address corresponds to the local node
139   */
140  public static boolean isLocalAddress(InetAddress addr) {
141    // Check if the address is any local or loop back
142    boolean local = addr.isAnyLocalAddress() || addr.isLoopbackAddress();
143
144    // Check if the address is defined on any interface
145    if (!local) {
146      try {
147        local = NetworkInterface.getByInetAddress(addr) != null;
148      } catch (SocketException e) {
149        local = false;
150      }
151    }
152    return local;
153  }
154
155  /**
156   * Interface for AddressSelectionCondition to check if address is acceptable
157   */
158  public interface AddressSelectionCondition{
159    /**
160     * Condition on which to accept inet address
161     * @param address to check
162     * @return true to accept this address
163     */
164    public boolean isAcceptableAddress(InetAddress address);
165  }
166}