blob: 37e9c18d5ab32bd96a45218442e339329384539c [file] [log] [blame]
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001/*
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
18package java.net;
19
20import java.io.IOException;
21import java.io.ObjectInputStream;
22import java.io.ObjectOutputStream;
23import java.io.ObjectStreamField;
Elliott Hughesfbbae972010-10-27 15:33:39 -070024import java.util.Arrays;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080025import java.util.Enumeration;
Elliott Hughes32b0fa42011-05-10 16:07:38 -070026import static libcore.io.OsConstants.*;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080027
28/**
Elliott Hughes4adff242010-05-27 13:01:38 -070029 * An IPv6 address. See {@link InetAddress}.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080030 */
31public final class Inet6Address extends InetAddress {
32
33 private static final long serialVersionUID = 6880410070516793377L;
34
Elliott Hughes4f11ebe2011-04-19 15:38:10 -070035 /**
36 * @hide
37 */
38 public static final InetAddress ANY =
Elliott Hughesfbbae972010-10-27 15:33:39 -070039 new Inet6Address(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, null, 0);
Elliott Hughes4f11ebe2011-04-19 15:38:10 -070040
41 /**
42 * @hide
43 */
44 public static final InetAddress LOOPBACK =
Elliott Hughesfbbae972010-10-27 15:33:39 -070045 new Inet6Address(new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
46 "localhost", 0);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080047
Elliott Hughesf02f9392011-05-17 15:03:50 -070048 private boolean scope_id_set;
49 private int scope_id;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080050
Elliott Hughesf02f9392011-05-17 15:03:50 -070051 private boolean scope_ifname_set;
52 private String ifname;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080053
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080054 /**
55 * Constructs an {@code InetAddress} representing the {@code address} and
56 * {@code name} and {@code scope_id}.
Elliott Hughesf33eae72010-05-13 12:36:25 -070057 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080058 * @param address
59 * the network address.
60 * @param name
61 * the name associated with the address.
62 * @param scope_id
63 * the scope id for link- or site-local addresses.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080064 */
Elliott Hughes4f11ebe2011-04-19 15:38:10 -070065 Inet6Address(byte[] ipaddress, String hostName, int scope_id) {
66 super(AF_INET6, ipaddress, hostName);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080067 this.scope_id = scope_id;
Elliott Hughesfbbae972010-10-27 15:33:39 -070068 this.scope_id_set = (scope_id != 0);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080069 }
70
71 /**
72 * Constructs an IPv6 address according to the given {@code host}, {@code
73 * addr} and {@code scope_id}.
Elliott Hughesf33eae72010-05-13 12:36:25 -070074 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080075 * @param host
76 * the host name associated with the address.
77 * @param addr
78 * the network address.
79 * @param scope_id
80 * the scope id for link- or site-local addresses.
81 * @return the Inet6Address instance representing the IP address.
82 * @throws UnknownHostException
83 * if the address is null or has an invalid length.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080084 */
Elliott Hughesfbbae972010-10-27 15:33:39 -070085 public static Inet6Address getByAddress(String host, byte[] addr, int scope_id)
86 throws UnknownHostException {
Elliott Hughesb1396872010-05-24 16:58:07 -070087 if (addr == null || addr.length != 16) {
Elliott Hughesfbbae972010-10-27 15:33:39 -070088 throw new UnknownHostException("Not an IPv6 address: " + Arrays.toString(addr));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080089 }
90 if (scope_id < 0) {
91 scope_id = 0;
92 }
Elliott Hughesfbbae972010-10-27 15:33:39 -070093 // TODO: should we clone 'addr'?
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080094 return new Inet6Address(addr, host, scope_id);
95 }
96
97 /**
98 * Gets an IPv6 address instance according to the given {@code host},
99 * {@code addr} and {@code nif}. {@code scope_id} is set according to the
100 * given {@code nif} and the {@code addr} type (for example site-local or
101 * link-local).
Elliott Hughesf33eae72010-05-13 12:36:25 -0700102 *
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800103 * @param host
104 * the hostname associated with the address.
105 * @param addr
106 * the network address.
107 * @param nif
108 * the network interface that this address is associated with.
109 * @return the Inet6Address instance representing the IP address.
110 * @throws UnknownHostException
111 * if the address is {@code null} or has an invalid length or
112 * the interface doesn't have a numeric scope id for the given
113 * address type.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800114 */
115 public static Inet6Address getByAddress(String host, byte[] addr,
116 NetworkInterface nif) throws UnknownHostException {
117
118 Inet6Address address = Inet6Address.getByAddress(host, addr, 0);
119
120 // if nif is null, nothing needs to be set.
Elliott Hughesb46dab32010-12-09 11:46:15 -0800121 if (nif == null) {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800122 return address;
123 }
124
125 // find the first address which matches the type addr,
Elliott Hughesa37e9712011-04-21 14:07:01 -0700126 // then set the scope_id and ifname.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800127 Enumeration<InetAddress> addressList = nif.getInetAddresses();
128 while (addressList.hasMoreElements()) {
129 InetAddress ia = addressList.nextElement();
130 if (ia.getAddress().length == 16) {
131 Inet6Address v6ia = (Inet6Address) ia;
132 boolean isSameType = v6ia.compareLocalType(address);
133 if (isSameType) {
134 address.scope_id_set = true;
135 address.scope_id = v6ia.scope_id;
136 address.scope_ifname_set = true;
137 address.ifname = nif.getName();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800138 break;
139 }
140 }
141 }
142 // if no address matches the type of addr, throws an
143 // UnknownHostException.
144 if (!address.scope_id_set) {
Elliott Hughesfbbae972010-10-27 15:33:39 -0700145 throw new UnknownHostException("Scope id not found for address: " + Arrays.toString(addr));
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800146 }
147 return address;
148 }
149
150 /**
151 * Returns {@code true} if one of following cases applies:
152 * <p>
Jesse Wilsonf5597e62009-07-24 15:17:03 -0700153 * <ol>
154 * <li>both addresses are site local</li>
155 * <li>both addresses are link local</li>
156 * <li>{@code ia} is neither site local nor link local</li>
157 * </ol>
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800158 */
159 private boolean compareLocalType(Inet6Address ia) {
160 if (ia.isSiteLocalAddress() && isSiteLocalAddress()) {
161 return true;
162 }
163 if (ia.isLinkLocalAddress() && isLinkLocalAddress()) {
164 return true;
165 }
166 if (!ia.isSiteLocalAddress() && !ia.isLinkLocalAddress()) {
167 return true;
168 }
169 return false;
170 }
171
Elliott Hughesa37e9712011-04-21 14:07:01 -0700172 @Override public boolean isAnyLocalAddress() {
173 return Arrays.equals(ipaddress, Inet6Address.ANY.ipaddress);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800174 }
175
176 /**
Elliott Hughesa7428d62011-09-29 14:41:32 -0700177 * Returns whether this IPv6 address is an IPv4-compatible address or not.
178 * An IPv4-compatible address has the prefix {@code ::/96} and is a deprecated
179 * and no-longer used equivalent of the modern IPv4-mapped IPv6 addresses.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800180 */
Elliott Hughesa7428d62011-09-29 14:41:32 -0700181 public boolean isIPv4CompatibleAddress() {
182 for (int i = 0; i < 12; i++) {
183 if (ipaddress[i] != 0) {
184 return false;
185 }
186 }
187 return true;
188 }
189
190 @Override public boolean isLinkLocalAddress() {
191 return ((ipaddress[0] & 0xff) == 0xfe) && ((ipaddress[1] & 0xc0) == 0x80); // fe80:/10
192 }
193
Elliott Hughesa37e9712011-04-21 14:07:01 -0700194 @Override public boolean isLoopbackAddress() {
195 return Arrays.equals(ipaddress, Inet6Address.LOOPBACK.ipaddress);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800196 }
197
Elliott Hughesa37e9712011-04-21 14:07:01 -0700198 @Override public boolean isMCGlobal() {
Elliott Hughesa7428d62011-09-29 14:41:32 -0700199 return ((ipaddress[0] & 0xff) == 0xff) && ((ipaddress[1] & 0x0f) == 0x0e); // ffxe:/16
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800200 }
201
Elliott Hughesa37e9712011-04-21 14:07:01 -0700202 @Override public boolean isMCLinkLocal() {
Elliott Hughesa7428d62011-09-29 14:41:32 -0700203 return ((ipaddress[0] & 0xff) == 0xff) && ((ipaddress[1] & 0x0f) == 0x02); // ffx2:/16
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800204 }
205
Elliott Hughesa7428d62011-09-29 14:41:32 -0700206 @Override public boolean isMCNodeLocal() {
207 return ((ipaddress[0] & 0xff) == 0xff) && ((ipaddress[1] & 0x0f) == 0x01); // ffx1:/16
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800208 }
209
Elliott Hughesa37e9712011-04-21 14:07:01 -0700210 @Override public boolean isMCOrgLocal() {
Elliott Hughesa7428d62011-09-29 14:41:32 -0700211 return ((ipaddress[0] & 0xff) == 0xff) && ((ipaddress[1] & 0x0f) == 0x08); // ffx8:/16
212 }
213
214 @Override public boolean isMCSiteLocal() {
215 return ((ipaddress[0] & 0xff) == 0xff) && ((ipaddress[1] & 0x0f) == 0x05); // ffx5:/16
216 }
217
218 @Override public boolean isMulticastAddress() {
219 return ((ipaddress[0] & 0xff) == 0xff); // ff::/8
220 }
221
222 @Override public boolean isSiteLocalAddress() {
223 return ((ipaddress[0] & 0xff) == 0xfe) && ((ipaddress[1] & 0xc0) == 0xc0); // fec0:/10
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800224 }
225
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800226 /**
Elliott Hughesa37e9712011-04-21 14:07:01 -0700227 * Returns the scope id if this address is scoped to an interface, 0 otherwise.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800228 */
229 public int getScopeId() {
Elliott Hughesa37e9712011-04-21 14:07:01 -0700230 return scope_id_set ? scope_id : 0;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800231 }
232
233 /**
Elliott Hughesa37e9712011-04-21 14:07:01 -0700234 * Returns the network interface if this address is instanced with a scoped
235 * network interface, null otherwise.
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800236 */
237 public NetworkInterface getScopedInterface() {
Elliott Hughesa37e9712011-04-21 14:07:01 -0700238 try {
Elliott Hughesf02f9392011-05-17 15:03:50 -0700239 return (scope_ifname_set && ifname != null) ? NetworkInterface.getByName(ifname) : null;
Elliott Hughesa37e9712011-04-21 14:07:01 -0700240 } catch (SocketException ex) {
241 return null;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800242 }
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800243 }
244
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800245 private static final ObjectStreamField[] serialPersistentFields = {
Elliott Hughese26ba792011-02-08 11:33:34 -0800246 new ObjectStreamField("ipaddress", byte[].class),
247 new ObjectStreamField("scope_id", int.class),
248 new ObjectStreamField("scope_id_set", boolean.class),
249 new ObjectStreamField("scope_ifname_set", boolean.class),
Elliott Hughes28eb98e2011-02-04 18:05:25 -0800250 new ObjectStreamField("ifname", String.class),
251 };
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800252
253 private void writeObject(ObjectOutputStream stream) throws IOException {
254 ObjectOutputStream.PutField fields = stream.putFields();
255 if (ipaddress == null) {
Elliott Hughesf33eae72010-05-13 12:36:25 -0700256 fields.put("ipaddress", null);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800257 } else {
Elliott Hughesf33eae72010-05-13 12:36:25 -0700258 fields.put("ipaddress", ipaddress);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800259 }
260
Elliott Hughesf33eae72010-05-13 12:36:25 -0700261 fields.put("scope_id", scope_id);
262 fields.put("scope_id_set", scope_id_set);
263 fields.put("scope_ifname_set", scope_ifname_set);
264 fields.put("ifname", ifname);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800265 stream.writeFields();
266 }
267
Elliott Hughesa37e9712011-04-21 14:07:01 -0700268 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800269 ObjectInputStream.GetField fields = stream.readFields();
Elliott Hughesf33eae72010-05-13 12:36:25 -0700270 ipaddress = (byte[]) fields.get("ipaddress", null);
271 scope_id = fields.get("scope_id", 0);
272 scope_id_set = fields.get("scope_id_set", false);
273 ifname = (String) fields.get("ifname", null);
274 scope_ifname_set = fields.get("scope_ifname_set", false);
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800275 }
276
Elliott Hughesa37e9712011-04-21 14:07:01 -0700277 @Override public String toString() {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800278 if (ifname != null) {
Elliott Hughesf33eae72010-05-13 12:36:25 -0700279 return super.toString() + "%" + ifname;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800280 }
281 if (scope_id != 0) {
Elliott Hughesf33eae72010-05-13 12:36:25 -0700282 return super.toString() + "%" + scope_id;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800283 }
284 return super.toString();
285 }
286}