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