001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.net;
019:
020: import java.io.IOException;
021: import java.io.ObjectInputStream;
022: import java.io.ObjectOutputStream;
023: import java.io.ObjectStreamField;
024: import java.util.Enumeration;
025:
026: import org.apache.harmony.luni.util.Inet6Util;
027: import org.apache.harmony.luni.util.Msg;
028:
029: public final class Inet6Address extends InetAddress {
030:
031: private static final long serialVersionUID = 6880410070516793377L;
032:
033: static final byte[] any_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
034: 0, 0, 0, 0, 0 };
035:
036: static final byte[] localhost_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0,
037: 0, 0, 0, 0, 0, 0, 1 };
038:
039: static final InetAddress ANY = new Inet6Address(any_bytes);
040:
041: static final InetAddress LOOPBACK = new Inet6Address(
042: localhost_bytes, "localhost"); //$NON-NLS-1$
043:
044: int scope_id;
045:
046: boolean scope_id_set;
047:
048: boolean scope_ifname_set;
049:
050: String ifname;
051:
052: /*
053: * scoped interface.
054: */
055: transient NetworkInterface scopedIf;
056:
057: Inet6Address(byte address[]) {
058: ipaddress = address;
059: scope_id = 0;
060: }
061:
062: Inet6Address(byte address[], String name) {
063: hostName = name;
064: ipaddress = address;
065: scope_id = 0;
066: }
067:
068: /**
069: * Constructs an InetAddress, representing the <code>address</code> and
070: * <code>hostName</code> and <code>scope_id</code>
071: *
072: * @param address
073: * network address
074: * @param name
075: * Name associated with the address
076: * @param scope_id
077: * The scope id for link or site local addresses
078: */
079: Inet6Address(byte address[], String name, int scope_id) {
080: hostName = name;
081: ipaddress = address;
082: this .scope_id = scope_id;
083: if (scope_id != 0) {
084: scope_id_set = true;
085: }
086: }
087:
088: /**
089: * Constructs an IPv6 address according to the given <code>host</code>,
090: * <code>addr</code> and <code>scope_id</code>.
091: *
092: * @param host
093: * hostname associated with the address
094: * @param addr
095: * network address
096: * @param scope_id
097: * the scope id for link or site local addresses
098: * @return an Inet6Address instance
099: * @throws UnknownHostException
100: * if the address is null or of invalid length
101: */
102: public static Inet6Address getByAddress(String host, byte[] addr,
103: int scope_id) throws UnknownHostException {
104: if (null == addr || 16 != addr.length) {
105: // KA020=Illegal IPv6 address
106: throw new UnknownHostException(Msg.getString("KA020")); //$NON-NLS-1$
107: }
108: if (scope_id < 0) {
109: scope_id = 0;
110: }
111: return new Inet6Address(addr, host, scope_id);
112: }
113:
114: /**
115: * Constructs an IPv6 address according to the given <code>host</code>,
116: * <code>addr</code> and <code>nif</code>. <code>scope_id</code> is
117: * set according to the given <code>nif</code> and the
118: * <code>addr<code> type(e.g. site local or link local).
119: *
120: * @param host
121: * host name associated with the address
122: * @param addr
123: * network address
124: * @param nif
125: * the Network Interface that this address is associated with.
126: * @return an Inet6Address instance
127: * @throws UnknownHostException
128: * if the address is null or of invalid length, or the
129: * interface doesn't have a numeric scope id for the given
130: * address type.
131: */
132: public static Inet6Address getByAddress(String host, byte[] addr,
133: NetworkInterface nif) throws UnknownHostException {
134:
135: Inet6Address address = Inet6Address.getByAddress(host, addr, 0);
136:
137: // if nif is null, nothing needs to be set.
138: if (null == nif) {
139: return address;
140: }
141:
142: // find the first address which matches the type addr,
143: // then set the scope_id, ifname and scopedIf.
144: Enumeration<InetAddress> addressList = nif.getInetAddresses();
145: while (addressList.hasMoreElements()) {
146: InetAddress ia = addressList.nextElement();
147: if (ia.getAddress().length == 16) {
148: Inet6Address v6ia = (Inet6Address) ia;
149: boolean isSameType = v6ia.compareLocalType(address);
150: if (isSameType) {
151: address.scope_id_set = true;
152: address.scope_id = v6ia.scope_id;
153: address.scope_ifname_set = true;
154: address.ifname = nif.getName();
155: address.scopedIf = nif;
156: break;
157: }
158: }
159: }
160: // if no address matches the type of addr, throws an
161: // UnknownHostException.
162: if (!address.scope_id_set) {
163: // KA021=Scope id is not found for the given address
164: throw new UnknownHostException(Msg.getString("KA021")); //$NON-NLS-1$
165: }
166: return address;
167: }
168:
169: /**
170: * Returns true if one of following cases is true: 1. both addresses are
171: * site local; 2. both addresses are link local; 3. ia is neither site local
172: * nor link local;
173: */
174: private boolean compareLocalType(Inet6Address ia) {
175: if (ia.isSiteLocalAddress() && isSiteLocalAddress()) {
176: return true;
177: }
178: if (ia.isLinkLocalAddress() && isLinkLocalAddress()) {
179: return true;
180: }
181: if (!ia.isSiteLocalAddress() && !ia.isLinkLocalAddress()) {
182: return true;
183: }
184: return false;
185: }
186:
187: /**
188: * Constructs an InetAddress, representing the <code>address</code> and
189: * <code>hostName</code> and <code>scope_id</code>
190: *
191: * @param address
192: * network address
193: * @param scope_id
194: * The scope id for link or site local addresses
195: */
196: Inet6Address(byte address[], int scope_id) {
197: ipaddress = address;
198: this .scope_id = scope_id;
199: if (scope_id != 0) {
200: scope_id_set = true;
201: }
202: }
203:
204: /**
205: * Answer true if the InetAddress is an IP multicast address.
206: *
207: * Valid IPv6 multicast address have the binary prefixed with 11111111 or FF
208: * (hex).
209: *
210: * @return boolean true, if the address is in the multicast group, false
211: * otherwise
212: */
213: @Override
214: public boolean isMulticastAddress() {
215: // Multicast addresses are prefixed with 11111111 (255)
216: return ipaddress[0] == -1;
217: }
218:
219: /**
220: * Answer true if the InetAddress is the unspecified address "::".
221: *
222: * @return boolean true, if the address is in the multicast group, false
223: * 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: * Answer true if the InetAddress is the loopback address
237: *
238: * The valid IPv6 loopback address is ::1
239: *
240: * @return boolean true if the address is the loopback, 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: * Answer true if the InetAddress is a link-local address.
262: *
263: * A valid IPv6 link-local address is prefixed with 1111111010
264: *
265: * @return boolean true, if it is a link-local address, 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)
272: && ((ipaddress[1] & 255) >>> 6) == 2;
273: }
274:
275: /**
276: * Answer true if the InetAddress is a site-local address.
277: *
278: * A valid IPv6 site-local address is prefixed with 1111111011
279: *
280: * @return boolean true, if it is a site-local address, false otherwise
281: */
282: @Override
283: public boolean isSiteLocalAddress() {
284:
285: // the first 10 bits need to be 1111111011 (1019)
286: return (ipaddress[0] == -2)
287: && ((ipaddress[1] & 255) >>> 6) == 3;
288: }
289:
290: /**
291: * Answer true if the InetAddress is a global multicast address.
292: *
293: * A valid IPv6 global multicast address is 11111111xxxx1110 (i.e. FF0E)
294: *
295: * @return boolean true, if it is a global multicast address, false
296: * otherwise
297: */
298: @Override
299: public boolean isMCGlobal() {
300: // the first byte should be 0xFF and the lower 4 bits
301: // of the second byte should be 0xE
302: return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 14;
303: }
304:
305: /**
306: * Answer true if the InetAddress is a node-local multicast address.
307: *
308: * A valid IPv6 node-local multicast address is prefixed with
309: * 11111111xxxx0001
310: *
311: * @return boolean true, if it is a node-local multicast address, false
312: * otherwise
313: */
314: @Override
315: public boolean isMCNodeLocal() {
316: // the first byte should be 0xFF and the lower 4 bits
317: // of the second byte should be 0x1
318: return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 1;
319: }
320:
321: /**
322: * Answer true if the InetAddress is a link-local multicast address.
323: *
324: * A valid IPv6 link-local multicast address is prefixed with
325: * 11111111xxxx0010
326: *
327: * @return boolean true, if it is a link-local multicast address, false
328: * otherwise
329: */
330: @Override
331: public boolean isMCLinkLocal() {
332: // the first byte should be 0xFF and the lower 4 bits
333: // of the second byte should be 0x2
334: return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 2;
335: }
336:
337: /**
338: * Answer true if the InetAddress is a site-local multicast address.
339: *
340: * A valid IPv6 site-local multicast address is prefixed with
341: * 11111111xxxx0101
342: *
343: * @return boolean true, if it is a site-local multicast address, false
344: * otherwise
345: */
346: @Override
347: public boolean isMCSiteLocal() {
348: // the first byte should be 0xFF and the lower 4 bits
349: // of the second byte should be 0x5
350: return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 5;
351: }
352:
353: /**
354: * Answer true if the InetAddress is a org-local multicast address.
355: *
356: * A valid IPv6 org-local multicast address is prefixed with
357: * 11111111xxxx1000
358: *
359: * @return boolean true, if it is a org-local multicast address, false
360: * otherwise
361: */
362: @Override
363: public boolean isMCOrgLocal() {
364: // the first byte should be 0xFF and the lower 4 bits
365: // of the second byte should be 0x8
366: return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 8;
367: }
368:
369: @Override
370: public String getHostAddress() {
371: return Inet6Util.createIPAddrStringFromByteArray(ipaddress);
372: }
373:
374: /**
375: * Returns the <code>scope id</code> of this address if it is associated
376: * with an interface. Otherwise returns zero.
377: *
378: * @return the scope_id.
379: */
380: public int getScopeId() {
381: if (scope_id_set) {
382: return scope_id;
383: }
384: return 0;
385: }
386:
387: /**
388: * Returns the network interface if this address is instanced with a scoped
389: * network interface. Otherwise returns null.
390: *
391: * @return the scoped network interface.
392: */
393: public NetworkInterface getScopedInterface() {
394: if (scope_ifname_set) {
395: return scopedIf;
396: }
397: return null;
398: }
399:
400: /**
401: * Returns the hashcode of the receiver.
402: *
403: * @return the hashcode
404: */
405: @Override
406: public int hashCode() {
407: /* Returns the low order int as the hash code */
408: return bytesToInt(ipaddress, 12);
409: }
410:
411: /**
412: * Returns true if obj is of the same type as the IPv6 address and they have
413: * the same IP address, false otherwise. the scope id does not seem to be
414: * part of the comparison
415: *
416: * @return String
417: *
418: */
419: @Override
420: public boolean equals(Object obj) {
421: return super .equals(obj);
422: }
423:
424: /**
425: * An IPv4 compatible address is prefixed with 96 bits of 0's. The last
426: * 32-bits are varied corresponding with the 32-bit IPv4 address space.
427: */
428: public boolean isIPv4CompatibleAddress() {
429: for (int i = 0; i < 12; i++) {
430: if (ipaddress[i] != 0) {
431: return false;
432: }
433: }
434: return true;
435: }
436:
437: private static final ObjectStreamField[] serialPersistentFields = {
438: new ObjectStreamField("ipaddress", new byte[0].getClass()), //$NON-NLS-1$
439: new ObjectStreamField("scope_id", Integer.TYPE), //$NON-NLS-1$
440: new ObjectStreamField("scope_id_set", Boolean.TYPE), //$NON-NLS-1$
441: new ObjectStreamField("scope_ifname_set", Boolean.TYPE), //$NON-NLS-1$
442: new ObjectStreamField("ifname", String.class), }; //$NON-NLS-1$
443:
444: private void writeObject(ObjectOutputStream stream)
445: throws IOException {
446: ObjectOutputStream.PutField fields = stream.putFields();
447: if (ipaddress == null) {
448: fields.put("ipaddress", null); //$NON-NLS-1$
449: } else {
450: fields.put("ipaddress", ipaddress); //$NON-NLS-1$
451: }
452:
453: fields.put("scope_id", scope_id); //$NON-NLS-1$
454: fields.put("scope_id_set", scope_id_set); //$NON-NLS-1$
455: fields.put("scope_ifname_set", scope_ifname_set); //$NON-NLS-1$
456: fields.put("ifname", ifname); //$NON-NLS-1$
457: stream.writeFields();
458: }
459:
460: private void readObject(ObjectInputStream stream)
461: throws IOException, ClassNotFoundException {
462: ObjectInputStream.GetField fields = stream.readFields();
463: ipaddress = (byte[]) fields.get("ipaddress", null); //$NON-NLS-1$
464: scope_id = fields.get("scope_id", 0); //$NON-NLS-1$
465: scope_id_set = fields.get("scope_id_set", false); //$NON-NLS-1$
466: ifname = (String) fields.get("ifname", null); //$NON-NLS-1$
467: scope_ifname_set = fields.get("scope_ifname_set", false); //$NON-NLS-1$
468: if (scope_ifname_set && null != ifname) {
469: scopedIf = NetworkInterface.getByName(ifname);
470: }
471: }
472:
473: /**
474: * Answers a string containing a concise, human-readable description of the
475: * address.
476: *
477: * @return String the description, as host/address
478: */
479: @Override
480: public String toString() {
481: if (ifname != null) {
482: return super .toString() + "%" + ifname; //$NON-NLS-1$
483: }
484: if (scope_id != 0) {
485: return super .toString() + "%" + scope_id; //$NON-NLS-1$
486: }
487: return super.toString();
488: }
489: }
|