1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.util;
17
18 import io.netty.util.NetUtilInitializations.NetworkIfaceAndInetAddress;
19 import io.netty.util.internal.PlatformDependent;
20 import io.netty.util.internal.StringUtil;
21 import io.netty.util.internal.SystemPropertyUtil;
22 import io.netty.util.internal.logging.InternalLogger;
23 import io.netty.util.internal.logging.InternalLoggerFactory;
24
25 import java.io.BufferedReader;
26 import java.io.File;
27 import java.io.FileReader;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.InputStreamReader;
31 import java.net.Inet4Address;
32 import java.net.Inet6Address;
33 import java.net.InetAddress;
34 import java.net.InetSocketAddress;
35 import java.net.NetworkInterface;
36 import java.net.UnknownHostException;
37 import java.security.AccessController;
38 import java.security.PrivilegedAction;
39 import java.util.Arrays;
40
41 import static io.netty.util.AsciiString.indexOf;
42
43
44
45
46
47
48
49
50 public final class NetUtil {
51
52
53
54
55 public static final Inet4Address LOCALHOST4;
56
57
58
59
60 public static final Inet6Address LOCALHOST6;
61
62
63
64
65
66 public static final InetAddress LOCALHOST;
67
68
69
70
71 public static final NetworkInterface LOOPBACK_IF;
72
73
74
75
76
77 public static final int SOMAXCONN;
78
79
80
81
82 private static final int IPV6_WORD_COUNT = 8;
83
84
85
86
87 private static final int IPV6_MAX_CHAR_COUNT = 39;
88
89
90
91
92 private static final int IPV6_BYTE_COUNT = 16;
93
94
95
96
97 private static final int IPV6_MAX_CHAR_BETWEEN_SEPARATOR = 4;
98
99
100
101
102 private static final int IPV6_MIN_SEPARATORS = 2;
103
104
105
106
107 private static final int IPV6_MAX_SEPARATORS = 8;
108
109
110
111
112 private static final int IPV4_MAX_CHAR_BETWEEN_SEPARATOR = 3;
113
114
115
116
117 private static final int IPV4_SEPARATORS = 3;
118
119
120
121
122 private static final boolean IPV4_PREFERRED = SystemPropertyUtil.getBoolean("java.net.preferIPv4Stack", false);
123
124
125
126
127 private static final boolean IPV6_ADDRESSES_PREFERRED =
128 SystemPropertyUtil.getBoolean("java.net.preferIPv6Addresses", false);
129
130
131
132
133 private static final InternalLogger logger = InternalLoggerFactory.getInstance(NetUtil.class);
134
135 static {
136 logger.debug("-Djava.net.preferIPv4Stack: {}", IPV4_PREFERRED);
137 logger.debug("-Djava.net.preferIPv6Addresses: {}", IPV6_ADDRESSES_PREFERRED);
138
139
140 LOCALHOST4 = NetUtilInitializations.createLocalhost4();
141
142
143 LOCALHOST6 = NetUtilInitializations.createLocalhost6();
144
145 NetworkIfaceAndInetAddress loopback = NetUtilInitializations.determineLoopback(LOCALHOST4, LOCALHOST6);
146 LOOPBACK_IF = loopback.iface();
147 LOCALHOST = loopback.address();
148
149
150
151
152 SOMAXCONN = AccessController.doPrivileged(new SoMaxConnAction());
153 }
154
155 private static final class SoMaxConnAction implements PrivilegedAction<Integer> {
156 @Override
157 public Integer run() {
158
159
160
161
162 int somaxconn = PlatformDependent.isWindows() ? 200 : 128;
163 File file = new File("/proc/sys/net/core/somaxconn");
164 BufferedReader in = null;
165 try {
166
167
168
169 if (file.exists()) {
170 in = new BufferedReader(new FileReader(file));
171 somaxconn = Integer.parseInt(in.readLine());
172 if (logger.isDebugEnabled()) {
173 logger.debug("{}: {}", file, somaxconn);
174 }
175 } else {
176
177 Integer tmp = null;
178 if (SystemPropertyUtil.getBoolean("io.netty.net.somaxconn.trySysctl", false)) {
179 tmp = sysctlGetInt("kern.ipc.somaxconn");
180 if (tmp == null) {
181 tmp = sysctlGetInt("kern.ipc.soacceptqueue");
182 if (tmp != null) {
183 somaxconn = tmp;
184 }
185 } else {
186 somaxconn = tmp;
187 }
188 }
189
190 if (tmp == null) {
191 logger.debug("Failed to get SOMAXCONN from sysctl and file {}. Default: {}", file,
192 somaxconn);
193 }
194 }
195 } catch (Exception e) {
196 if (logger.isDebugEnabled()) {
197 logger.debug("Failed to get SOMAXCONN from sysctl and file {}. Default: {}",
198 file, somaxconn, e);
199 }
200 } finally {
201 if (in != null) {
202 try {
203 in.close();
204 } catch (Exception e) {
205
206 }
207 }
208 }
209 return somaxconn;
210 }
211 }
212
213
214
215
216
217
218 private static Integer sysctlGetInt(String sysctlKey) throws IOException {
219 Process process = new ProcessBuilder("sysctl", sysctlKey).start();
220 try {
221
222 InputStream is = process.getInputStream();
223 InputStreamReader isr = new InputStreamReader(is);
224 BufferedReader br = new BufferedReader(isr);
225 try {
226 String line = br.readLine();
227 if (line != null && line.startsWith(sysctlKey)) {
228 for (int i = line.length() - 1; i > sysctlKey.length(); --i) {
229 if (!Character.isDigit(line.charAt(i))) {
230 return Integer.valueOf(line.substring(i + 1));
231 }
232 }
233 }
234 return null;
235 } finally {
236 br.close();
237 }
238 } finally {
239
240
241
242 process.destroy();
243 }
244 }
245
246
247
248
249
250
251
252
253 public static boolean isIpV4StackPreferred() {
254 return IPV4_PREFERRED;
255 }
256
257
258
259
260
261
262
263
264 public static boolean isIpV6AddressesPreferred() {
265 return IPV6_ADDRESSES_PREFERRED;
266 }
267
268
269
270
271 public static byte[] createByteArrayFromIpAddressString(String ipAddressString) {
272
273 if (isValidIpV4Address(ipAddressString)) {
274 return validIpV4ToBytes(ipAddressString);
275 }
276
277 if (isValidIpV6Address(ipAddressString)) {
278 if (ipAddressString.charAt(0) == '[') {
279 ipAddressString = ipAddressString.substring(1, ipAddressString.length() - 1);
280 }
281
282 int percentPos = ipAddressString.indexOf('%');
283 if (percentPos >= 0) {
284 ipAddressString = ipAddressString.substring(0, percentPos);
285 }
286
287 return getIPv6ByName(ipAddressString, true);
288 }
289 return null;
290 }
291
292
293
294
295
296 public static InetAddress createInetAddressFromIpAddressString(String ipAddressString) {
297 if (isValidIpV4Address(ipAddressString)) {
298 byte[] bytes = validIpV4ToBytes(ipAddressString);
299 try {
300 return InetAddress.getByAddress(bytes);
301 } catch (UnknownHostException e) {
302
303 throw new IllegalStateException(e);
304 }
305 }
306
307 if (isValidIpV6Address(ipAddressString)) {
308 if (ipAddressString.charAt(0) == '[') {
309 ipAddressString = ipAddressString.substring(1, ipAddressString.length() - 1);
310 }
311
312 int percentPos = ipAddressString.indexOf('%');
313 if (percentPos >= 0) {
314 try {
315 int scopeId = Integer.parseInt(ipAddressString.substring(percentPos + 1));
316 ipAddressString = ipAddressString.substring(0, percentPos);
317 byte[] bytes = getIPv6ByName(ipAddressString, true);
318 if (bytes == null) {
319 return null;
320 }
321 try {
322 return Inet6Address.getByAddress(null, bytes, scopeId);
323 } catch (UnknownHostException e) {
324
325 throw new IllegalStateException(e);
326 }
327 } catch (NumberFormatException e) {
328 return null;
329 }
330 }
331 byte[] bytes = getIPv6ByName(ipAddressString, true);
332 if (bytes == null) {
333 return null;
334 }
335 try {
336 return InetAddress.getByAddress(bytes);
337 } catch (UnknownHostException e) {
338
339 throw new IllegalStateException(e);
340 }
341 }
342 return null;
343 }
344
345 private static int decimalDigit(String str, int pos) {
346 return str.charAt(pos) - '0';
347 }
348
349 private static byte ipv4WordToByte(String ip, int from, int toExclusive) {
350 int ret = decimalDigit(ip, from);
351 from++;
352 if (from == toExclusive) {
353 return (byte) ret;
354 }
355 ret = ret * 10 + decimalDigit(ip, from);
356 from++;
357 if (from == toExclusive) {
358 return (byte) ret;
359 }
360 return (byte) (ret * 10 + decimalDigit(ip, from));
361 }
362
363
364 static byte[] validIpV4ToBytes(String ip) {
365 int i;
366 return new byte[] {
367 ipv4WordToByte(ip, 0, i = ip.indexOf('.', 1)),
368 ipv4WordToByte(ip, i + 1, i = ip.indexOf('.', i + 2)),
369 ipv4WordToByte(ip, i + 1, i = ip.indexOf('.', i + 2)),
370 ipv4WordToByte(ip, i + 1, ip.length())
371 };
372 }
373
374
375
376
377 public static int ipv4AddressToInt(Inet4Address ipAddress) {
378 byte[] octets = ipAddress.getAddress();
379
380 return (octets[0] & 0xff) << 24 |
381 (octets[1] & 0xff) << 16 |
382 (octets[2] & 0xff) << 8 |
383 octets[3] & 0xff;
384 }
385
386
387
388
389 public static String intToIpAddress(int i) {
390 StringBuilder buf = new StringBuilder(15);
391 buf.append(i >> 24 & 0xff);
392 buf.append('.');
393 buf.append(i >> 16 & 0xff);
394 buf.append('.');
395 buf.append(i >> 8 & 0xff);
396 buf.append('.');
397 buf.append(i & 0xff);
398 return buf.toString();
399 }
400
401
402
403
404
405
406
407 public static String bytesToIpAddress(byte[] bytes) {
408 return bytesToIpAddress(bytes, 0, bytes.length);
409 }
410
411
412
413
414
415
416
417 public static String bytesToIpAddress(byte[] bytes, int offset, int length) {
418 switch (length) {
419 case 4: {
420 return new StringBuilder(15)
421 .append(bytes[offset] & 0xff)
422 .append('.')
423 .append(bytes[offset + 1] & 0xff)
424 .append('.')
425 .append(bytes[offset + 2] & 0xff)
426 .append('.')
427 .append(bytes[offset + 3] & 0xff).toString();
428 }
429 case 16:
430 return toAddressString(bytes, offset, false);
431 default:
432 throw new IllegalArgumentException("length: " + length + " (expected: 4 or 16)");
433 }
434 }
435
436 public static boolean isValidIpV6Address(String ip) {
437 return isValidIpV6Address((CharSequence) ip);
438 }
439
440 public static boolean isValidIpV6Address(CharSequence ip) {
441 int end = ip.length();
442 if (end < 2) {
443 return false;
444 }
445
446
447 int start;
448 char c = ip.charAt(0);
449 if (c == '[') {
450 end--;
451 if (ip.charAt(end) != ']') {
452
453 return false;
454 }
455 start = 1;
456 c = ip.charAt(1);
457 } else {
458 start = 0;
459 }
460
461 int colons;
462 int compressBegin;
463 if (c == ':') {
464
465 if (ip.charAt(start + 1) != ':') {
466 return false;
467 }
468 colons = 2;
469 compressBegin = start;
470 start += 2;
471 } else {
472 colons = 0;
473 compressBegin = -1;
474 }
475
476 int wordLen = 0;
477 loop:
478 for (int i = start; i < end; i++) {
479 c = ip.charAt(i);
480 if (isValidHexChar(c)) {
481 if (wordLen < 4) {
482 wordLen++;
483 continue;
484 }
485 return false;
486 }
487
488 switch (c) {
489 case ':':
490 if (colons > 7) {
491 return false;
492 }
493 if (ip.charAt(i - 1) == ':') {
494 if (compressBegin >= 0) {
495 return false;
496 }
497 compressBegin = i - 1;
498 } else {
499 wordLen = 0;
500 }
501 colons++;
502 break;
503 case '.':
504
505
506
507 if (compressBegin < 0 && colons != 6 ||
508
509
510 (colons == 7 && compressBegin >= start || colons > 7)) {
511 return false;
512 }
513
514
515
516
517 int ipv4Start = i - wordLen;
518 int j = ipv4Start - 2;
519 if (isValidIPv4MappedChar(ip.charAt(j))) {
520 if (!isValidIPv4MappedChar(ip.charAt(j - 1)) ||
521 !isValidIPv4MappedChar(ip.charAt(j - 2)) ||
522 !isValidIPv4MappedChar(ip.charAt(j - 3))) {
523 return false;
524 }
525 j -= 5;
526 }
527
528 for (; j >= start; --j) {
529 char tmpChar = ip.charAt(j);
530 if (tmpChar != '0' && tmpChar != ':') {
531 return false;
532 }
533 }
534
535
536 int ipv4End = indexOf(ip, '%', ipv4Start + 7);
537 if (ipv4End < 0) {
538 ipv4End = end;
539 }
540 return isValidIpV4Address(ip, ipv4Start, ipv4End);
541 case '%':
542
543 end = i;
544 break loop;
545 default:
546 return false;
547 }
548 }
549
550
551 if (compressBegin < 0) {
552 return colons == 7 && wordLen > 0;
553 }
554
555 return compressBegin + 2 == end ||
556
557 wordLen > 0 && (colons < 8 || compressBegin <= start);
558 }
559
560 private static boolean isValidIpV4Word(CharSequence word, int from, int toExclusive) {
561 int len = toExclusive - from;
562 char c0, c1, c2;
563 if (len < 1 || len > 3 || (c0 = word.charAt(from)) < '0') {
564 return false;
565 }
566 if (len == 3) {
567 return (c1 = word.charAt(from + 1)) >= '0' &&
568 (c2 = word.charAt(from + 2)) >= '0' &&
569 (c0 <= '1' && c1 <= '9' && c2 <= '9' ||
570 c0 == '2' && c1 <= '5' && (c2 <= '5' || c1 < '5' && c2 <= '9'));
571 }
572 return c0 <= '9' && (len == 1 || isValidNumericChar(word.charAt(from + 1)));
573 }
574
575 private static boolean isValidHexChar(char c) {
576 return c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f';
577 }
578
579 private static boolean isValidNumericChar(char c) {
580 return c >= '0' && c <= '9';
581 }
582
583 private static boolean isValidIPv4MappedChar(char c) {
584 return c == 'f' || c == 'F';
585 }
586
587 private static boolean isValidIPv4MappedSeparators(byte b0, byte b1, boolean mustBeZero) {
588
589
590
591 return b0 == b1 && (b0 == 0 || !mustBeZero && b1 == -1);
592 }
593
594 private static boolean isValidIPv4Mapped(byte[] bytes, int currentIndex, int compressBegin, int compressLength) {
595 final boolean mustBeZero = compressBegin + compressLength >= 14;
596 return currentIndex <= 12 && currentIndex >= 2 && (!mustBeZero || compressBegin < 12) &&
597 isValidIPv4MappedSeparators(bytes[currentIndex - 1], bytes[currentIndex - 2], mustBeZero) &&
598 PlatformDependent.isZero(bytes, 0, currentIndex - 3);
599 }
600
601
602
603
604
605
606
607 public static boolean isValidIpV4Address(CharSequence ip) {
608 return isValidIpV4Address(ip, 0, ip.length());
609 }
610
611
612
613
614
615
616
617 public static boolean isValidIpV4Address(String ip) {
618 return isValidIpV4Address(ip, 0, ip.length());
619 }
620
621 private static boolean isValidIpV4Address(CharSequence ip, int from, int toExcluded) {
622 return ip instanceof String ? isValidIpV4Address((String) ip, from, toExcluded) :
623 ip instanceof AsciiString ? isValidIpV4Address((AsciiString) ip, from, toExcluded) :
624 isValidIpV4Address0(ip, from, toExcluded);
625 }
626
627 @SuppressWarnings("DuplicateBooleanBranch")
628 private static boolean isValidIpV4Address(String ip, int from, int toExcluded) {
629 int len = toExcluded - from;
630 int i;
631 return len <= 15 && len >= 7 &&
632 (i = ip.indexOf('.', from + 1)) > 0 && isValidIpV4Word(ip, from, i) &&
633 (i = ip.indexOf('.', from = i + 2)) > 0 && isValidIpV4Word(ip, from - 1, i) &&
634 (i = ip.indexOf('.', from = i + 2)) > 0 && isValidIpV4Word(ip, from - 1, i) &&
635 isValidIpV4Word(ip, i + 1, toExcluded);
636 }
637
638 @SuppressWarnings("DuplicateBooleanBranch")
639 private static boolean isValidIpV4Address(AsciiString ip, int from, int toExcluded) {
640 int len = toExcluded - from;
641 int i;
642 return len <= 15 && len >= 7 &&
643 (i = ip.indexOf('.', from + 1)) > 0 && isValidIpV4Word(ip, from, i) &&
644 (i = ip.indexOf('.', from = i + 2)) > 0 && isValidIpV4Word(ip, from - 1, i) &&
645 (i = ip.indexOf('.', from = i + 2)) > 0 && isValidIpV4Word(ip, from - 1, i) &&
646 isValidIpV4Word(ip, i + 1, toExcluded);
647 }
648
649 @SuppressWarnings("DuplicateBooleanBranch")
650 private static boolean isValidIpV4Address0(CharSequence ip, int from, int toExcluded) {
651 int len = toExcluded - from;
652 int i;
653 return len <= 15 && len >= 7 &&
654 (i = indexOf(ip, '.', from + 1)) > 0 && isValidIpV4Word(ip, from, i) &&
655 (i = indexOf(ip, '.', from = i + 2)) > 0 && isValidIpV4Word(ip, from - 1, i) &&
656 (i = indexOf(ip, '.', from = i + 2)) > 0 && isValidIpV4Word(ip, from - 1, i) &&
657 isValidIpV4Word(ip, i + 1, toExcluded);
658 }
659
660
661
662
663
664
665
666
667 public static Inet6Address getByName(CharSequence ip) {
668 return getByName(ip, true);
669 }
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685 public static Inet6Address getByName(CharSequence ip, boolean ipv4Mapped) {
686 byte[] bytes = getIPv6ByName(ip, ipv4Mapped);
687 if (bytes == null) {
688 return null;
689 }
690 try {
691 return Inet6Address.getByAddress(null, bytes, -1);
692 } catch (UnknownHostException e) {
693 throw new RuntimeException(e);
694 }
695 }
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712 static byte[] getIPv6ByName(CharSequence ip, boolean ipv4Mapped) {
713 final byte[] bytes = new byte[IPV6_BYTE_COUNT];
714 final int ipLength = ip.length();
715 int compressBegin = 0;
716 int compressLength = 0;
717 int currentIndex = 0;
718 int value = 0;
719 int begin = -1;
720 int i = 0;
721 int ipv6Separators = 0;
722 int ipv4Separators = 0;
723 int tmp;
724 for (; i < ipLength; ++i) {
725 final char c = ip.charAt(i);
726 switch (c) {
727 case ':':
728 ++ipv6Separators;
729 if (i - begin > IPV6_MAX_CHAR_BETWEEN_SEPARATOR ||
730 ipv4Separators > 0 || ipv6Separators > IPV6_MAX_SEPARATORS ||
731 currentIndex + 1 >= bytes.length) {
732 return null;
733 }
734 value <<= (IPV6_MAX_CHAR_BETWEEN_SEPARATOR - (i - begin)) << 2;
735
736 if (compressLength > 0) {
737 compressLength -= 2;
738 }
739
740
741
742
743 bytes[currentIndex++] = (byte) (((value & 0xf) << 4) | ((value >> 4) & 0xf));
744 bytes[currentIndex++] = (byte) ((((value >> 8) & 0xf) << 4) | ((value >> 12) & 0xf));
745 tmp = i + 1;
746 if (tmp < ipLength && ip.charAt(tmp) == ':') {
747 ++tmp;
748 if (compressBegin != 0 || (tmp < ipLength && ip.charAt(tmp) == ':')) {
749 return null;
750 }
751 ++ipv6Separators;
752 compressBegin = currentIndex;
753 compressLength = bytes.length - compressBegin - 2;
754 ++i;
755 }
756 value = 0;
757 begin = -1;
758 break;
759 case '.':
760 ++ipv4Separators;
761 tmp = i - begin;
762 if (tmp > IPV4_MAX_CHAR_BETWEEN_SEPARATOR
763 || begin < 0
764 || ipv4Separators > IPV4_SEPARATORS
765 || (ipv6Separators > 0 && (currentIndex + compressLength < 12))
766 || i + 1 >= ipLength
767 || currentIndex >= bytes.length
768 || ipv4Separators == 1 &&
769
770 ((!ipv4Mapped || currentIndex != 0 && !isValidIPv4Mapped(bytes, currentIndex,
771 compressBegin, compressLength)) ||
772 (tmp == 3 && (!isValidNumericChar(ip.charAt(i - 1)) ||
773 !isValidNumericChar(ip.charAt(i - 2)) ||
774 !isValidNumericChar(ip.charAt(i - 3))) ||
775 tmp == 2 && (!isValidNumericChar(ip.charAt(i - 1)) ||
776 !isValidNumericChar(ip.charAt(i - 2))) ||
777 tmp == 1 && !isValidNumericChar(ip.charAt(i - 1))))) {
778 return null;
779 }
780 value <<= (IPV4_MAX_CHAR_BETWEEN_SEPARATOR - tmp) << 2;
781
782
783
784
785 begin = (value & 0xf) * 100 + ((value >> 4) & 0xf) * 10 + ((value >> 8) & 0xf);
786 if (begin > 255) {
787 return null;
788 }
789 bytes[currentIndex++] = (byte) begin;
790 value = 0;
791 begin = -1;
792 break;
793 default:
794 if (!isValidHexChar(c) || (ipv4Separators > 0 && !isValidNumericChar(c))) {
795 return null;
796 }
797 if (begin < 0) {
798 begin = i;
799 } else if (i - begin > IPV6_MAX_CHAR_BETWEEN_SEPARATOR) {
800 return null;
801 }
802
803
804
805
806 value += StringUtil.decodeHexNibble(c) << ((i - begin) << 2);
807 break;
808 }
809 }
810
811 final boolean isCompressed = compressBegin > 0;
812
813 if (ipv4Separators > 0) {
814 if (begin > 0 && i - begin > IPV4_MAX_CHAR_BETWEEN_SEPARATOR ||
815 ipv4Separators != IPV4_SEPARATORS ||
816 currentIndex >= bytes.length) {
817 return null;
818 }
819 if (!(ipv6Separators == 0 || ipv6Separators >= IPV6_MIN_SEPARATORS &&
820 (!isCompressed && (ipv6Separators == 6 && ip.charAt(0) != ':') ||
821 isCompressed && (ipv6Separators < IPV6_MAX_SEPARATORS &&
822 (ip.charAt(0) != ':' || compressBegin <= 2))))) {
823 return null;
824 }
825 value <<= (IPV4_MAX_CHAR_BETWEEN_SEPARATOR - (i - begin)) << 2;
826
827
828
829
830 begin = (value & 0xf) * 100 + ((value >> 4) & 0xf) * 10 + ((value >> 8) & 0xf);
831 if (begin > 255) {
832 return null;
833 }
834 bytes[currentIndex++] = (byte) begin;
835 } else {
836 tmp = ipLength - 1;
837 if (begin > 0 && i - begin > IPV6_MAX_CHAR_BETWEEN_SEPARATOR ||
838 ipv6Separators < IPV6_MIN_SEPARATORS ||
839 !isCompressed && (ipv6Separators + 1 != IPV6_MAX_SEPARATORS ||
840 ip.charAt(0) == ':' || ip.charAt(tmp) == ':') ||
841 isCompressed && (ipv6Separators > IPV6_MAX_SEPARATORS ||
842 (ipv6Separators == IPV6_MAX_SEPARATORS &&
843 (compressBegin <= 2 && ip.charAt(0) != ':' ||
844 compressBegin >= 14 && ip.charAt(tmp) != ':'))) ||
845 currentIndex + 1 >= bytes.length ||
846 begin < 0 && ip.charAt(tmp - 1) != ':' ||
847 compressBegin > 2 && ip.charAt(0) == ':') {
848 return null;
849 }
850 if (begin >= 0 && i - begin <= IPV6_MAX_CHAR_BETWEEN_SEPARATOR) {
851 value <<= (IPV6_MAX_CHAR_BETWEEN_SEPARATOR - (i - begin)) << 2;
852 }
853
854
855
856 bytes[currentIndex++] = (byte) (((value & 0xf) << 4) | ((value >> 4) & 0xf));
857 bytes[currentIndex++] = (byte) ((((value >> 8) & 0xf) << 4) | ((value >> 12) & 0xf));
858 }
859
860 if (currentIndex < bytes.length) {
861 int toBeCopiedLength = currentIndex - compressBegin;
862 int targetIndex = bytes.length - toBeCopiedLength;
863 System.arraycopy(bytes, compressBegin, bytes, targetIndex, toBeCopiedLength);
864
865 Arrays.fill(bytes, compressBegin, targetIndex, (byte) 0);
866 }
867
868 if (ipv4Separators > 0) {
869
870
871
872 bytes[10] = bytes[11] = (byte) 0xff;
873 }
874
875 return bytes;
876 }
877
878
879
880
881
882
883
884
885 public static String toSocketAddressString(InetSocketAddress addr) {
886 String port = String.valueOf(addr.getPort());
887 final StringBuilder sb;
888
889 if (addr.isUnresolved()) {
890 String hostname = getHostname(addr);
891 sb = newSocketAddressStringBuilder(hostname, port, !isValidIpV6Address(hostname));
892 } else {
893 InetAddress address = addr.getAddress();
894 String hostString = toAddressString(address);
895 sb = newSocketAddressStringBuilder(hostString, port, address instanceof Inet4Address);
896 }
897 return sb.append(':').append(port).toString();
898 }
899
900
901
902
903 public static String toSocketAddressString(String host, int port) {
904 String portStr = String.valueOf(port);
905 return newSocketAddressStringBuilder(
906 host, portStr, !isValidIpV6Address(host)).append(':').append(portStr).toString();
907 }
908
909 private static StringBuilder newSocketAddressStringBuilder(String host, String port, boolean ipv4) {
910 int hostLen = host.length();
911 if (ipv4) {
912
913 return new StringBuilder(hostLen + 1 + port.length()).append(host);
914 }
915
916 StringBuilder stringBuilder = new StringBuilder(hostLen + 3 + port.length());
917 if (hostLen > 1 && host.charAt(0) == '[' && host.charAt(hostLen - 1) == ']') {
918 return stringBuilder.append(host);
919 }
920 return stringBuilder.append('[').append(host).append(']');
921 }
922
923
924
925
926
927
928
929
930
931
932
933
934
935 public static String toAddressString(InetAddress ip) {
936 return toAddressString(ip, false);
937 }
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963 public static String toAddressString(InetAddress ip, boolean ipv4Mapped) {
964 if (ip instanceof Inet4Address) {
965 return ip.getHostAddress();
966 }
967 if (!(ip instanceof Inet6Address)) {
968 throw new IllegalArgumentException("Unhandled type: " + ip);
969 }
970
971 return toAddressString(ip.getAddress(), 0, ipv4Mapped);
972 }
973
974 private static String toAddressString(byte[] bytes, int offset, boolean ipv4Mapped) {
975 final int[] words = new int[IPV6_WORD_COUNT];
976 int i;
977 final int end = offset + words.length;
978 for (i = offset; i < end; ++i) {
979 words[i] = ((bytes[i << 1] & 0xff) << 8) | (bytes[(i << 1) + 1] & 0xff);
980 }
981
982
983 int currentStart = -1;
984 int currentLength;
985 int shortestStart = -1;
986 int shortestLength = 0;
987 for (i = 0; i < words.length; ++i) {
988 if (words[i] == 0) {
989 if (currentStart < 0) {
990 currentStart = i;
991 }
992 } else if (currentStart >= 0) {
993 currentLength = i - currentStart;
994 if (currentLength > shortestLength) {
995 shortestStart = currentStart;
996 shortestLength = currentLength;
997 }
998 currentStart = -1;
999 }
1000 }
1001
1002 if (currentStart >= 0) {
1003 currentLength = i - currentStart;
1004 if (currentLength > shortestLength) {
1005 shortestStart = currentStart;
1006 shortestLength = currentLength;
1007 }
1008 }
1009
1010 if (shortestLength == 1) {
1011 shortestLength = 0;
1012 shortestStart = -1;
1013 }
1014
1015
1016 final int shortestEnd = shortestStart + shortestLength;
1017 final StringBuilder b = new StringBuilder(IPV6_MAX_CHAR_COUNT);
1018 if (shortestEnd < 0) {
1019 b.append(Integer.toHexString(words[0]));
1020 for (i = 1; i < words.length; ++i) {
1021 b.append(':');
1022 b.append(Integer.toHexString(words[i]));
1023 }
1024 } else {
1025
1026 final boolean isIpv4Mapped;
1027 if (inRangeEndExclusive(0, shortestStart, shortestEnd)) {
1028 b.append("::");
1029 isIpv4Mapped = ipv4Mapped && (shortestEnd == 5 && words[5] == 0xffff);
1030 } else {
1031 b.append(Integer.toHexString(words[0]));
1032 isIpv4Mapped = false;
1033 }
1034 for (i = 1; i < words.length; ++i) {
1035 if (!inRangeEndExclusive(i, shortestStart, shortestEnd)) {
1036 if (!inRangeEndExclusive(i - 1, shortestStart, shortestEnd)) {
1037
1038 if (!isIpv4Mapped || i == 6) {
1039 b.append(':');
1040 } else {
1041 b.append('.');
1042 }
1043 }
1044 if (isIpv4Mapped && i > 5) {
1045 b.append(words[i] >> 8);
1046 b.append('.');
1047 b.append(words[i] & 0xff);
1048 } else {
1049 b.append(Integer.toHexString(words[i]));
1050 }
1051 } else if (!inRangeEndExclusive(i - 1, shortestStart, shortestEnd)) {
1052
1053 b.append("::");
1054 }
1055 }
1056 }
1057
1058 return b.toString();
1059 }
1060
1061
1062
1063
1064
1065
1066
1067 public static String getHostname(InetSocketAddress addr) {
1068 return PlatformDependent.javaVersion() >= 7 ? addr.getHostString() : addr.getHostName();
1069 }
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082 private static boolean inRangeEndExclusive(int value, int start, int end) {
1083 return value >= start && value < end;
1084 }
1085
1086
1087
1088
1089 private NetUtil() {
1090
1091 }
1092 }