OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / java / net / Inet6Address.java
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17
18 package java.net;
19
20 import java.io.IOException;
21 import java.io.ObjectInputStream;
22 import java.io.ObjectOutputStream;
23 import java.io.ObjectStreamField;
24 import java.util.Enumeration;
25
26 /**
27  * An IPv6 address. See {@link InetAddress}.
28  */
29 public final class Inet6Address extends InetAddress {
30
31     private static final long serialVersionUID = 6880410070516793377L;
32
33     private static final int AF_INET6 = 10;
34
35     static final InetAddress ANY = new Inet6Address(new byte[]
36             {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 });
37     static final InetAddress LOOPBACK = new Inet6Address(new byte[]
38             {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, "localhost");
39
40     int scope_id;
41
42     boolean scope_id_set;
43
44     boolean scope_ifname_set;
45
46     String ifname;
47
48     /*
49      * scoped interface.
50      */
51     transient NetworkInterface scopedIf;
52
53     Inet6Address(byte[] address) {
54         family = AF_INET6;
55         ipaddress = address;
56         scope_id = 0;
57     }
58
59     Inet6Address(byte[] address, String name) {
60         family = AF_INET6;
61         hostName = name;
62         ipaddress = address;
63         scope_id = 0;
64     }
65
66     /**
67      * Constructs an {@code InetAddress} representing the {@code address} and
68      * {@code name} and {@code scope_id}.
69      *
70      * @param address
71      *            the network address.
72      * @param name
73      *            the name associated with the address.
74      * @param scope_id
75      *            the scope id for link- or site-local addresses.
76      */
77     Inet6Address(byte[] address, String name, int scope_id) {
78         family = AF_INET6;
79         hostName = name;
80         ipaddress = address;
81         this.scope_id = scope_id;
82         if (scope_id != 0) {
83             scope_id_set = true;
84         }
85     }
86
87     /**
88      * Constructs an IPv6 address according to the given {@code host}, {@code
89      * addr} and {@code scope_id}.
90      *
91      * @param host
92      *            the host name associated with the address.
93      * @param addr
94      *            the network address.
95      * @param scope_id
96      *            the scope id for link- or site-local addresses.
97      * @return the Inet6Address instance representing the IP address.
98      * @throws UnknownHostException
99      *             if the address is null or has an invalid length.
100      */
101     public static Inet6Address getByAddress(String host, byte[] addr,
102             int scope_id) throws UnknownHostException {
103         if (addr == null || addr.length != 16) {
104             throw new UnknownHostException("Illegal IPv6 address");
105         }
106         if (scope_id < 0) {
107             scope_id = 0;
108         }
109         return new Inet6Address(addr, host, scope_id);
110     }
111
112     /**
113      * Gets an IPv6 address instance according to the given {@code host},
114      * {@code addr} and {@code nif}. {@code scope_id} is set according to the
115      * given {@code nif} and the {@code addr} type (for example site-local or
116      * link-local).
117      *
118      * @param host
119      *            the hostname associated with the address.
120      * @param addr
121      *            the network address.
122      * @param nif
123      *            the network interface that this address is associated with.
124      * @return the Inet6Address instance representing the IP address.
125      * @throws UnknownHostException
126      *             if the address is {@code null} or has an invalid length or
127      *             the interface doesn't have a numeric scope id for the given
128      *             address type.
129      */
130     public static Inet6Address getByAddress(String host, byte[] addr,
131             NetworkInterface nif) throws UnknownHostException {
132
133         Inet6Address address = Inet6Address.getByAddress(host, addr, 0);
134
135         // if nif is null, nothing needs to be set.
136         if (null == nif) {
137             return address;
138         }
139
140         // find the first address which matches the type addr,
141         // then set the scope_id, ifname and scopedIf.
142         Enumeration<InetAddress> addressList = nif.getInetAddresses();
143         while (addressList.hasMoreElements()) {
144             InetAddress ia = addressList.nextElement();
145             if (ia.getAddress().length == 16) {
146                 Inet6Address v6ia = (Inet6Address) ia;
147                 boolean isSameType = v6ia.compareLocalType(address);
148                 if (isSameType) {
149                     address.scope_id_set = true;
150                     address.scope_id = v6ia.scope_id;
151                     address.scope_ifname_set = true;
152                     address.ifname = nif.getName();
153                     address.scopedIf = nif;
154                     break;
155                 }
156             }
157         }
158         // if no address matches the type of addr, throws an
159         // UnknownHostException.
160         if (!address.scope_id_set) {
161             throw new UnknownHostException("Scope id not found for the given address");
162         }
163         return address;
164     }
165
166     /**
167      * Returns {@code true} if one of following cases applies:
168      * <p>
169      * <ol>
170      *  <li>both addresses are site local</li>
171      *  <li>both addresses are link local</li>
172      *  <li>{@code ia} is neither site local nor link local</li>
173      * </ol>
174      */
175     private boolean compareLocalType(Inet6Address ia) {
176         if (ia.isSiteLocalAddress() && isSiteLocalAddress()) {
177             return true;
178         }
179         if (ia.isLinkLocalAddress() && isLinkLocalAddress()) {
180             return true;
181         }
182         if (!ia.isSiteLocalAddress() && !ia.isLinkLocalAddress()) {
183             return true;
184         }
185         return false;
186     }
187
188     /**
189      * Constructs an {@code InetAddress} representing the {@code address} and
190      * {@code scope_id}.
191      *
192      * @param address
193      *            the network address.
194      * @param scope_id
195      *            the scope id for link- or site-local addresses.
196      */
197     Inet6Address(byte[] address, int scope_id) {
198         ipaddress = address;
199         this.scope_id = scope_id;
200         if (scope_id != 0) {
201             scope_id_set = true;
202         }
203     }
204
205     /**
206      * Returns whether this address is an IP multicast address or not. Valid
207      * IPv6 multicast addresses are binary prefixed with 11111111 or FF (hex).
208      *
209      * @return {@code true} if this address is in the multicast group, {@code
210      *         false} otherwise.
211      */
212     @Override
213     public boolean isMulticastAddress() {
214         // Multicast addresses are prefixed with 11111111 (255)
215         return ipaddress[0] == -1;
216     }
217
218     /**
219      * Returns whether this address is a unspecified wildcard address "::" or
220      * not.
221      *
222      * @return {@code true} if this instance represents a wildcard address,
223      *         {@code false} otherwise.
224      */
225     @Override
226     public boolean isAnyLocalAddress() {
227         for (int i = 0; i < ipaddress.length; i++) {
228             if (ipaddress[i] != 0) {
229                 return false;
230             }
231         }
232         return true;
233     }
234
235     /**
236      * Returns whether this address is the loopback address or not. The only
237      * valid IPv6 loopback address is "::1".
238      *
239      * @return {@code true} if this instance represents the loopback address,
240      *         {@code false} otherwise.
241      */
242     @Override
243     public boolean isLoopbackAddress() {
244
245         // The last word must be 1
246         if (ipaddress[15] != 1) {
247             return false;
248         }
249
250         // All other words must be 0
251         for (int i = 0; i < 15; i++) {
252             if (ipaddress[i] != 0) {
253                 return false;
254             }
255         }
256
257         return true;
258     }
259
260     /**
261      * Returns whether this address is a link-local address or not. A valid IPv6
262      * link-local address is prefixed with 1111111010.
263      *
264      * @return {@code true} if this instance represents a link-local address,
265      *         {@code false} otherwise.
266      */
267     @Override
268     public boolean isLinkLocalAddress() {
269
270         // the first 10 bits need to be 1111111010 (1018)
271         return (ipaddress[0] == -2) && ((ipaddress[1] & 255) >>> 6) == 2;
272     }
273
274     /**
275      * Returns whether this address is a site-local address or not. A valid IPv6
276      * site-local address is prefixed with 1111111011.
277      *
278      * @return {@code true} if this instance represents a site-local address,
279      *         {@code false} otherwise.
280      */
281     @Override
282     public boolean isSiteLocalAddress() {
283
284         // the first 10 bits need to be 1111111011 (1019)
285         return (ipaddress[0] == -2) && ((ipaddress[1] & 255) >>> 6) == 3;
286     }
287
288     /**
289      * Returns whether this address is a global multicast address or not. A
290      * valid IPv6 global multicast address is 11111111xxxx1110 or FF0E hex.
291      *
292      * @return {@code true} if this instance represents a global multicast
293      *         address, {@code false} otherwise.
294      */
295     @Override
296     public boolean isMCGlobal() {
297         // the first byte should be 0xFF and the lower 4 bits
298         // of the second byte should be 0xE
299         return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 14;
300     }
301
302     /**
303      * Returns whether this address is a node-local multicast address or not. A
304      * valid IPv6 node-local multicast address is prefixed with
305      * 11111111xxxx0001.
306      *
307      * @return {@code true} if this instance represents a node-local multicast
308      *         address, {@code false} otherwise.
309      */
310     @Override
311     public boolean isMCNodeLocal() {
312         // the first byte should be 0xFF and the lower 4 bits
313         // of the second byte should be 0x1
314         return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 1;
315     }
316
317     /**
318      * Returns whether this address is a link-local multicast address or not. A
319      * valid IPv6 link-local multicast address is prefixed with
320      * 11111111xxxx0010.
321      *
322      * @return {@code true} if this instance represents a link-local multicast
323      *         address, {@code false} otherwise.
324      */
325     @Override
326     public boolean isMCLinkLocal() {
327         // the first byte should be 0xFF and the lower 4 bits
328         // of the second byte should be 0x2
329         return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 2;
330     }
331
332     /**
333      * Returns whether this address is a site-local multicast address or not. A
334      * valid IPv6 site-local multicast address is prefixed with
335      * 11111111xxxx0101.
336      *
337      * @return {@code true} if this instance represents a site-local multicast
338      *         address, {@code false} otherwise.
339      */
340     @Override
341     public boolean isMCSiteLocal() {
342         // the first byte should be 0xFF and the lower 4 bits
343         // of the second byte should be 0x5
344         return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 5;
345     }
346
347     /**
348      * Returns whether this address is a organization-local multicast address or
349      * not. A valid IPv6 org-local multicast address is prefixed with
350      * 11111111xxxx1000.
351      *
352      * @return {@code true} if this instance represents a org-local multicast
353      *         address, {@code false} otherwise.
354      */
355     @Override
356     public boolean isMCOrgLocal() {
357         // the first byte should be 0xFF and the lower 4 bits
358         // of the second byte should be 0x8
359         return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 8;
360     }
361
362     // BEGIN android-removed
363     // public String getHostAddress() {
364     // }
365     // END android-removed
366
367     /**
368      * Gets the scope id as a number if this address is linked to an interface.
369      * Otherwise returns {@code 0}.
370      *
371      * @return the scope_id of this address or 0 when not linked with an
372      *         interface.
373      */
374     public int getScopeId() {
375         if (scope_id_set) {
376             return scope_id;
377         }
378         return 0;
379     }
380
381     /**
382      * Gets the network interface if this address is instanced with a scoped
383      * network interface. Otherwise returns {@code null}.
384      *
385      * @return the scoped network interface of this address.
386      */
387     public NetworkInterface getScopedInterface() {
388         if (scope_ifname_set) {
389             return scopedIf;
390         }
391         return null;
392     }
393
394     // BEGIN android-removed
395     // public int hashCode() {}
396     // END android-removed
397
398     // BEGIN android-removed
399     // public boolean equals(Object obj) {}
400     // END android-removed
401
402     /**
403      * Returns whether this address is IPv4 compatible or not. An IPv4
404      * compatible address is prefixed with 96 bits of 0's. The last 32-bits are
405      * varied corresponding with the 32-bit IPv4 address space.
406      *
407      * @return {@code true} if this instance represents an IPv4 compatible
408      *         address, {@code false} otherwise.
409      */
410     public boolean isIPv4CompatibleAddress() {
411         for (int i = 0; i < 12; i++) {
412             if (ipaddress[i] != 0) {
413                 return false;
414             }
415         }
416         return true;
417     }
418
419     private static final ObjectStreamField[] serialPersistentFields = {
420             new ObjectStreamField("ipaddress", new byte[0].getClass()),
421             new ObjectStreamField("scope_id", Integer.TYPE),
422             new ObjectStreamField("scope_id_set", Boolean.TYPE),
423             new ObjectStreamField("scope_ifname_set", Boolean.TYPE),
424             new ObjectStreamField("ifname", String.class), };
425
426     private void writeObject(ObjectOutputStream stream) throws IOException {
427         ObjectOutputStream.PutField fields = stream.putFields();
428         if (ipaddress == null) {
429             fields.put("ipaddress", null);
430         } else {
431             fields.put("ipaddress", ipaddress);
432         }
433
434         fields.put("scope_id", scope_id);
435         fields.put("scope_id_set", scope_id_set);
436         fields.put("scope_ifname_set", scope_ifname_set);
437         fields.put("ifname", ifname);
438         stream.writeFields();
439     }
440
441     private void readObject(ObjectInputStream stream) throws IOException,
442             ClassNotFoundException {
443         ObjectInputStream.GetField fields = stream.readFields();
444         ipaddress = (byte[]) fields.get("ipaddress", null);
445         scope_id = fields.get("scope_id", 0);
446         scope_id_set = fields.get("scope_id_set", false);
447         ifname = (String) fields.get("ifname", null);
448         scope_ifname_set = fields.get("scope_ifname_set", false);
449         if (scope_ifname_set && null != ifname) {
450             scopedIf = NetworkInterface.getByName(ifname);
451         }
452     }
453
454     /**
455      * Returns a string containing a concise, human-readable description of this
456      * IP address.
457      *
458      * @return the description, as host/address.
459      */
460     @Override
461     public String toString() {
462         if (ifname != null) {
463             return super.toString() + "%" + ifname;
464         }
465         if (scope_id != 0) {
466             return super.toString() + "%" + scope_id;
467         }
468         return super.toString();
469     }
470 }