001    /* Inet6Address.java --
002       Copyright (C) 2002, 2003, 2004, 2006 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.Arrays;
042    import java.io.ObjectInputStream;
043    import java.io.ObjectOutputStream;
044    import java.io.IOException;
045    
046    /*
047     * Written using on-line Java Platform 1.4 API Specification and
048     * RFC 1884 (http://www.ietf.org/rfc/rfc1884.txt)
049     * 
050     * @author Michael Koch
051     * @status Updated to 1.5. Serialization compatibility is tested.
052     */
053    public final class Inet6Address extends InetAddress
054    {
055      static final long serialVersionUID = 6880410070516793377L;
056    
057      /**
058       * Needed for serialization
059       */
060      byte[] ipaddress;
061    
062      /**
063       * The scope ID, if any. 
064       * @since 1.5
065       * @serial 
066       */
067      private int scope_id;
068    
069      /**
070       * The scope ID, if any. 
071       * @since 1.5
072       * @serial 
073       */
074      private boolean scope_id_set;
075    
076      /**
077       * Whether ifname is set or not.
078       * @since 1.5
079       * @serial 
080       */
081      private boolean scope_ifname_set;
082    
083      /**
084       * Name of the network interface, used only by the serialization methods
085       * @since 1.5
086       * @serial 
087       */
088      private String ifname;
089    
090      /**
091       * Scope network interface, or <code>null</code>.
092       */
093      private transient NetworkInterface nif; 
094    
095      /**
096       * The address family of these addresses (used for serialization).
097       */
098      private static final int AF_INET6 = 10;
099    
100      /**
101       * Create an Inet6Address object
102       *
103       * @param addr The IP address
104       * @param host The hostname
105       */
106      Inet6Address(byte[] addr, String host)
107      {
108        super(addr, host, AF_INET6);
109        // Super constructor clones the addr.  Get a reference to the clone.
110        this.ipaddress = this.addr;
111        ifname = null;
112        scope_ifname_set = scope_id_set = false;
113        scope_id = 0;
114        nif = null;
115      }
116    
117      /**
118       * Utility routine to check if the InetAddress is an IP multicast address
119       *
120       * @since 1.1
121       */
122      public boolean isMulticastAddress()
123      {
124        return ipaddress[0] == (byte) 0xFF;
125      }
126    
127      /**
128       * Utility routine to check if the InetAddress in a wildcard address
129       *
130       * @since 1.4
131       */
132      public boolean isAnyLocalAddress()
133      {
134        byte[] anylocal = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
135    
136        return Arrays.equals(ipaddress, anylocal);
137      }
138    
139      /**
140       * Utility routine to check if the InetAddress is a loopback address
141       *
142       * @since 1.4
143       */
144      public boolean isLoopbackAddress()
145      {
146        byte[] loopback = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
147    
148        return Arrays.equals(ipaddress, loopback);
149      }
150    
151      /**
152       * Utility routine to check if the InetAddress is an link local address
153       *
154       * @since 1.4
155       */
156      public boolean isLinkLocalAddress()
157      {
158        return ipaddress[0] == 0xFA;
159      }
160    
161      /**
162       * Utility routine to check if the InetAddress is a site local address
163       *
164       * @since 1.4
165       */
166      public boolean isSiteLocalAddress()
167      {
168        return ipaddress[0] == 0xFB;
169      }
170    
171      /**
172       * Utility routine to check if the multicast address has global scope
173       *
174       * @since 1.4
175       */
176      public boolean isMCGlobal()
177      {
178        if (! isMulticastAddress())
179          return false;
180    
181        return (ipaddress[1] & 0x0F) == 0xE;
182      }
183    
184      /**
185       * Utility routine to check if the multicast address has node scope
186       *
187       * @since 1.4
188       */
189      public boolean isMCNodeLocal()
190      {
191        if (! isMulticastAddress())
192          return false;
193    
194        return (ipaddress[1] & 0x0F) == 0x1;
195      }
196    
197      /**
198       * Utility routine to check if the multicast address has link scope
199       *
200       * @since 1.4
201       */
202      public boolean isMCLinkLocal()
203      {
204        if (! isMulticastAddress())
205          return false;
206    
207        return (ipaddress[1] & 0x0F) == 0x2;
208      }
209    
210      /**
211       * Utility routine to check if the multicast address has site scope
212       *
213       * @since 1.4
214       */
215      public boolean isMCSiteLocal()
216      {
217        if (! isMulticastAddress())
218          return false;
219    
220        return (ipaddress[1] & 0x0F) == 0x5;
221      }
222    
223      /**
224       * Utility routine to check if the multicast address has organization scope
225       *
226       * @since 1.4
227       */
228      public boolean isMCOrgLocal()
229      {
230        if (! isMulticastAddress())
231          return false;
232    
233        return (ipaddress[1] & 0x0F) == 0x8;
234      }
235    
236      /**
237       * Returns the raw IP address of this InetAddress object. The result is in
238       * network byte order: the highest order byte of the address is i
239       * n getAddress()[0]
240       */
241      public byte[] getAddress()
242      {
243        return (byte[]) ipaddress.clone();
244      }
245    
246      /**
247       * Creates a scoped Inet6Address where the scope has an integer id.
248       *
249       * @throws UnkownHostException if the address is an invalid number of bytes.
250       * @since 1.5
251       */  
252      public static Inet6Address getByAddress(String host, byte[] addr, 
253                                              int scopeId)
254        throws UnknownHostException
255      {
256        if( addr.length != 16 )
257          throw new UnknownHostException("Illegal address length: " + addr.length
258                                         + " bytes.");
259        Inet6Address ip = new Inet6Address( addr, host );
260        ip.scope_id = scopeId;
261        ip.scope_id_set = true;
262        return ip;
263      }
264    
265      /**
266       * Creates a scoped Inet6Address where the scope is a given
267       * NetworkInterface.
268       *
269       * @throws UnkownHostException if the address is an invalid number of bytes.
270       * @since 1.5
271       */  
272      public static Inet6Address getByAddress(String host, byte[] addr, 
273                                              NetworkInterface nif)
274        throws UnknownHostException
275      {
276        if( addr.length != 16 )
277          throw new UnknownHostException("Illegal address length: " + addr.length
278                                         + " bytes.");
279        Inet6Address ip = new Inet6Address( addr, host );
280        ip.nif = nif;
281    
282        return ip;
283      }
284    
285      /**
286       * Returns the <code>NetworkInterface</code> of the address scope
287       * if it is a scoped address and the scope is given in the form of a
288       * NetworkInterface. 
289       * (I.e. the address was created using  the 
290       * getByAddress(String, byte[], NetworkInterface) method)
291       * Otherwise this method returns <code>null</code>.
292       * @since 1.5
293       */
294      public NetworkInterface getScopedInterface()
295      {
296        return nif;
297      }
298    
299      /**
300       * Returns the scope ID of the address scope if it is a scoped adress using
301       * an integer to identify the scope.
302       *
303       * Otherwise this method returns 0.
304       * @since 1.5
305       */
306      public int getScopeId()
307      {
308        // check scope_id_set because some JDK-serialized objects seem to have
309        // scope_id set to a nonzero value even when scope_id_set == false
310        if( scope_id_set )
311          return scope_id; 
312        return 0;
313      }
314    
315      /**
316       * Returns the IP address string in textual presentation
317       */
318      public String getHostAddress()
319      {
320        StringBuffer sbuf = new StringBuffer(40);
321    
322        for (int i = 0; i < 16; i += 2)
323          {
324            int x = ((ipaddress[i] & 0xFF) << 8) | (ipaddress[i + 1] & 0xFF);
325    
326            if (i > 0)
327              sbuf.append(':');
328    
329            sbuf.append(Integer.toHexString(x));
330          }
331        if( nif != null )
332          sbuf.append( "%" + nif.getName() );
333        else if( scope_id_set )
334          sbuf.append( "%" + scope_id );
335    
336        return sbuf.toString();
337      }
338    
339      /**
340       * Returns a hashcode for this IP address
341       * (The hashcode is independent of scope)
342       */
343      public int hashCode()
344      {
345        return super.hashCode();
346      }
347    
348      /**
349       * Compares this object against the specified object
350       */
351      public boolean equals(Object obj)
352      {
353        if (! (obj instanceof Inet6Address))
354          return false;
355    
356        Inet6Address ip = (Inet6Address)obj;
357        if (ipaddress.length != ip.ipaddress.length)
358          return false;
359    
360        for (int i = 0; i < ip.ipaddress.length; i++)
361          if (ipaddress[i] != ip.ipaddress[i])
362            return false;
363    
364        if( ip.nif != null && nif != null )
365          return nif.equals( ip.nif );
366        if( ip.nif != nif )
367          return false;
368        if( ip.scope_id_set != scope_id_set )
369          return false;
370        if( scope_id_set )
371          return (scope_id == ip.scope_id);
372        return true;
373      }
374    
375      /**
376       * Utility routine to check if the InetAddress is an
377       * IPv4 compatible IPv6 address
378       *
379       * @since 1.4
380       */
381      public boolean isIPv4CompatibleAddress()
382      {
383        if (ipaddress[0] != 0x00 || ipaddress[1] != 0x00 || ipaddress[2] != 0x00
384            || ipaddress[3] != 0x00 || ipaddress[4] != 0x00
385            || ipaddress[5] != 0x00 || ipaddress[6] != 0x00
386            || ipaddress[7] != 0x00 || ipaddress[8] != 0x00
387            || ipaddress[9] != 0x00 || ipaddress[10] != 0x00
388            || ipaddress[11] != 0x00)
389          return false;
390    
391        return true;
392      }
393    
394      /**
395       * Required for 1.5-compatible serialization.
396       * @since 1.5
397       */
398      private void readObject(ObjectInputStream s)
399        throws IOException, ClassNotFoundException
400      {  
401        s.defaultReadObject();
402        try
403          {
404            if( scope_ifname_set )
405              nif = NetworkInterface.getByName( ifname );
406          }
407        catch( SocketException se )
408          {
409            // FIXME: Ignore this? or throw an IOException?
410          }
411      }
412    
413      /**
414       * Required for 1.5-compatible serialization.
415       * @since 1.5
416       */
417      private void writeObject(ObjectOutputStream s)
418        throws IOException
419      {
420        if( nif != null )
421          {
422            ifname = nif.getName();
423            scope_ifname_set = true;
424          }
425        s.defaultWriteObject();
426      }
427    }