blob: f47b06586ba679eb19ef376d04f95cd0c5d417c4 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
Thomas Vachuska24c849c2014-10-27 09:53:05 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska24c849c2014-10-27 09:53:05 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070015 */
Jonathan Hartdec62d42014-09-22 15:59:04 -070016package org.onlab.packet;
17
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -070018import java.net.InetAddress;
19import java.net.Inet4Address;
20import java.net.Inet6Address;
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070021import java.nio.ByteBuffer;
Jonathan Hartdec62d42014-09-22 15:59:04 -070022import java.util.Arrays;
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -070023import java.util.Objects;
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -070024import com.google.common.net.InetAddresses;
25import com.google.common.primitives.UnsignedBytes;
26
Jonathan Hartdec62d42014-09-22 15:59:04 -070027
28/**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070029 * A class representing an IP address.
Pavlin Radoslavovf182f012014-11-04 15:03:18 -080030 * This class is immutable.
Jonathan Hartdec62d42014-09-22 15:59:04 -070031 */
Pavlin Radoslavovf182f012014-11-04 15:03:18 -080032public class IpAddress implements Comparable<IpAddress> {
Aaron Kruglikovafdf4de2015-06-24 09:28:22 -070033 private static final int BIT_MASK = 0x000000ff;
34
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070035 // IP Versions
Jonathan Hartdec62d42014-09-22 15:59:04 -070036 public enum Version { INET, INET6 };
37
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070038 // lengths of address, in bytes
39 public static final int INET_BYTE_LENGTH = 4;
40 public static final int INET_BIT_LENGTH = INET_BYTE_LENGTH * Byte.SIZE;
41 public static final int INET6_BYTE_LENGTH = 16;
42 public static final int INET6_BIT_LENGTH = INET6_BYTE_LENGTH * Byte.SIZE;
Jonathan Hartdec62d42014-09-22 15:59:04 -070043
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070044 private final Version version;
45 private final byte[] octets;
Jonathan Hartdec62d42014-09-22 15:59:04 -070046
47 /**
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070048 * Constructor for given IP address version and address octets.
49 *
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -070050 * @param version the IP address version
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -070051 * @param value the IP address value stored in network byte order
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070052 * (i.e., the most significant byte first)
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -070053 * @throws IllegalArgumentException if the arguments are invalid
Jonathan Hartdec62d42014-09-22 15:59:04 -070054 */
Pavlin Radoslavovf182f012014-11-04 15:03:18 -080055 protected IpAddress(Version version, byte[] value) {
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -070056 checkArguments(version, value, 0);
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -070057 this.version = version;
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -070058 switch (version) {
59 case INET:
60 this.octets = Arrays.copyOf(value, INET_BYTE_LENGTH);
61 break;
62 case INET6:
63 this.octets = Arrays.copyOf(value, INET6_BYTE_LENGTH);
64 break;
65 default:
66 // Should not be reached
67 this.octets = null;
68 break;
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -070069 }
Jonathan Hartdec62d42014-09-22 15:59:04 -070070 }
71
72 /**
73 * Returns the IP version of this address.
74 *
75 * @return the version
76 */
77 public Version version() {
78 return this.version;
79 }
80
81 /**
Pavlin Radoslavov34ffe722015-03-10 12:48:55 -070082 * Tests whether the IP version of this address is IPv4.
83 *
84 * @return true if the IP version of this address is IPv4, otherwise false.
85 */
86 public boolean isIp4() {
87 return (version() == Ip4Address.VERSION);
88 }
89
90 /**
91 * Tests whether the IP version of this address is IPv6.
92 *
93 * @return true if the IP version of this address is IPv6, otherwise false.
94 */
95 public boolean isIp6() {
96 return (version() == Ip6Address.VERSION);
97 }
98
99 /**
Pavlin Radoslavov34c81642014-11-04 16:21:38 -0800100 * Gets the {@link Ip4Address} view of the IP address.
101 *
102 * @return the {@link Ip4Address} view of the IP address if it is IPv4,
103 * otherwise null
104 */
105 public Ip4Address getIp4Address() {
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700106 if (!isIp4()) {
Pavlin Radoslavov34c81642014-11-04 16:21:38 -0800107 return null;
108 }
109
110 // Return this object itself if it is already instance of Ip4Address
111 if (this instanceof Ip4Address) {
112 return (Ip4Address) this;
113 }
114 return Ip4Address.valueOf(octets);
115 }
116
117 /**
118 * Gets the {@link Ip6Address} view of the IP address.
119 *
120 * @return the {@link Ip6Address} view of the IP address if it is IPv6,
121 * otherwise null
122 */
123 public Ip6Address getIp6Address() {
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700124 if (!isIp6()) {
Pavlin Radoslavov34c81642014-11-04 16:21:38 -0800125 return null;
126 }
127
128 // Return this object itself if it is already instance of Ip6Address
129 if (this instanceof Ip6Address) {
130 return (Ip6Address) this;
131 }
132 return Ip6Address.valueOf(octets);
133 }
134
135 /**
Jonathan Hartdec62d42014-09-22 15:59:04 -0700136 * Returns the IP address as a byte array.
137 *
138 * @return a byte array
139 */
140 public byte[] toOctets() {
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700141 return Arrays.copyOf(octets, octets.length);
Jonathan Hartdec62d42014-09-22 15:59:04 -0700142 }
143
144 /**
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700145 * Computes the IP address byte length for a given IP version.
146 *
147 * @param version the IP version
148 * @return the IP address byte length for the IP version
149 * @throws IllegalArgumentException if the IP version is invalid
150 */
151 public static int byteLength(Version version) {
152 switch (version) {
153 case INET:
154 return INET_BYTE_LENGTH;
155 case INET6:
156 return INET6_BYTE_LENGTH;
157 default:
158 String msg = "Invalid IP version " + version;
159 throw new IllegalArgumentException(msg);
160 }
161 }
162
163 /**
164 * Converts an integer into an IPv4 address.
165 *
166 * @param value an integer representing an IPv4 address value
167 * @return an IP address
168 */
169 public static IpAddress valueOf(int value) {
170 byte[] bytes =
171 ByteBuffer.allocate(INET_BYTE_LENGTH).putInt(value).array();
172 return new IpAddress(Version.INET, bytes);
173 }
174
175 /**
176 * Converts a byte array into an IP address.
177 *
178 * @param version the IP address version
179 * @param value the IP address value stored in network byte order
180 * (i.e., the most significant byte first)
181 * @return an IP address
182 * @throws IllegalArgumentException if the arguments are invalid
183 */
184 public static IpAddress valueOf(Version version, byte[] value) {
185 return new IpAddress(version, value);
186 }
187
188 /**
189 * Converts a byte array and a given offset from the beginning of the
190 * array into an IP address.
191 * <p>
192 * The IP address is stored in network byte order (i.e., the most
193 * significant byte first).
194 * </p>
195 * @param version the IP address version
196 * @param value the value to use
197 * @param offset the offset in bytes from the beginning of the byte array
198 * @return an IP address
199 * @throws IllegalArgumentException if the arguments are invalid
200 */
201 public static IpAddress valueOf(Version version, byte[] value,
202 int offset) {
203 checkArguments(version, value, offset);
204 byte[] bc = Arrays.copyOfRange(value, offset, value.length);
205 return IpAddress.valueOf(version, bc);
206 }
207
208 /**
Pavlin Radoslavovaf5ff792014-10-31 20:51:47 -0700209 * Converts an InetAddress into an IP address.
210 *
211 * @param inetAddress the InetAddress value to use
212 * @return an IP address
213 * @throws IllegalArgumentException if the argument is invalid
214 */
215 public static IpAddress valueOf(InetAddress inetAddress) {
216 byte[] bytes = inetAddress.getAddress();
217 if (inetAddress instanceof Inet4Address) {
218 return new IpAddress(Version.INET, bytes);
219 }
220 if (inetAddress instanceof Inet6Address) {
221 return new IpAddress(Version.INET6, bytes);
222 }
223 // Use the number of bytes as a hint
224 if (bytes.length == INET_BYTE_LENGTH) {
225 return new IpAddress(Version.INET, bytes);
226 }
227 if (bytes.length == INET6_BYTE_LENGTH) {
228 return new IpAddress(Version.INET6, bytes);
229 }
230 final String msg = "Unrecognized IP version address string: " +
231 inetAddress.toString();
232 throw new IllegalArgumentException(msg);
233 }
234
235 /**
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700236 * Converts an IPv4 or IPv6 string literal (e.g., "10.2.3.4" or
237 * "1111:2222::8888") into an IP address.
238 *
239 * @param value an IP address value in string form
240 * @return an IP address
241 * @throws IllegalArgumentException if the argument is invalid
242 */
243 public static IpAddress valueOf(String value) {
Pavlin Radoslavovaf5ff792014-10-31 20:51:47 -0700244 InetAddress inetAddress = null;
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700245 try {
Pavlin Radoslavovaf5ff792014-10-31 20:51:47 -0700246 inetAddress = InetAddresses.forString(value);
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700247 } catch (IllegalArgumentException e) {
248 final String msg = "Invalid IP address string: " + value;
249 throw new IllegalArgumentException(msg);
250 }
Pavlin Radoslavovaf5ff792014-10-31 20:51:47 -0700251 return valueOf(inetAddress);
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700252 }
253
254 /**
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700255 * Creates an IP network mask prefix.
256 *
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700257 * @param version the IP address version
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700258 * @param prefixLength the length of the mask prefix. Must be in the
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700259 * interval [0, 32] for IPv4, or [0, 128] for IPv6
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700260 * @return a new IP address that contains a mask prefix of the
261 * specified length
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700262 * @throws IllegalArgumentException if the arguments are invalid
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700263 */
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700264 public static IpAddress makeMaskPrefix(Version version, int prefixLength) {
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800265 byte[] mask = makeMaskPrefixArray(version, prefixLength);
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700266 return new IpAddress(version, mask);
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700267 }
268
269 /**
270 * Creates an IP address by masking it with a network mask of given
271 * mask length.
272 *
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800273 * @param address the address to mask
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700274 * @param prefixLength the length of the mask prefix. Must be in the
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700275 * interval [0, 32] for IPv4, or [0, 128] for IPv6
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700276 * @return a new IP address that is masked with a mask prefix of the
277 * specified length
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700278 * @throws IllegalArgumentException if the prefix length is invalid
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700279 */
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800280 public static IpAddress makeMaskedAddress(final IpAddress address,
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700281 int prefixLength) {
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800282 if (address instanceof Ip4Address) {
283 Ip4Address ip4a = (Ip4Address) address;
284 return Ip4Address.makeMaskedAddress(ip4a, prefixLength);
285 } else if (address instanceof Ip6Address) {
286 Ip6Address ip6a = (Ip6Address) address;
287 return Ip6Address.makeMaskedAddress(ip6a, prefixLength);
288 } else {
289 byte[] net = makeMaskedAddressArray(address, prefixLength);
290 return IpAddress.valueOf(address.version(), net);
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700291 }
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700292 }
293
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800294 /**
295 * Check if this IP address is zero.
296 *
Thomas Vachuskae7966102015-09-09 17:33:33 -0700297 * @return true if this address is zero
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800298 */
299 public boolean isZero() {
300 for (byte b : octets) {
301 if (b != 0) {
302 return false;
303 }
304 }
305 return true;
306 }
307
Thomas Vachuskae7966102015-09-09 17:33:33 -0700308 /**
309 * Check if this IP address is self-assigned.
310 *
311 * @return true if this address is self-assigned
312 */
313 public boolean isSelfAssigned() {
314 return isIp4() && octets[0] == (byte) 169;
315 }
316
Charles Chan4ca8e602016-02-25 18:05:59 -0800317 /**
318 * Check if this IP address is a multicast address.
319 *
320 * @return true if this address a multicast address
321 */
322 public boolean isMulticast() {
323 return isIp4() ?
Charles Chanaedabfd2016-02-26 09:31:48 -0800324 Ip4Prefix.IPV4_MULTICAST_PREFIX.contains(this.getIp4Address()) :
325 Ip6Prefix.IPV6_MULTICAST_PREFIX.contains(this.getIp6Address());
Charles Chan4ca8e602016-02-25 18:05:59 -0800326 }
327
Jonathan Hartdec62d42014-09-22 15:59:04 -0700328 @Override
Jonathan Hartab63aac2014-10-16 08:52:55 -0700329 public int compareTo(IpAddress o) {
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700330 // Compare first the version
331 if (this.version != o.version) {
332 return this.version.compareTo(o.version);
333 }
334
335 // Compare the bytes, one-by-one
336 for (int i = 0; i < this.octets.length; i++) {
337 if (this.octets[i] != o.octets[i]) {
338 return UnsignedBytes.compare(this.octets[i], o.octets[i]);
339 }
340 }
341 return 0; // Equal
Jonathan Hartab63aac2014-10-16 08:52:55 -0700342 }
343
344 @Override
Jonathan Hartdec62d42014-09-22 15:59:04 -0700345 public int hashCode() {
Thomas Vachuskad16ce182014-10-29 17:25:29 -0700346 return Objects.hash(version, Arrays.hashCode(octets));
Jonathan Hartdec62d42014-09-22 15:59:04 -0700347 }
348
349 @Override
350 public boolean equals(Object obj) {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700351 if (this == obj) {
Jonathan Hartdec62d42014-09-22 15:59:04 -0700352 return true;
353 }
Pavlin Radoslavov50b70672014-11-05 11:22:25 -0800354 if ((obj == null) || (!(obj instanceof IpAddress))) {
Jonathan Hartdec62d42014-09-22 15:59:04 -0700355 return false;
356 }
357 IpAddress other = (IpAddress) obj;
Pavlin Radoslavov49e159a2014-10-29 16:22:13 -0700358 return (version == other.version) &&
359 Arrays.equals(octets, other.octets);
Jonathan Hartdec62d42014-09-22 15:59:04 -0700360 }
361
362 @Override
363 /*
364 * (non-Javadoc)
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700365 * The string representation of the IP address: "x.x.x.x" for IPv4
366 * addresses, or ':' separated string for IPv6 addresses.
Jonathan Hartdec62d42014-09-22 15:59:04 -0700367 *
368 * @see java.lang.Object#toString()
369 */
370 public String toString() {
Brian O'Connor041515f2015-02-19 15:36:17 -0800371 // FIXME InetAddress is super slow
372 switch (version) {
373 case INET:
374 return String.format("%d.%d.%d.%d", octets[0] & 0xff,
Aaron Kruglikovafdf4de2015-06-24 09:28:22 -0700375 octets[1] & 0xff,
376 octets[2] & 0xff,
377 octets[3] & 0xff);
Brian O'Connor041515f2015-02-19 15:36:17 -0800378 case INET6:
379 default:
Aaron Kruglikovafdf4de2015-06-24 09:28:22 -0700380 return ipv6ToStringHelper();
Jonathan Hartdec62d42014-09-22 15:59:04 -0700381 }
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700382 }
383
384 /**
Pingping Line28ae4c2015-03-13 11:37:03 -0700385 * Generates an IP prefix.
386 *
387 * @return the IP prefix of the IP address
388 */
389 public IpPrefix toIpPrefix() {
390
391 if (isIp4()) {
392 return IpPrefix.valueOf(new IpAddress(Version.INET, octets),
393 Ip4Address.BIT_LENGTH);
394 } else {
395 return IpPrefix.valueOf(new IpAddress(Version.INET6, octets),
396 Ip6Address.BIT_LENGTH);
397 }
398 }
399
400 /**
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700401 * Gets the IP address name for the IP address version.
402 *
403 * @param version the IP address version
404 * @return the IP address name for the IP address version
405 */
406 private static String addressName(Version version) {
407 switch (version) {
408 case INET:
409 return "IPv4";
410 case INET6:
411 return "IPv6";
412 default:
413 break;
414 }
415 return "UnknownIP(" + version + ")";
416 }
417
418 /**
419 * Checks whether the arguments are valid.
420 *
421 * @param version the IP address version
422 * @param value the IP address value stored in a byte array
423 * @param offset the offset in bytes from the beginning of the byte
424 * array with the address
425 * @throws IllegalArgumentException if any of the arguments is invalid
426 */
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800427 static void checkArguments(Version version, byte[] value, int offset) {
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -0700428 // Check the offset and byte array length
429 int addrByteLength = byteLength(version);
430 if ((offset < 0) || (offset + addrByteLength > value.length)) {
431 String msg;
432 if (value.length < addrByteLength) {
433 msg = "Invalid " + addressName(version) +
434 " address array: array length: " + value.length +
435 ". Must be at least " + addrByteLength;
436 } else {
437 msg = "Invalid " + addressName(version) +
438 " address array: array offset: " + offset +
439 ". Must be in the interval [0, " +
440 (value.length - addrByteLength) + "]";
441 }
442 throw new IllegalArgumentException(msg);
443 }
Jonathan Hartdec62d42014-09-22 15:59:04 -0700444 }
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800445
446 /**
447 * Creates a byte array for IP network mask prefix.
448 *
449 * @param version the IP address version
450 * @param prefixLength the length of the mask prefix. Must be in the
451 * interval [0, 32] for IPv4, or [0, 128] for IPv6
452 * @return a byte array that contains a mask prefix of the
453 * specified length
454 * @throws IllegalArgumentException if the arguments are invalid
455 */
456 static byte[] makeMaskPrefixArray(Version version, int prefixLength) {
457 int addrByteLength = byteLength(version);
458 int addrBitLength = addrByteLength * Byte.SIZE;
459
460 // Verify the prefix length
461 if ((prefixLength < 0) || (prefixLength > addrBitLength)) {
462 final String msg = "Invalid IP prefix length: " + prefixLength +
463 ". Must be in the interval [0, " + addrBitLength + "].";
464 throw new IllegalArgumentException(msg);
465 }
466
467 // Number of bytes and extra bits that should be all 1s
468 int maskBytes = prefixLength / Byte.SIZE;
469 int maskBits = prefixLength % Byte.SIZE;
470 byte[] mask = new byte[addrByteLength];
471
472 // Set the bytes and extra bits to 1s
473 for (int i = 0; i < maskBytes; i++) {
474 mask[i] = (byte) 0xff; // Set mask bytes to 1s
475 }
476 for (int i = maskBytes; i < addrByteLength; i++) {
477 mask[i] = 0; // Set remaining bytes to 0s
478 }
479 if (maskBits > 0) {
480 mask[maskBytes] = (byte) (0xff << (Byte.SIZE - maskBits));
481 }
482 return mask;
483 }
484
485 /**
486 * Creates a byte array that represents an IP address masked with
487 * a network mask of given mask length.
488 *
489 * @param addr the address to mask
490 * @param prefixLength the length of the mask prefix. Must be in the
491 * interval [0, 32] for IPv4, or [0, 128] for IPv6
492 * @return a byte array that represents the IP address masked with
493 * a mask prefix of the specified length
494 * @throws IllegalArgumentException if the prefix length is invalid
495 */
496 static byte[] makeMaskedAddressArray(final IpAddress addr,
497 int prefixLength) {
498 byte[] mask = IpAddress.makeMaskPrefixArray(addr.version(),
499 prefixLength);
500 byte[] net = new byte[mask.length];
501
502 // Mask each byte
503 for (int i = 0; i < net.length; i++) {
504 net[i] = (byte) (addr.octets[i] & mask[i]);
505 }
506 return net;
507 }
Aaron Kruglikovafdf4de2015-06-24 09:28:22 -0700508
509 /**
510 * Creates a string based on the IPv6 recommendations for canonical representations found here:
511 * https://tools.ietf.org/html/rfc5952#section-1.
512 * @return A properly formatted IPv6 canonical representation.
513 */
514 private String ipv6ToStringHelper() {
515 //Populate a buffer with the string of the full address with leading zeros stripped
516 StringBuffer buff = new StringBuffer();
517 buff.append(String.format("%x:%x:%x:%x:%x:%x:%x:%x",
518 (((octets[0] & BIT_MASK) << 8) | (octets[1] & BIT_MASK)),
519 (((octets[2] & BIT_MASK) << 8) | (octets[3] & BIT_MASK)),
520 (((octets[4] & BIT_MASK) << 8) | (octets[5] & BIT_MASK)),
521 (((octets[6] & BIT_MASK) << 8) | (octets[7] & BIT_MASK)),
522 (((octets[8] & BIT_MASK) << 8) | (octets[9] & BIT_MASK)),
523 (((octets[10] & BIT_MASK) << 8) | (octets[11] & BIT_MASK)),
524 (((octets[12] & BIT_MASK) << 8) | (octets[13] & BIT_MASK)),
525 (((octets[14] & BIT_MASK) << 8) | (octets[15] & BIT_MASK))));
526 //Initialize variables for tracking longest zero subsequence, tiebreaking by first occurence
527 int longestSeqStart, longestSeqLen, currSeqStart, currSeqLen;
528 longestSeqStart = 0;
529 longestSeqLen = 0;
530 currSeqStart = 0;
531 currSeqLen = 0;
532
533 for (int index = 0; index < buff.length(); index++) {
534 if (buff.charAt(index) == ':') {
535 if (currSeqLen != 0 && buff.charAt(index + 1) == '0') {
536 currSeqLen += 1;
537 }
538 } else if (buff.charAt(index) == '0' && ((index == 0) || (buff.charAt(index - 1) == ':'))) {
539 if (currSeqLen == 0) {
540 currSeqStart = index;
541 }
542 currSeqLen += 1;
543 } else {
544 if (currSeqLen > longestSeqLen) {
545 longestSeqStart = currSeqStart;
546 longestSeqLen = currSeqLen;
547 }
548 currSeqLen = 0;
549 }
550 }
551
552 if (currSeqLen > longestSeqLen) {
553 longestSeqLen = currSeqLen;
554 longestSeqStart = currSeqStart;
555 }
556 if (longestSeqLen > 1) {
557 if (buff.length() == (longestSeqStart + longestSeqLen)) {
558 buff.append(':');
559 }
560
561 buff.delete(longestSeqStart, longestSeqStart + longestSeqLen);
562
563 if (longestSeqStart == 0) {
564 buff.insert(0, ':');
565 }
566 }
567
568 return buff.toString();
569 }
Jonathan Hartdec62d42014-09-22 15:59:04 -0700570}