1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.newsclub.net.unix;
19
20 import java.io.ByteArrayInputStream;
21 import java.io.File;
22 import java.io.FileDescriptor;
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.io.ObjectInputStream;
26 import java.io.ObjectOutputStream;
27 import java.net.DatagramSocket;
28 import java.net.InetAddress;
29 import java.net.InetSocketAddress;
30 import java.net.ServerSocket;
31 import java.net.SocketAddress;
32 import java.net.SocketException;
33 import java.net.URI;
34 import java.nio.ByteBuffer;
35 import java.nio.charset.StandardCharsets;
36 import java.util.HashMap;
37 import java.util.Locale;
38 import java.util.Map;
39 import java.util.Objects;
40
41 import org.eclipse.jdt.annotation.NonNull;
42 import org.eclipse.jdt.annotation.Nullable;
43 import org.newsclub.net.unix.pool.ObjectPool;
44 import org.newsclub.net.unix.pool.ObjectPool.Lease;
45
46 import com.google.errorprone.annotations.Immutable;
47 import com.kohlschutter.annotations.compiletime.SuppressFBWarnings;
48
49
50
51
52
53
54 @Immutable
55 @SuppressWarnings({"PMD.CouplingBetweenObjects", "PMD.CyclomaticComplexity"})
56 public abstract class AFSocketAddress extends InetSocketAddress {
57 private static final long serialVersionUID = 1L;
58
59
60
61
62
63 static final AFSocketAddress INTERNAL_DUMMY_BIND = new SentinelSocketAddress(0);
64 static final AFSocketAddress INTERNAL_DUMMY_CONNECT = new SentinelSocketAddress(1);
65 static final AFSocketAddress INTERNAL_DUMMY_DONT_CONNECT = new SentinelSocketAddress(2);
66
67 private static final int SOCKADDR_NATIVE_FAMILY_OFFSET = NativeUnixSocket.isLoaded()
68 ? NativeUnixSocket.sockAddrNativeFamilyOffset() : -1;
69
70 private static final int SOCKADDR_NATIVE_DATA_OFFSET = NativeUnixSocket.isLoaded()
71 ? NativeUnixSocket.sockAddrNativeDataOffset() : -1;
72
73 private static final int SOCKADDR_MAX_LEN = NativeUnixSocket.isLoaded()
74 ? NativeUnixSocket.sockAddrLength(0) : 256;
75
76 private static final Map<AFAddressFamily<?>, Map<Integer, Map<ByteBuffer, AFSocketAddress>>> ADDRESS_CACHE =
77 new HashMap<>();
78
79 static final ObjectPool<ByteBuffer> SOCKETADDRESS_BUFFER_TL = ObjectPool.newThreadLocalPool(
80 () -> {
81 return AFSocketAddress.newSockAddrDirectBuffer(SOCKADDR_MAX_LEN);
82 }, (o) -> {
83 o.clear();
84 return true;
85 });
86
87 private static final boolean USE_DESERIALIZATION_FOR_INIT;
88
89 static {
90 String v = System.getProperty("org.newsclub.net.unix.AFSocketAddress.deserialize", "");
91 USE_DESERIALIZATION_FOR_INIT = v.isEmpty() ? NativeLibraryLoader.isAndroid() : Boolean
92 .parseBoolean(v);
93 }
94
95
96
97
98
99 private byte[] bytes;
100
101
102
103
104 private InetAddress inetAddress = null;
105
106
107
108
109 private transient ByteBuffer nativeAddress;
110
111
112
113
114 private transient AFAddressFamily<?> addressFamily;
115
116
117
118
119
120
121
122
123
124
125 @SuppressFBWarnings("CT_CONSTRUCTOR_THROW")
126 protected AFSocketAddress(int port, final byte[] socketAddress, Lease<ByteBuffer> nativeAddress,
127 AFAddressFamily<?> af) throws SocketException {
128
129
130
131
132
133
134
135 super(AFInetAddress.createUnresolvedHostname(socketAddress, af), port >= 0 && port <= 0xffff
136 ? port : 0);
137 initAFSocketAddress(this, port, socketAddress, nativeAddress, af);
138 }
139
140
141
142
143
144
145
146 @SuppressWarnings("PMD.UnusedFormalParameter")
147 AFSocketAddress(Class<SentinelSocketAddress> clazz, int port) {
148 super(InetAddress.getLoopbackAddress(), port);
149 this.nativeAddress = null;
150 this.bytes = new byte[0];
151 this.addressFamily = null;
152 }
153
154 @SuppressWarnings({"cast", "this-escape"})
155 private static void initAFSocketAddress(AFSocketAddress addr, int port,
156 final byte[] socketAddress, Lease<ByteBuffer> nativeAddress, AFAddressFamily<?> af)
157 throws SocketException {
158 if (socketAddress.length == 0) {
159 throw new SocketException("Illegal address length: " + socketAddress.length);
160 }
161
162 addr.nativeAddress = nativeAddress == null ? null : (ByteBuffer) (Object) nativeAddress.get()
163 .duplicate().rewind();
164 if (port < -1) {
165 throw new IllegalArgumentException("port out of range");
166 } else if (port > 0xffff) {
167 if (!NativeUnixSocket.isLoaded()) {
168 throw (SocketException) new SocketException(
169 "Cannot set SocketAddress port - junixsocket JNI library is not available").initCause(
170 NativeUnixSocket.unsupportedException());
171 }
172 NativeUnixSocket.setPort1(addr, port);
173 }
174
175 addr.bytes = socketAddress.clone();
176 addr.addressFamily = af;
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193 @SuppressFBWarnings("OBJECT_DESERIALIZATION")
194 protected static <A extends AFSocketAddress> A newDeserializedAFSocketAddress(int port,
195 final byte[] socketAddress, Lease<ByteBuffer> nativeAddress, AFAddressFamily<A> af,
196 AFSocketAddressConstructor<A> constructor) throws SocketException {
197 String hostname = AFInetAddress.createUnresolvedHostname(socketAddress, af);
198 if (hostname == null || hostname.isEmpty()) {
199 return constructor.newAFSocketAddress(port, socketAddress, nativeAddress);
200 }
201 try (ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(AFSocketAddress
202 .craftSerializedObject(af.getSocketAddressClass(), hostname, (port >= 0 && port <= 0xffff
203 ? port : 0))))) {
204 @SuppressWarnings("unchecked")
205 A addr = (A) oin.readObject();
206 initAFSocketAddress(addr, port, socketAddress, nativeAddress, af);
207 return addr;
208 } catch (SocketException e) {
209 throw e;
210 } catch (ClassNotFoundException | IOException e) {
211 throw (SocketException) new SocketException("Unexpected deserialization problem").initCause(
212 e);
213 }
214 }
215
216
217
218
219
220
221
222
223
224
225 private static byte[] craftSerializedObject(Class<? extends AFSocketAddress> className,
226 String hostname, int port) {
227 ByteBuffer bb = ByteBuffer.allocate(768);
228 bb.putShort((short) 0xaced);
229 bb.putShort((short) 5);
230 bb.put((byte) 0x73);
231 bb.put((byte) 0x72);
232
233 putShortLengthUtf8(bb, className.getName());
234 bb.putLong(1);
235 bb.putInt(0x02000078);
236 bb.put((byte) 0x72);
237
238 putShortLengthUtf8(bb, AFSocketAddress.class.getName());
239 bb.putLong(serialVersionUID);
240 bb.putInt(0x0300025B);
241 putShortLengthUtf8(bb, "bytes");
242
243 bb.putInt(0x7400025B);
244 bb.putShort((short) 0x424C);
245
246 putShortLengthUtf8(bb, "inetAddress");
247 bb.put((byte) 0x74);
248
249 putShortLengthEncodedClassName(bb, InetAddress.class);
250
251 bb.putShort((short) 0x7872);
252 putShortLengthUtf8(bb, InetSocketAddress.class.getName());
253 bb.putLong(5076001401234631237L);
254
255 bb.putInt(0x03000349);
256 putShortLengthUtf8(bb, "port");
257
258 bb.put((byte) 0x4C);
259 putShortLengthUtf8(bb, "addr");
260
261 bb.putInt(0x71007E00);
262 bb.putShort((short) 0x034C);
263 putShortLengthUtf8(bb, "hostname");
264 bb.put((byte) 0x74);
265
266 putShortLengthEncodedClassName(bb, String.class);
267
268 bb.putShort((short) 0x7872);
269 putShortLengthUtf8(bb, SocketAddress.class.getName());
270 bb.putLong(5215720748342549866L);
271
272 bb.putInt(0x02000078);
273 bb.put((byte) 0x70);
274 bb.putInt(port);
275
276 bb.putShort((short) 0x7074);
277 putShortLengthUtf8(bb, hostname);
278
279 bb.putInt(0x78707077);
280 bb.put((byte) 0x0B);
281
282 putShortLengthUtf8(bb, "undefined");
283
284 bb.put((byte) 0x78);
285 bb.flip();
286
287 byte[] buf = new byte[bb.remaining()];
288 bb.get(buf);
289 return buf;
290 }
291
292 private static void putShortLengthEncodedClassName(ByteBuffer bb, Class<?> klazz) {
293 putShortLengthUtf8(bb, "L" + klazz.getName().replace('.', '/') + ";");
294 }
295
296 private static void putShortLengthUtf8(ByteBuffer bb, String s) {
297 byte[] utf8 = s.getBytes(StandardCharsets.UTF_8);
298 bb.putShort((short) utf8.length);
299 bb.put(utf8);
300 }
301
302
303
304
305
306
307
308
309 protected static boolean isUseDeserializationForInit() {
310 return USE_DESERIALIZATION_FOR_INIT;
311 }
312
313
314
315
316
317
318 public abstract boolean hasFilename();
319
320
321
322
323
324
325
326
327
328
329 public abstract File getFile() throws FileNotFoundException;
330
331
332
333
334
335
336 public final AFAddressFamily<?> getAddressFamily() {
337 return addressFamily;
338 }
339
340
341
342
343
344
345
346
347
348 protected static final InetAddress getInetAddress(FileDescriptor fdesc, boolean peerName,
349 AFAddressFamily<?> af) {
350 if (!fdesc.valid()) {
351 return null;
352 }
353 byte[] addr = NativeUnixSocket.sockname(af.getDomain(), fdesc, peerName);
354 if (addr == null) {
355 return null;
356 }
357 return AFInetAddress.wrapAddress(addr, af);
358 }
359
360
361
362
363
364
365
366
367
368
369
370
371 protected static final <A extends AFSocketAddress> @Nullable A getSocketAddress(
372 FileDescriptor fdesc, boolean requestPeerName, int port, AFAddressFamily<A> af) {
373 if (!fdesc.valid()) {
374 return null;
375 }
376 byte[] addr = NativeUnixSocket.sockname(af.getDomain(), fdesc, requestPeerName);
377 if (addr == null) {
378 return null;
379 }
380 try {
381
382 return AFSocketAddress.unwrap(AFInetAddress.wrapAddress(addr, af), port, af);
383 } catch (SocketException e) {
384 throw new IllegalStateException(e);
385 }
386 }
387
388
389
390
391
392
393
394
395
396
397
398 @SuppressWarnings("PMD.ReturnEmptyCollectionRatherThanNull")
399 static final <A extends AFSocketAddress> byte[] getSocketAddressBytes(FileDescriptor fdesc,
400 boolean requestPeerName, AFAddressFamily<A> af) {
401 if (!fdesc.valid()) {
402 return null;
403 }
404 byte[] addr = NativeUnixSocket.sockname(af.getDomain(), fdesc, requestPeerName);
405 if (addr == null) {
406 return null;
407 }
408 return addr.clone();
409 }
410
411 static final AFSocketAddress preprocessSocketAddress(
412 Class<? extends AFSocketAddress> supportedAddressClass, SocketAddress endpoint,
413 AFSocketAddressFromHostname<?> afh) throws SocketException {
414 Objects.requireNonNull(endpoint);
415 if (endpoint instanceof SentinelSocketAddress) {
416 return (SentinelSocketAddress) endpoint;
417 }
418
419 if (!(endpoint instanceof AFSocketAddress)) {
420 if (afh != null) {
421 if (endpoint instanceof InetSocketAddress) {
422 InetSocketAddress isa = (InetSocketAddress) endpoint;
423
424 String hostname = isa.getHostString();
425 if (afh.isHostnameSupported(hostname)) {
426 try {
427 endpoint = afh.addressFromHost(hostname, isa.getPort());
428 } catch (SocketException e) {
429 throw e;
430 }
431 }
432 }
433 }
434 endpoint = mapOrFail(endpoint, supportedAddressClass);
435 }
436
437 Objects.requireNonNull(endpoint);
438
439 if (!supportedAddressClass.isAssignableFrom(endpoint.getClass())) {
440 throw new IllegalArgumentException("Can only connect to endpoints of type "
441 + supportedAddressClass.getName() + ", got: " + endpoint.getClass() + ": " + endpoint);
442 }
443
444 return (AFSocketAddress) endpoint;
445 }
446
447
448
449
450
451
452 protected final byte[] getBytes() {
453 return bytes;
454 }
455
456
457
458
459
460
461
462
463
464
465
466
467 public final InetAddress wrapAddress() {
468 return AFInetAddress.wrapAddress(bytes, getAddressFamily());
469 }
470
471
472
473
474
475
476
477 @FunctionalInterface
478 protected interface AFSocketAddressConstructor<T extends AFSocketAddress> {
479
480
481
482
483
484
485
486
487
488 @NonNull
489 T newAFSocketAddress(int port, byte[] socketAddress, Lease<ByteBuffer> nativeAddress)
490 throws SocketException;
491 }
492
493
494
495
496
497
498
499
500
501
502
503
504 @SuppressWarnings({"unchecked", "null"})
505 protected static final <A extends AFSocketAddress> A resolveAddress(final byte[] socketAddress,
506 int port, AFAddressFamily<A> af) throws SocketException {
507 if (socketAddress.length == 0) {
508 throw new SocketException("Address cannot be empty");
509 }
510
511 if (port == -1) {
512 port = 0;
513 }
514
515 try (Lease<ByteBuffer> lease = SOCKETADDRESS_BUFFER_TL.take()) {
516 ByteBuffer direct = lease.get();
517 int limit = NativeUnixSocket.isLoaded() ? NativeUnixSocket.bytesToSockAddr(af.getDomain(),
518 direct, socketAddress) : -1;
519 if (limit == -1) {
520
521 return af.getAddressConstructor().newAFSocketAddress(port, socketAddress, null);
522 } else if (limit > SOCKADDR_MAX_LEN) {
523 throw new IllegalStateException("Unexpected address length");
524 }
525 direct.rewind();
526 direct.limit(limit);
527
528 A instance;
529 synchronized (AFSocketAddress.class) {
530 Map<ByteBuffer, AFSocketAddress> map;
531 Map<Integer, Map<ByteBuffer, AFSocketAddress>> mapPorts = ADDRESS_CACHE.get(af);
532 if (mapPorts == null) {
533 instance = null;
534 mapPorts = new HashMap<>();
535 map = new HashMap<>();
536 mapPorts.put(port, map);
537 ADDRESS_CACHE.put(af, mapPorts);
538 } else {
539 map = mapPorts.get(port);
540 if (map == null) {
541 instance = null;
542 map = new HashMap<>();
543 mapPorts.put(port, map);
544 } else {
545 instance = (A) map.get(direct);
546 }
547 }
548
549 if (instance == null) {
550 ByteBuffer key = newSockAddrKeyBuffer(limit);
551 key.put(direct);
552 key = key.asReadOnlyBuffer();
553
554 instance = af.getAddressConstructor().newAFSocketAddress(port, socketAddress, ObjectPool
555 .unpooledLease(key));
556
557 map.put(key, instance);
558 }
559 }
560 return instance;
561 }
562 }
563
564 @SuppressWarnings("null")
565 static final <A extends AFSocketAddress> A ofInternal(ByteBuffer socketAddressBuffer,
566 AFAddressFamily<A> af) throws SocketException {
567 synchronized (AFSocketAddress.class) {
568 socketAddressBuffer.rewind();
569
570 Map<Integer, Map<ByteBuffer, AFSocketAddress>> mapPorts = ADDRESS_CACHE.get(af);
571 if (mapPorts != null) {
572 Map<ByteBuffer, AFSocketAddress> map = mapPorts.get(0);
573
574 if (map != null) {
575 @SuppressWarnings("unchecked")
576 A address = (A) map.get(socketAddressBuffer);
577 if (address != null) {
578 return address;
579 }
580 }
581 }
582
583 try (Lease<ByteBuffer> leasedBuffer = socketAddressBuffer.isDirect() ? null
584 : getNativeAddressDirectBuffer(Math.min(socketAddressBuffer.limit(), SOCKADDR_MAX_LEN))) {
585 if (leasedBuffer != null) {
586 ByteBuffer buf = leasedBuffer.get();
587 buf.put(socketAddressBuffer);
588 socketAddressBuffer = buf;
589 }
590
591 byte[] sockAddrToBytes = NativeUnixSocket.sockAddrToBytes(af.getDomain(),
592 socketAddressBuffer);
593 if (sockAddrToBytes == null) {
594 return null;
595 } else {
596 return AFSocketAddress.resolveAddress(sockAddrToBytes, 0, af);
597 }
598 }
599 }
600 }
601
602
603
604
605
606
607
608 protected final synchronized InetAddress getInetAddress(AFAddressFamily<?> af) {
609 if (inetAddress == null) {
610 inetAddress = AFInetAddress.wrapAddress(bytes, af);
611 }
612 return inetAddress;
613 }
614
615
616
617
618
619
620 protected final InetAddress getInetAddress() {
621 return getInetAddress(getAddressFamily());
622 }
623
624 @SuppressWarnings("null")
625 static final @NonNull ByteBuffer newSockAddrDirectBuffer(int length) {
626 return ByteBuffer.allocateDirect(length);
627 }
628
629 @SuppressWarnings("null")
630 static final @NonNull ByteBuffer newSockAddrKeyBuffer(int length) {
631 return ByteBuffer.allocate(length);
632 }
633
634
635
636
637
638
639
640
641
642
643
644
645
646 @SuppressWarnings("null")
647 @NonNull
648 protected static final <A extends AFSocketAddress> A unwrap(InetAddress address, int port,
649 AFAddressFamily<A> af) throws SocketException {
650 Objects.requireNonNull(address);
651 return resolveAddress(AFInetAddress.unwrapAddress(address, af), port, af);
652 }
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667 @SuppressWarnings("null")
668 @NonNull
669 protected static final <A extends AFSocketAddress> A unwrap(String hostname, int port,
670 AFAddressFamily<A> af) throws SocketException {
671 Objects.requireNonNull(hostname);
672 return resolveAddress(AFInetAddress.unwrapAddress(hostname, af), port, af);
673 }
674
675 static final int unwrapAddressDirectBufferInternal(ByteBuffer socketAddressBuffer,
676 SocketAddress address) throws SocketException {
677 if (!NativeUnixSocket.isLoaded()) {
678 throw new SocketException("Unsupported operation; junixsocket native library is not loaded");
679 }
680 Objects.requireNonNull(address);
681
682 address = AFSocketAddress.mapOrFail(address, AFSocketAddress.class);
683 AFSocketAddress socketAddress = (AFSocketAddress) address;
684
685 byte[] addr = socketAddress.getBytes();
686 int domain = socketAddress.getAddressFamily().getDomain();
687
688 int len = NativeUnixSocket.bytesToSockAddr(domain, socketAddressBuffer, addr);
689 if (len == -1) {
690 throw new SocketException("Unsupported domain");
691 }
692 return len;
693 }
694
695
696
697
698
699
700
701 final Lease<ByteBuffer> getNativeAddressDirectBuffer() throws SocketException {
702 ByteBuffer address = nativeAddress;
703 if (address == null) {
704 throw (SocketException) new SocketException("Cannot access native address").initCause(
705 NativeUnixSocket.unsupportedException());
706 }
707 address = address.duplicate();
708
709 Lease<ByteBuffer> lease = getNativeAddressDirectBuffer(address.limit());
710 ByteBuffer direct = lease.get();
711 address.position(0);
712 direct.put(address);
713
714 return lease;
715 }
716
717 static final Lease<ByteBuffer> getNativeAddressDirectBuffer(int limit) {
718 Lease<ByteBuffer> lease = SOCKETADDRESS_BUFFER_TL.take();
719 ByteBuffer direct = lease.get();
720 direct.position(0);
721 direct.limit(limit);
722 return lease;
723 }
724
725
726
727
728
729
730
731
732 protected static final boolean isSupportedAddress(InetAddress addr, AFAddressFamily<?> af) {
733 return AFInetAddress.isSupportedAddress(addr, af);
734 }
735
736
737
738
739
740
741
742
743
744 public final void writeNativeAddressTo(ByteBuffer buf) throws IOException {
745 if (nativeAddress == null) {
746 throw (SocketException) new SocketException("Cannot access native address").initCause(
747 NativeUnixSocket.unsupportedException());
748 }
749 buf.put(nativeAddress);
750 }
751
752
753
754
755
756
757
758 public AFSocket<?> newConnectedSocket() throws IOException {
759 AFSocket<?> socket = getAddressFamily().newSocket();
760 socket.connect(this);
761 return socket;
762 }
763
764
765
766
767
768
769
770 public AFServerSocket<?> newBoundServerSocket() throws IOException {
771 AFServerSocket<?> serverSocket = getAddressFamily().newServerSocket();
772 serverSocket.bind(this);
773 return serverSocket;
774 }
775
776
777
778
779
780
781
782
783
784 public AFServerSocket<?> newForceBoundServerSocket() throws IOException {
785 AFServerSocket<?> serverSocket = getAddressFamily().newServerSocket();
786 serverSocket.forceBindAddress(this).bind(this);
787 return serverSocket;
788 }
789
790
791
792
793
794
795
796
797
798
799
800
801 @SuppressWarnings("PMD.ShortMethodName")
802 public static AFSocketAddress of(URI u) throws SocketException {
803 return of(u, -1);
804 }
805
806
807
808
809
810
811
812
813
814
815
816
817
818 @SuppressWarnings("PMD.ShortMethodName")
819 public static AFSocketAddress of(URI u, int overridePort) throws SocketException {
820 AFAddressFamily<?> af = AFAddressFamily.getAddressFamily(u);
821 if (af == null) {
822 throw new SocketException("Cannot resolve AFSocketAddress from URI scheme: " + u.getScheme());
823 }
824 return af.parseURI(u, overridePort);
825 }
826
827
828
829
830
831
832
833
834
835
836 public URI toURI(String scheme, URI template) throws IOException {
837 throw new IOException("Unsupported operation");
838 }
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854 public @Nullable String toSocatAddressString(AFSocketType socketType,
855 AFSocketProtocol socketProtocol) throws IOException {
856
857 if (SOCKADDR_NATIVE_FAMILY_OFFSET == -1 || SOCKADDR_NATIVE_DATA_OFFSET == -1) {
858 return null;
859 }
860 if (nativeAddress == null) {
861 throw (SocketException) new SocketException("Cannot access native address").initCause(
862 NativeUnixSocket.unsupportedException());
863 }
864 if (socketProtocol != null && socketProtocol.getId() != 0) {
865 throw new IOException("Protocol not (yet) supported");
866 }
867
868 int family = (nativeAddress.get(SOCKADDR_NATIVE_FAMILY_OFFSET) & 0xFF);
869 int type = socketType == null ? -1 : NativeUnixSocket.sockTypeToNative(socketType.getId());
870 StringBuilder sb = new StringBuilder();
871 sb.append(family);
872 if (type != -1) {
873 sb.append(':');
874 sb.append(type);
875 }
876 if (socketProtocol != null) {
877 sb.append(':');
878 sb.append(socketProtocol.getId());
879 }
880 sb.append(":x");
881 int n = nativeAddress.limit();
882 while (n > 1 && nativeAddress.get(n - 1) == 0) {
883 n--;
884 }
885 for (int pos = SOCKADDR_NATIVE_DATA_OFFSET; pos < n; pos++) {
886 byte b = nativeAddress.get(pos);
887 sb.append(String.format(Locale.ENGLISH, "%02x", b));
888 }
889 return sb.toString();
890 }
891
892
893
894
895
896
897
898
899
900
901
902
903
904 public boolean covers(AFSocketAddress other) {
905 return this.equals(other);
906 }
907
908
909
910
911
912
913
914
915 private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
916 in.defaultReadObject();
917
918 String af = in.readUTF();
919 if ("undefined".equals(af)) {
920 this.addressFamily = null;
921 } else {
922 this.addressFamily = Objects.requireNonNull(AFAddressFamily.getAddressFamily(af),
923 "address family");
924 }
925 }
926
927
928
929
930
931
932
933 private void writeObject(ObjectOutputStream out) throws IOException {
934 out.defaultWriteObject();
935 out.writeUTF(addressFamily == null ? "undefined" : addressFamily.getJuxString());
936 }
937
938
939
940
941
942
943
944
945
946 static String toUnsignedString(int i) {
947 return Long.toString(toUnsignedLong(i));
948 }
949
950
951
952
953
954
955
956
957
958 static String toUnsignedString(int i, int radix) {
959 return Long.toUnsignedString(toUnsignedLong(i), radix);
960 }
961
962 private static long toUnsignedLong(long x) {
963 return x & 0xffffffffL;
964 }
965
966
967
968
969
970
971
972
973
974
975
976 protected static int parseUnsignedInt(String s, int radix) throws NumberFormatException {
977 if (s == null || s.isEmpty()) {
978 throw new NumberFormatException("Cannot parse null or empty string");
979 }
980
981 int len = s.length();
982 if (s.startsWith("-")) {
983 throw new NumberFormatException("Illegal leading minus sign on unsigned string " + s);
984 }
985
986 if (len <= 5 || (radix == 10 && len <= 9)) {
987 return Integer.parseInt(s, radix);
988 } else {
989 long ell = Long.parseLong(s, radix);
990 if ((ell & 0xffff_ffff_0000_0000L) == 0) {
991 return (int) ell;
992 } else {
993 throw new NumberFormatException("String value exceeds " + "range of unsigned int: " + s);
994 }
995 }
996 }
997
998
999
1000
1001
1002
1003
1004
1005
1006 public static boolean canMap(SocketAddress addr) {
1007 return canMap(addr, AFSocketAddress.class);
1008 }
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020 public static boolean canMap(SocketAddress addr,
1021 Class<? extends AFSocketAddress> targetAddressClass) {
1022 if (addr == null) {
1023 return true;
1024 } else if (targetAddressClass.isAssignableFrom(addr.getClass())) {
1025 return true;
1026 }
1027 AFSupplier<? extends AFSocketAddress> supplier = SocketAddressUtil.supplyAFSocketAddress(addr);
1028 if (supplier == null) {
1029 return false;
1030 }
1031 AFSocketAddress afAddr = supplier.get();
1032 if (afAddr == null) {
1033 return false;
1034 }
1035 return (targetAddressClass.isAssignableFrom(afAddr.getClass()));
1036 }
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046 public static AFSocketAddress mapOrFail(SocketAddress addr) {
1047 return mapOrFail(addr, AFSocketAddress.class);
1048 }
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060 @SuppressWarnings("null")
1061 public static <A extends AFSocketAddress> A mapOrFail(SocketAddress addr,
1062 Class<A> targetAddressClass) {
1063 if (addr == null) {
1064 return null;
1065 } else if (targetAddressClass.isAssignableFrom(addr.getClass())) {
1066 return targetAddressClass.cast(addr);
1067 }
1068
1069 AFSupplier<? extends AFSocketAddress> supplier = SocketAddressUtil.supplyAFSocketAddress(addr);
1070 if (supplier == null) {
1071 throw new IllegalArgumentException("Can only bind to endpoints of type "
1072 + AFSocketAddress.class.getName() + ": " + addr);
1073 }
1074 AFSocketAddress afAddr = supplier.get();
1075 if (afAddr == null || !targetAddressClass.isAssignableFrom(afAddr.getClass())) {
1076 throw new IllegalArgumentException("Can only bind to endpoints of type "
1077 + AFSocketAddress.class.getName() + ", and this specific address is unsupported: "
1078 + addr);
1079 }
1080 return targetAddressClass.cast(afAddr);
1081 }
1082 }