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