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