001/* Inet6Address.java --
002   Copyright (C) 2002, 2003, 2004, 2006 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 gnu.java.lang.CPStringBuilder;
042
043import java.util.Arrays;
044import java.io.ObjectInputStream;
045import java.io.ObjectOutputStream;
046import 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 */
055public 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}