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