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