001/* NetworkInterface.java --
002   Copyright (C) 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package java.net;
040
041import java.util.Collection;
042import java.util.Collections;
043import java.util.Enumeration;
044import java.util.HashMap;
045import java.util.Iterator;
046import java.util.Map;
047import java.util.Vector;
048
049/**
050 * This class models a network interface on the host computer.  A network
051 * interface contains a name (typically associated with a specific
052 * hardware adapter) and a list of addresses that are bound to it.
053 * For example, an ethernet interface may be named "eth0" and have the
054 * address 192.168.1.101 assigned to it.
055 *
056 * @author Michael Koch (konqueror@gmx.de)
057 * @since 1.4
058 */
059public final class NetworkInterface
060{
061  private String name;
062  private Vector<InetAddress> inetAddresses;
063
064  NetworkInterface(String name, InetAddress address)
065  {
066    this.name = name;
067    this.inetAddresses = new Vector(1, 1);
068    this.inetAddresses.add(address);
069  }
070
071  NetworkInterface(String name, InetAddress[] addresses)
072  {
073    this.name = name;
074    this.inetAddresses = new Vector(addresses.length, 1);
075
076    for (int i = 0; i < addresses.length; i++)
077      this.inetAddresses.add(addresses[i]);
078  }
079
080  /**
081   * Returns the name of the network interface
082   *
083   * @return The name of the interface.
084   */
085  public String getName()
086  {
087    return name;
088  }
089
090  /**
091   * Returns all available addresses of the network interface
092   *
093   * If a @see SecurityManager is available all addresses are checked
094   * with @see SecurityManager::checkConnect() if they are available.
095   * Only <code>InetAddresses</code> are returned where the security manager
096   * doesn't throw an exception.
097   *
098   * @return An enumeration of all addresses.
099   */
100  public Enumeration<InetAddress> getInetAddresses()
101  {
102    SecurityManager s = System.getSecurityManager();
103
104    if (s == null)
105      return inetAddresses.elements();
106
107    Vector<InetAddress> tmpInetAddresses = new Vector<InetAddress>(1, 1);
108
109    for (Enumeration<InetAddress> addresses = inetAddresses.elements();
110         addresses.hasMoreElements();)
111      {
112        InetAddress addr = addresses.nextElement();
113        try
114          {
115            s.checkConnect(addr.getHostAddress(), 58000);
116            tmpInetAddresses.add(addr);
117          }
118        catch (SecurityException e)
119          {
120            // Ignore.
121          }
122      }
123
124    return tmpInetAddresses.elements();
125  }
126
127  /**
128   * Returns the display name of the interface
129   *
130   * @return The display name of the interface
131   */
132  public String getDisplayName()
133  {
134    return name;
135  }
136
137  /**
138   * Returns an network interface by name
139   *
140   * @param name The name of the interface to return
141   * 
142   * @return a <code>NetworkInterface</code> object representing the interface,
143   * or null if there is no interface with that name.
144   *
145   * @exception SocketException If an error occurs
146   * @exception NullPointerException If the specified name is null
147   */
148  public static NetworkInterface getByName(String name)
149    throws SocketException
150  {
151    for (Enumeration e = getNetworkInterfaces(); e.hasMoreElements();)
152      {
153        NetworkInterface tmp = (NetworkInterface) e.nextElement();
154
155        if (name.equals(tmp.getName()))
156          return tmp;
157      }
158
159    // No interface with the given name found.
160    return null;
161  }
162
163  /**
164   * Return a network interface by its address
165   *
166   * @param addr The address of the interface to return
167   *
168   * @return the interface, or <code>null</code> if none found
169   *
170   * @exception SocketException If an error occurs
171   * @exception NullPointerException If the specified addess is null
172   */
173  public static NetworkInterface getByInetAddress(InetAddress addr)
174    throws SocketException
175  {
176    for (Enumeration interfaces = getNetworkInterfaces();
177         interfaces.hasMoreElements();)
178      {
179        NetworkInterface tmp = (NetworkInterface) interfaces.nextElement();
180
181        for (Enumeration addresses = tmp.inetAddresses.elements();
182             addresses.hasMoreElements();)
183          {
184            if (addr.equals((InetAddress) addresses.nextElement()))
185              return tmp;
186          }
187      }
188
189    throw new SocketException("no network interface is bound to such an IP address");
190  }
191
192  static private Collection condense(Collection interfaces) 
193  {
194    final Map condensed = new HashMap();
195
196    final Iterator interfs = interfaces.iterator();
197    while (interfs.hasNext()) {
198
199      final NetworkInterface face = (NetworkInterface) interfs.next();
200      final String name = face.getName();
201      
202      if (condensed.containsKey(name))
203        {
204          final NetworkInterface conface = (NetworkInterface) condensed.get(name);
205          if (!conface.inetAddresses.containsAll(face.inetAddresses))
206            {
207              final Iterator faceAddresses = face.inetAddresses.iterator();
208              while (faceAddresses.hasNext())
209                {
210                  final InetAddress faceAddress = (InetAddress) faceAddresses.next();
211                  if (!conface.inetAddresses.contains(faceAddress))
212                    {
213                      conface.inetAddresses.add(faceAddress);
214                    }
215                }
216            }
217        }
218      else
219        {
220          condensed.put(name, face);
221        }
222    }
223
224    return condensed.values();
225  }
226
227  /**
228   * Return an <code>Enumeration</code> of all available network interfaces
229   *
230   * @return all interfaces
231   * 
232   * @exception SocketException If an error occurs
233   */
234  public static Enumeration<NetworkInterface> getNetworkInterfaces()
235    throws SocketException
236  {
237    Vector<NetworkInterface> networkInterfaces =
238      VMNetworkInterface.getInterfaces();
239
240    if (networkInterfaces.isEmpty())
241      return null;
242
243    Collection condensed = condense(networkInterfaces);
244
245    return Collections.enumeration(condensed);
246  }
247
248  /**
249   * Checks if the current instance is equal to obj
250   *
251   * @param obj The object to compare with
252   *
253   * @return <code>true</code> if equal, <code>false</code> otherwise
254   */
255  public boolean equals(Object obj)
256  {
257    if (! (obj instanceof NetworkInterface))
258      return false;
259
260    NetworkInterface tmp = (NetworkInterface) obj;
261
262    return (name.equals(tmp.name) && inetAddresses.equals(tmp.inetAddresses));
263  }
264
265  /**
266   * Returns the hashcode of the current instance
267   *
268   * @return the hashcode
269   */
270  public int hashCode()
271  {
272    // FIXME: hash correctly
273    return name.hashCode() + inetAddresses.hashCode();
274  }
275
276  /**
277   * Returns a string representation of the interface
278   *
279   * @return the string
280   */
281  public String toString()
282  {
283    // FIXME: check if this is correct
284    String result;
285    String separator = System.getProperty("line.separator");
286
287    result =
288      "name: " + getDisplayName() + " (" + getName() + ") addresses:"
289      + separator;
290
291    for (Enumeration e = inetAddresses.elements(); e.hasMoreElements();)
292      {
293        InetAddress address = (InetAddress) e.nextElement();
294        result += address.toString() + ";" + separator;
295      }
296
297    return result;
298  }
299}