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.File;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.Serializable;
24 import java.net.InetAddress;
25 import java.net.InetSocketAddress;
26 import java.net.SocketAddress;
27 import java.net.SocketException;
28 import java.net.URI;
29 import java.nio.ByteBuffer;
30 import java.util.Arrays;
31 import java.util.HashSet;
32 import java.util.Locale;
33 import java.util.Objects;
34 import java.util.Set;
35 import java.util.regex.Matcher;
36 import java.util.regex.Pattern;
37
38 import org.eclipse.jdt.annotation.NonNull;
39 import org.eclipse.jdt.annotation.NonNullByDefault;
40 import org.newsclub.net.unix.pool.ObjectPool.Lease;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 public final class AFTIPCSocketAddress extends AFSocketAddress {
114 private static final long serialVersionUID = 1L;
115
116 private static final Pattern PAT_TIPC_URI_HOST_AND_PORT = Pattern.compile(
117 "^((?:(?:(?<scope>cluster|node|default|[0-9a-fx]+)\\-)?(?<type>service|service-range|socket)\\.)|"
118 + "(?<scope2>cluster|node|default|[0-9a-fx]+)\\-(?<type2>[0-9a-fx]+)\\.)?"
119 + "(?<a>[0-9a-fx]+)\\.(?<b>[0-9a-fx]+)(?:\\.(?<c>[0-9a-fx]+))?(?:\\:(?<javaPort>[0-9]+))?$");
120
121
122
123
124 public static final int TIPC_TOP_SRV = 1;
125
126
127
128
129 public static final int TIPC_RESERVED_TYPES = 64;
130
131 private static AFAddressFamily<AFTIPCSocketAddress> afTipc;
132
133
134
135
136
137
138 @NonNullByDefault
139 public static final class AddressType extends NamedInteger {
140 private static final long serialVersionUID = 1L;
141
142
143
144
145 public static final AddressType SERVICE_RANGE;
146
147
148
149
150 public static final AddressType SERVICE_ADDR;
151
152
153
154
155 public static final AddressType SOCKET_ADDR;
156
157 private static final @NonNull AddressType[] VALUES = init(new @NonNull AddressType[] {
158 SERVICE_RANGE = new AddressType("SERVICE_RANGE", 1,
159 (a, b, c) -> formatTIPCInt(a) + "@" + formatTIPCInt(b) + "-" + formatTIPCInt(c)),
160 SERVICE_ADDR = new AddressType("SERVICE_ADDR", 2,
161 (a, b, c) -> formatTIPCInt(a) + "@" + formatTIPCInt(b) + (c == 0 ? "" : ":"
162 + formatTIPCInt(c))),
163 SOCKET_ADDR = new AddressType("SOCKET_ADDR", 3,
164 (a, b, c) -> formatTIPCInt(a) + "@" + formatTIPCInt(b) + (c == 0 ? "" : ":"
165 + formatTIPCInt(c))),
166 });
167
168
169
170
171 private final DebugStringProvider ds;
172
173 private AddressType(int id) {
174 super(id);
175 this.ds = (a, b, c) -> ":" + toUnsignedString(a) + ":" + toUnsignedString(b) + ":"
176 + toUnsignedString(c);
177 }
178
179 private AddressType(String name, int id, DebugStringProvider ds) {
180 super(name, id);
181 this.ds = ds;
182 }
183
184 static AddressType ofValue(int v) {
185 return ofValue(VALUES, AddressType::new, v);
186 }
187
188 @FunctionalInterface
189 interface DebugStringProvider extends Serializable {
190 String toDebugString(int a, int b, int c);
191 }
192
193
194
195
196
197
198
199 @SuppressWarnings("null")
200 public static String formatTIPCInt(int i) {
201 return String.format(Locale.ENGLISH, "0x%08x", (i & 0xFFFFFFFFL));
202 }
203
204 private String toDebugString(Scope scope, int a, int b, int c) {
205 if (this == SOCKET_ADDR && scope.equals(Scope.SCOPE_NOT_SPECIFIED)) {
206 return name() + "(" + value() + ");" + ds.toDebugString(a, b, c);
207 } else {
208 return name() + "(" + value() + ");" + scope + ":" + ds.toDebugString(a, b, c);
209 }
210 }
211 }
212
213
214
215
216
217
218 @NonNullByDefault
219 public static final class Scope extends NamedInteger {
220 private static final long serialVersionUID = 1L;
221
222
223
224
225 public static final Scope SCOPE_CLUSTER;
226
227
228
229
230 public static final Scope SCOPE_NODE;
231
232
233
234
235 public static final Scope SCOPE_NOT_SPECIFIED;
236
237 private static final @NonNull Scope[] VALUES = init(new @NonNull Scope[] {
238 SCOPE_NOT_SPECIFIED = new Scope("SCOPE_NOT_SPECIFIED", 0),
239 SCOPE_CLUSTER = new Scope("SCOPE_CLUSTER", 2),
240 SCOPE_NODE = new Scope("SCOPE_NODE", 3),
241 });
242
243 private Scope(int id) {
244 super(id);
245 }
246
247 private Scope(String name, int id) {
248 super(name, id);
249 }
250
251
252
253
254
255
256
257 public static Scope ofValue(int v) {
258 return ofValue(VALUES, Scope::new, v);
259 }
260 }
261
262 private AFTIPCSocketAddress(int port, final byte[] socketAddress, Lease<ByteBuffer> nativeAddress)
263 throws SocketException {
264 super(port, socketAddress, nativeAddress, addressFamily());
265 }
266
267 private static AFTIPCSocketAddress newAFSocketAddress(int port, final byte[] socketAddress,
268 Lease<ByteBuffer> nativeAddress) throws SocketException {
269 return newDeserializedAFSocketAddress(port, socketAddress, nativeAddress, addressFamily(),
270 AFTIPCSocketAddress::new);
271 }
272
273
274
275
276
277
278
279
280
281
282
283 public static AFTIPCSocketAddress ofService(Scope scope, int type, int instance)
284 throws SocketException {
285 return ofService(scope, type, instance, 0);
286 }
287
288
289
290
291
292
293
294
295
296
297 public static AFTIPCSocketAddress ofService(int type, int instance) throws SocketException {
298 return ofService(Scope.SCOPE_CLUSTER, type, instance, 0);
299 }
300
301
302
303
304
305
306
307
308
309
310
311
312
313 public static AFTIPCSocketAddress ofService(Scope scope, int type, int instance, int domain)
314 throws SocketException {
315 return ofService(0, scope, type, instance, domain);
316 }
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332 public static AFTIPCSocketAddress ofService(int javaPort, Scope scope, int type, int instance,
333 int domain) throws SocketException {
334 return resolveAddress(toBytes(AddressType.SERVICE_ADDR, scope, type, instance, domain),
335 javaPort, addressFamily());
336 }
337
338
339
340
341
342
343
344
345
346
347
348
349 public static AFTIPCSocketAddress ofServiceRange(Scope scope, int type, int lower, int upper)
350 throws SocketException {
351 return ofServiceRange(0, scope, type, lower, upper);
352 }
353
354
355
356
357
358
359
360
361
362
363
364 public static AFTIPCSocketAddress ofServiceRange(int type, int lower, int upper)
365 throws SocketException {
366 return ofServiceRange(0, Scope.SCOPE_CLUSTER, type, lower, upper);
367 }
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382 public static AFTIPCSocketAddress ofServiceRange(int javaPort, Scope scope, int type, int lower,
383 int upper) throws SocketException {
384 return resolveAddress(toBytes(AddressType.SERVICE_RANGE, scope, type, lower, upper), javaPort,
385 addressFamily());
386 }
387
388
389
390
391
392
393
394
395
396
397
398
399 public static AFTIPCSocketAddress ofSocket(int ref, int node) throws SocketException {
400 return ofSocket(0, ref, node);
401 }
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416 public static AFTIPCSocketAddress ofSocket(int javaPort, int ref, int node)
417 throws SocketException {
418 return resolveAddress(toBytes(AddressType.SOCKET_ADDR, Scope.SCOPE_NOT_SPECIFIED, ref, node, 0),
419 javaPort, addressFamily());
420 }
421
422
423
424
425
426
427
428 public static AFTIPCSocketAddress ofTopologyService() throws SocketException {
429 return resolveAddress(toBytes(AddressType.SERVICE_ADDR, Scope.SCOPE_NOT_SPECIFIED, TIPC_TOP_SRV,
430 TIPC_TOP_SRV, 0), 0, addressFamily());
431 }
432
433 private static int parseUnsignedInt(String v) {
434 if (v.startsWith("0x")) {
435 return parseUnsignedInt(v.substring(2), 16);
436 } else {
437 return parseUnsignedInt(v, 10);
438 }
439 }
440
441
442
443
444
445
446
447
448
449
450
451 public static AFTIPCSocketAddress unwrap(InetAddress address, int port) throws SocketException {
452 return AFSocketAddress.unwrap(address, port, addressFamily());
453 }
454
455
456
457
458
459
460
461
462
463
464
465
466 public static AFTIPCSocketAddress unwrap(String hostname, int port) throws SocketException {
467 return AFSocketAddress.unwrap(hostname, port, addressFamily());
468 }
469
470
471
472
473
474
475
476
477
478 public static AFTIPCSocketAddress unwrap(SocketAddress address) throws SocketException {
479 Objects.requireNonNull(address);
480 if (!isSupportedAddress(address)) {
481 throw new SocketException("Unsupported address");
482 }
483 return (AFTIPCSocketAddress) address;
484 }
485
486
487
488
489
490
491 public Scope getScope() {
492 byte[] bytes = getBytes();
493 if (bytes.length != (5 * 4)) {
494 return Scope.SCOPE_NOT_SPECIFIED;
495 }
496 return Scope.ofValue(ByteBuffer.wrap(bytes, 4, 4).getInt());
497 }
498
499
500
501
502
503
504 public int getTIPCType() {
505 ByteBuffer bb = ByteBuffer.wrap(getBytes());
506 int a = bb.getInt(2 * 4);
507 return a;
508 }
509
510
511
512
513
514
515 public int getTIPCInstance() {
516 ByteBuffer bb = ByteBuffer.wrap(getBytes());
517 int a = bb.getInt(3 * 4);
518 return a;
519 }
520
521
522
523
524
525
526 public int getTIPCDomain() {
527 ByteBuffer bb = ByteBuffer.wrap(getBytes());
528 int a = bb.getInt(4 * 4);
529 return a;
530 }
531
532
533
534
535
536
537 public int getTIPCLower() {
538 ByteBuffer bb = ByteBuffer.wrap(getBytes());
539 int a = bb.getInt(2 * 4);
540 return a;
541 }
542
543
544
545
546
547
548 public int getTIPCUpper() {
549 ByteBuffer bb = ByteBuffer.wrap(getBytes());
550 int a = bb.getInt(3 * 4);
551 return a;
552 }
553
554
555
556
557
558
559 public int getTIPCRef() {
560 ByteBuffer bb = ByteBuffer.wrap(getBytes());
561 int a = bb.getInt(2 * 4);
562 return a;
563 }
564
565
566
567
568
569
570 public int getTIPCNodeHash() {
571 ByteBuffer bb = ByteBuffer.wrap(getBytes());
572 int a = bb.getInt(3 * 4);
573 return a;
574 }
575
576 @Override
577 public String toString() {
578 int port = getPort();
579
580 byte[] bytes = getBytes();
581 if (bytes.length != (5 * 4)) {
582 return getClass().getName() + "[" + (port == 0 ? "" : "port=" + port) + ";UNKNOWN" + "]";
583 }
584
585 ByteBuffer bb = ByteBuffer.wrap(bytes);
586 int typeId = bb.getInt();
587 int scopeId = bb.getInt();
588 int a = bb.getInt();
589 int b = bb.getInt();
590 int c = bb.getInt();
591
592 Scope scope = Scope.ofValue((byte) scopeId);
593
594 AddressType type = AddressType.ofValue(typeId);
595 String typeString = type.toDebugString(scope, a, b, c);
596
597 return getClass().getName() + "[" + (port == 0 ? "" : "port=" + port + ";") + typeString + "]";
598 }
599
600 @Override
601 public boolean hasFilename() {
602 return false;
603 }
604
605 @Override
606 public File getFile() throws FileNotFoundException {
607 throw new FileNotFoundException("no file");
608 }
609
610
611
612
613
614
615
616
617
618 public static boolean isSupportedAddress(InetAddress addr) {
619 return AFSocketAddress.isSupportedAddress(addr, addressFamily());
620 }
621
622
623
624
625
626
627
628
629 public static boolean isSupportedAddress(SocketAddress addr) {
630 return (addr instanceof AFTIPCSocketAddress);
631 }
632
633 @SuppressWarnings("cast")
634 private static byte[] toBytes(AddressType addrType, Scope scope, int a, int b, int c) {
635 ByteBuffer bb = ByteBuffer.allocate(5 * 4);
636 bb.putInt(addrType.value());
637 bb.putInt(scope.value());
638 bb.putInt(a);
639 bb.putInt(b);
640 bb.putInt(c);
641 return (byte[]) bb.flip().array();
642 }
643
644
645
646
647
648
649 @SuppressWarnings("null")
650 public static synchronized AFAddressFamily<AFTIPCSocketAddress> addressFamily() {
651 if (afTipc == null) {
652 afTipc = AFAddressFamily.registerAddressFamily("tipc",
653 AFTIPCSocketAddress.class, new AFSocketAddressConfig<AFTIPCSocketAddress>() {
654
655 private final AFSocketAddressConstructor<AFTIPCSocketAddress> addrConstr =
656 isUseDeserializationForInit() ? AFTIPCSocketAddress::newAFSocketAddress
657 : AFTIPCSocketAddress::new;
658
659 @Override
660 protected AFTIPCSocketAddress parseURI(URI u, int port) throws SocketException {
661 return AFTIPCSocketAddress.of(u, port);
662 }
663
664 @Override
665 protected AFSocketAddressConstructor<AFTIPCSocketAddress> addressConstructor() {
666 return addrConstr;
667 }
668
669 @Override
670 protected String selectorProviderClassname() {
671 return "org.newsclub.net.unix.tipc.AFTIPCSelectorProvider";
672 }
673
674 @Override
675 protected Set<String> uriSchemes() {
676 return new HashSet<>(Arrays.asList("tipc", "http+tipc", "https+tipc"));
677 }
678 });
679 try {
680 Class.forName("org.newsclub.net.unix.tipc.AFTIPCSelectorProvider");
681 } catch (ClassNotFoundException e) {
682
683 }
684 }
685 return afTipc;
686 }
687
688 private String toTipcInt(int v) {
689 if (v < 0) {
690 return "0x" + toUnsignedString(v, 16);
691 } else {
692 return toUnsignedString(v);
693 }
694 }
695
696
697
698
699
700
701
702
703 @SuppressWarnings("PMD.ShortMethodName")
704 public static AFTIPCSocketAddress of(URI uri) throws SocketException {
705 return of(uri, -1);
706 }
707
708
709
710
711
712
713
714
715
716 @SuppressWarnings({
717 "PMD.CognitiveComplexity", "PMD.CyclomaticComplexity", "PMD.ExcessiveMethodLength",
718 "PMD.NcssCount", "PMD.NPathComplexity", "PMD.ShortMethodName"})
719 public static AFTIPCSocketAddress of(URI uri, int overridePort) throws SocketException {
720 switch (uri.getScheme()) {
721 case "tipc":
722 case "http+tipc":
723 case "https+tipc":
724 break;
725 default:
726 throw new SocketException("Unsupported URI scheme: " + uri.getScheme());
727 }
728
729 String host = uri.getHost();
730 if (host == null) {
731 host = uri.getAuthority();
732 if (host != null) {
733 int at = host.indexOf('@');
734 if (at >= 0) {
735 host = host.substring(at + 1);
736 }
737 }
738 }
739 if (host == null) {
740 throw new SocketException("Cannot get hostname from URI: " + uri);
741 }
742 int port = overridePort != -1 ? overridePort : uri.getPort();
743 if (port != -1) {
744 host += ":" + port;
745 }
746 try {
747 Matcher m = PAT_TIPC_URI_HOST_AND_PORT.matcher(host);
748 if (!m.matches()) {
749 throw new SocketException("Invalid TIPC URI: " + uri);
750 }
751
752 String typeStr = m.group("type");
753 String scopeStr = m.group("scope");
754 if (typeStr == null) {
755 typeStr = m.group("type2");
756 scopeStr = m.group("scope2");
757 }
758 String strA = m.group("a");
759 String strB = m.group("b");
760 String strC = m.group("c");
761 String javaPortStr = m.group("javaPort");
762
763 final AddressType addrType;
764 switch (typeStr == null ? "" : typeStr) {
765 case "service":
766 addrType = AddressType.SERVICE_ADDR;
767 break;
768 case "service-range":
769 addrType = AddressType.SERVICE_RANGE;
770 break;
771 case "socket":
772 addrType = AddressType.SOCKET_ADDR;
773 break;
774 case "":
775 addrType = AddressType.SERVICE_ADDR;
776 break;
777 default:
778 addrType = AddressType.ofValue(parseUnsignedInt(typeStr));
779 break;
780 }
781
782 final Scope scope;
783 switch (scopeStr == null ? "" : scopeStr) {
784 case "cluster":
785 scope = Scope.SCOPE_CLUSTER;
786 break;
787 case "node":
788 scope = Scope.SCOPE_NODE;
789 break;
790 case "default":
791 scope = Scope.SCOPE_NOT_SPECIFIED;
792 break;
793 case "":
794 if (addrType == AddressType.SERVICE_ADDR || addrType == AddressType.SERVICE_RANGE) {
795 scope = Scope.SCOPE_CLUSTER;
796 } else {
797 scope = Scope.SCOPE_NOT_SPECIFIED;
798 }
799 break;
800 default:
801 scope = Scope.ofValue(parseUnsignedInt(scopeStr));
802 break;
803 }
804
805 int a = parseUnsignedInt(strA);
806 int b = parseUnsignedInt(strB);
807
808 int c;
809 if (strC == null || strC.isEmpty()) {
810 if (addrType == AddressType.SERVICE_RANGE) {
811 c = b;
812 } else {
813 c = 0;
814 }
815 } else {
816 c = parseUnsignedInt(strC);
817 }
818
819 int javaPort = javaPortStr == null || javaPortStr.isEmpty() ? port : Integer.parseInt(
820 javaPortStr);
821 if (overridePort != -1) {
822 javaPort = overridePort;
823 }
824
825 return resolveAddress(toBytes(addrType, scope, a, b, c), javaPort, addressFamily());
826 } catch (IllegalArgumentException e) {
827 throw (SocketException) new SocketException("Invalid TIPC URI: " + uri).initCause(e);
828 }
829 }
830
831 @Override
832 @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CompareObjectsWithEquals"})
833 public URI toURI(String scheme, URI template) throws IOException {
834 switch (scheme) {
835 case "tipc":
836 case "http+tipc":
837 case "https+tipc":
838 break;
839 default:
840 return super.toURI(scheme, template);
841 }
842
843 byte[] bytes = getBytes();
844 if (bytes.length != (5 * 4)) {
845 return super.toURI(scheme, template);
846 }
847
848 ByteBuffer bb = ByteBuffer.wrap(bytes);
849 AddressType addrType = AddressType.ofValue(bb.getInt());
850 Scope scope = Scope.ofValue(bb.getInt());
851
852 StringBuilder sb = new StringBuilder();
853
854 boolean haveScope = true;
855 if (scope == Scope.SCOPE_NOT_SPECIFIED) {
856 sb.append("default-");
857 } else if (scope == Scope.SCOPE_CLUSTER) {
858 if (addrType == AddressType.SERVICE_ADDR || addrType == AddressType.SERVICE_RANGE) {
859
860 haveScope = false;
861 } else {
862 sb.append("cluster-");
863 }
864 } else if (scope == Scope.SCOPE_NODE) {
865 sb.append("node-");
866 } else {
867 sb.append(toTipcInt(scope.value()));
868 sb.append('-');
869 }
870
871 boolean addrTypeImplied = false;
872 if (addrType == AddressType.SERVICE_ADDR) {
873 if (!haveScope) {
874 addrTypeImplied = true;
875 } else {
876 sb.append("service");
877 }
878 } else if (addrType == AddressType.SERVICE_RANGE) {
879 sb.append("service-range");
880 } else if (addrType == AddressType.SOCKET_ADDR) {
881 sb.append("socket");
882 } else {
883 sb.append(toTipcInt(addrType.value()));
884 }
885 if (!addrTypeImplied) {
886 sb.append('.');
887 }
888
889 int a = bb.getInt();
890 int b = bb.getInt();
891 int c = bb.getInt();
892
893 sb.append(toTipcInt(a));
894 sb.append('.');
895 sb.append(toTipcInt(b));
896 if (c != 0) {
897 sb.append('.');
898 sb.append(toTipcInt(c));
899 }
900
901 return new HostAndPort(sb.toString(), getPort()).toURI(scheme, template);
902 }
903 }