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