blob: f921b079fda60b47091a384e3400b545d551cc7e [file] [log] [blame]
/*
* 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 java.net;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Vector;
import org.apache.harmony.luni.util.Msg;
/**
* This class is used to represent a network interface of the local device. An
* interface is defined by its address and a platform dependent name. The class
* provides methods to get all information about the available interfaces of the
* system or to identify the local interface of a joined multicast group.
*/
public final class NetworkInterface extends Object {
private static final int CHECK_CONNECT_NO_PORT = -1;
static final int NO_INTERFACE_INDEX = 0;
static final int UNSET_INTERFACE_INDEX = -1;
private String name;
private String displayName;
InetAddress addresses[];
// The interface index is a positive integer which is non-negative. Where
// value is zero then we do not have an index for the interface (which
// occurs in systems which only support IPV4)
private int interfaceIndex;
private int hashCode;
/**
* This {@code native} method returns the list of network interfaces
* supported by the system. An array is returned which is easier to generate
* and which can easily be converted into the required enumeration on the
* java side.
*
* @return an array of zero or more {@code NetworkInterface} objects
* @throws SocketException
* if an error occurs when getting network interface information
*/
private static native NetworkInterface[] getNetworkInterfacesImpl()
throws SocketException;
/**
* This constructor is used by the native method in order to construct the
* NetworkInterface objects in the array that it returns.
*
* @param name
* internal name associated with the interface.
* @param displayName
* a user interpretable name for the interface.
* @param addresses
* the Internet addresses associated with the interface.
* @param interfaceIndex
* an index for the interface. Only set for platforms that
* support IPV6.
*/
NetworkInterface(String name, String displayName, InetAddress addresses[],
int interfaceIndex) {
this.name = name;
this.displayName = displayName;
this.addresses = addresses;
this.interfaceIndex = interfaceIndex;
}
/**
* Returns the index for the network interface. Unless the system supports
* IPV6 this will be 0.
*
* @return the index
*/
int getIndex() {
return interfaceIndex;
}
/**
* Returns the first address for the network interface. This is used in the
* natives when we need one of the addresses for the interface and any one
* will do
*
* @return the first address if one exists, otherwise null.
*/
InetAddress getFirstAddress() {
if ((addresses != null) && (addresses.length >= 1)) {
return addresses[0];
}
return null;
}
/**
* Gets the name associated with this network interface.
*
* @return the name of this {@code NetworkInterface} instance.
*/
public String getName() {
return name;
}
/**
* Gets a list of addresses bound to this network interface.
*
* @return the address list of the represented network interface.
*/
public Enumeration<InetAddress> getInetAddresses() {
/*
* create new vector from which Enumeration to be returned can be
* generated set the initial capacity to be the number of addresses for
* the network interface which is the maximum required size
*/
/*
* return an empty enumeration if there are no addresses associated with
* the interface
*/
if (addresses == null) {
return new Vector<InetAddress>(0).elements();
}
/*
* for those configuration that support the security manager we only
* return addresses for which checkConnect returns true
*/
Vector<InetAddress> accessibleAddresses = new Vector<InetAddress>(
addresses.length);
/*
* get the security manager. If one does not exist just return the full
* list
*/
SecurityManager security = System.getSecurityManager();
if (security == null) {
return (new Vector<InetAddress>(Arrays.asList(addresses)))
.elements();
}
/*
* ok security manager exists so check each address and return those
* that pass
*/
for (InetAddress element : addresses) {
if (security != null) {
try {
/*
* since we don't have a port in this case we pass in
* NO_PORT
*/
security.checkConnect(element.getHostName(),
CHECK_CONNECT_NO_PORT);
accessibleAddresses.add(element);
} catch (SecurityException e) {
}
}
}
Enumeration<InetAddress> theAccessibleElements = accessibleAddresses
.elements();
if (theAccessibleElements.hasMoreElements()) {
return accessibleAddresses.elements();
}
return new Vector<InetAddress>(0).elements();
}
/**
* Gets the human-readable name associated with this network interface.
*
* @return the display name of this network interface or the name if the
* display name is not available.
*/
public String getDisplayName() {
/*
* we should return the display name unless it is blank in this case
* return the name so that something is displayed.
*/
if (!(displayName.equals(""))) { //$NON-NLS-1$
return displayName;
}
return name;
}
/**
* Gets the specific network interface according to a given name.
*
* @param interfaceName
* the name to identify the searched network interface.
* @return the network interface with the specified name if one exists or
* {@code null} otherwise.
* @throws SocketException
* if an error occurs while getting the network interface
* information.
* @throws NullPointerException
* if the given interface's name is {@code null}.
*/
public static NetworkInterface getByName(String interfaceName)
throws SocketException {
if (interfaceName == null) {
throw new NullPointerException(Msg.getString("K0330")); //$NON-NLS-1$
}
/*
* get the list of interfaces, and then loop through the list to look
* for one with a matching name
*/
Enumeration<NetworkInterface> interfaces = getNetworkInterfaces();
if (interfaces != null) {
while (interfaces.hasMoreElements()) {
NetworkInterface netif = interfaces.nextElement();
if (netif.getName().equals(interfaceName)) {
return netif;
}
}
}
return null;
}
/**
* Gets the specific network interface according to the given address.
*
* @param address
* the address to identify the searched network interface.
* @return the network interface with the specified address if one exists or
* {@code null} otherwise.
* @throws SocketException
* if an error occurs while getting the network interface
* information.
* @throws NullPointerException
* if the given interface address is invalid.
*/
public static NetworkInterface getByInetAddress(InetAddress address)
throws SocketException {
if (address == null) {
throw new NullPointerException(Msg.getString("K0331")); //$NON-NLS-1$
}
/*
* get the list of interfaces, and then loop through the list. For each
* interface loop through the associated set of internet addresses and
* see if one matches. If so return that network interface
*/
Enumeration<NetworkInterface> interfaces = getNetworkInterfaces();
if (interfaces != null) {
while (interfaces.hasMoreElements()) {
NetworkInterface netif = interfaces.nextElement();
/*
* to be compatible use the raw addresses without any security
* filtering
*/
// Enumeration netifAddresses = netif.getInetAddresses();
if ((netif.addresses != null) && (netif.addresses.length != 0)) {
Enumeration<InetAddress> netifAddresses = (new Vector<InetAddress>(
Arrays.asList(netif.addresses))).elements();
if (netifAddresses != null) {
while (netifAddresses.hasMoreElements()) {
if (address.equals(netifAddresses.nextElement())) {
return netif;
}
}
}
}
}
}
return null;
}
/**
* Gets a list of all network interfaces available on the local system or
* {@code null} if no interface is available.
*
* @return the list of {@code NetworkInterface} instances representing the
* available interfaces.
* @throws SocketException
* if an error occurs while getting the network interface
* information.
*/
public static Enumeration<NetworkInterface> getNetworkInterfaces()
throws SocketException {
NetworkInterface[] interfaces = getNetworkInterfacesImpl();
if (interfaces == null) {
return null;
}
for (NetworkInterface netif : interfaces) {
// Ensure that current NetworkInterface is bound to at least
// one InetAddress before processing
if (netif.addresses != null) {
for (InetAddress addr : netif.addresses) {
if (16 == addr.ipaddress.length) {
if (addr.isLinkLocalAddress()
|| addr.isSiteLocalAddress()) {
((Inet6Address) addr).scopedIf = netif;
((Inet6Address) addr).ifname = netif.name;
((Inet6Address) addr).scope_ifname_set = true;
}
}
}
}
}
return (new Vector<NetworkInterface>(Arrays.asList(interfaces)))
.elements();
}
/**
* Compares the specified object to this {@code NetworkInterface} and
* returns whether they are equal or not. The object must be an instance of
* {@code NetworkInterface} with the same name, {@code displayName} and list
* of network interfaces to be equal.
*
* @param obj
* the object to compare with this instance.
* @return {@code true} if the specified object is equal to this {@code
* NetworkInterface}, {@code false} otherwise.
* @see #hashCode()
*/
@Override
public boolean equals(Object obj) {
// Return true if it is the exact same object.
if (obj == this) {
return true;
}
// Ensure it is the right type.
if (!(obj instanceof NetworkInterface)) {
return false;
}
/*
* Make sure that some simple checks pass. If the name is not the same
* then we are sure it is not the same one. We don't check the hashcode
* as it is generated from the name which we check
*/
NetworkInterface netif = (NetworkInterface) obj;
if (netif.getIndex() != interfaceIndex) {
return false;
}
if (!(name.equals("")) && (!netif.getName().equals(name))) { //$NON-NLS-1$
return false;
}
if ((name.equals("")) && (!netif.getName().equals(displayName))) { //$NON-NLS-1$
return false;
}
// Now check that the collection of internet addresses are equal.
Enumeration<InetAddress> netifAddresses = netif.getInetAddresses();
Enumeration<InetAddress> localifAddresses = getInetAddresses();
// Check for both null (same), or one null (not same).
if (netifAddresses == null) {
return localifAddresses == null;
}
if (localifAddresses == null) {
return false;
}
// Both are not null, check InetAddress elements.
while (netifAddresses.hasMoreElements()
&& localifAddresses.hasMoreElements()) {
if (!(localifAddresses.nextElement()).equals(
netifAddresses.nextElement())) {
return false;
}
}
/*
* Now make sure that they had the same number of addresses, if not they
* are not the same interface.
*/
return !netifAddresses.hasMoreElements()
&& !localifAddresses.hasMoreElements();
}
/**
* Gets the hashcode for this {@code NetworkInterface} instance. Since the
* name should be unique for each network interface the hashcode is
* generated using this name.
*
* @return the hashcode value for this {@code NetworkInterface} instance.
*/
@Override
public int hashCode() {
if (hashCode == 0) {
hashCode = name.hashCode();
}
return hashCode;
}
/**
* Gets a string containing a concise, human-readable description of this
* network interface.
*
* @return the textual representation for this network interface.
*/
@Override
public String toString() {
StringBuilder string = new StringBuilder(25);
string.append("["); //$NON-NLS-1$
string.append(name);
string.append("]["); //$NON-NLS-1$
string.append(displayName);
string.append("]"); //$NON-NLS-1$
/*
* get the addresses through this call to make sure we only reveal those
* that we should
*/
Enumeration<InetAddress> theAddresses = getInetAddresses();
if (theAddresses != null) {
while (theAddresses.hasMoreElements()) {
InetAddress nextAddress = theAddresses.nextElement();
string.append("["); //$NON-NLS-1$
string.append(nextAddress.toString());
string.append("]"); //$NON-NLS-1$
}
}
return string.toString();
}
}