001    /* NetworkInterface.java --
002       Copyright (C) 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.net;
040    
041    import java.util.Collection;
042    import java.util.Collections;
043    import java.util.Enumeration;
044    import java.util.HashMap;
045    import java.util.Iterator;
046    import java.util.Map;
047    import 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     */
059    public 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    }