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.net.InetAddress;
24 import java.net.SocketAddress;
25 import java.net.SocketException;
26 import java.net.URI;
27 import java.nio.ByteBuffer;
28 import java.util.Arrays;
29 import java.util.HashSet;
30 import java.util.Locale;
31 import java.util.Objects;
32 import java.util.Set;
33 import java.util.regex.Matcher;
34 import java.util.regex.Pattern;
35
36 import org.newsclub.net.unix.pool.ObjectPool.Lease;
37
38 import com.kohlschutter.annotations.compiletime.SuppressFBWarnings;
39
40
41
42
43
44
45 @SuppressFBWarnings({"REDOS", "USO_UNSAFE_STATIC_METHOD_SYNCHRONIZATION"})
46 public final class AFVSOCKSocketAddress extends AFSocketAddress {
47 private static final long serialVersionUID = 1L;
48
49 private static final Pattern PAT_VSOCK_URI_HOST_AND_PORT = Pattern.compile(
50 "^(?<port>any|[0-9a-fx\\-]+)(\\.(?<cid>any|hypervisor|local|host|[0-9a-fx\\-]+))?(?:\\:(?<javaPort>[0-9]+))?$");
51
52 private static AFAddressFamily<AFVSOCKSocketAddress> afVsock;
53
54
55
56
57 public static final int VMADDR_CID_ANY = -1;
58
59
60
61
62 public static final int VMADDR_CID_HYPERVISOR = 0;
63
64
65
66
67 public static final int VMADDR_CID_LOCAL = 1;
68
69
70
71
72 public static final int VMADDR_CID_HOST = 2;
73
74
75
76
77 public static final int VMADDR_PORT_ANY = -1;
78
79 private AFVSOCKSocketAddress(int port, final byte[] socketAddress,
80 Lease<ByteBuffer> nativeAddress) throws SocketException {
81 super(port, socketAddress, nativeAddress, addressFamily());
82 }
83
84 private static AFVSOCKSocketAddress newAFSocketAddress(int port, final byte[] socketAddress,
85 Lease<ByteBuffer> nativeAddress) throws SocketException {
86 return newDeserializedAFSocketAddress(port, socketAddress, nativeAddress, addressFamily(),
87 AFVSOCKSocketAddress::new);
88 }
89
90
91
92
93
94
95
96
97
98
99 public static AFVSOCKSocketAddress ofPortAndCID(int port, int cid) throws SocketException {
100 return ofPortAndCID(-1, port, cid);
101 }
102
103
104
105
106
107
108
109
110
111 public static AFVSOCKSocketAddress ofHypervisorPort(int port) throws SocketException {
112 return ofPortAndCID(port, VMADDR_CID_HYPERVISOR);
113 }
114
115
116
117
118
119
120
121
122 public static AFVSOCKSocketAddress ofAnyHypervisorPort() throws SocketException {
123 return ofPortAndCID(VMADDR_PORT_ANY, VMADDR_CID_HYPERVISOR);
124 }
125
126
127
128
129
130
131
132
133
134 public static AFVSOCKSocketAddress ofLocalPort(int port) throws SocketException {
135 return ofPortAndCID(port, VMADDR_CID_LOCAL);
136 }
137
138
139
140
141
142
143
144
145 public static AFVSOCKSocketAddress ofAnyLocalPort() throws SocketException {
146 return ofPortAndCID(VMADDR_PORT_ANY, VMADDR_CID_LOCAL);
147 }
148
149
150
151
152
153
154
155
156
157 public static AFVSOCKSocketAddress ofHostPort(int port) throws SocketException {
158 return ofPortAndCID(port, VMADDR_CID_HOST);
159 }
160
161
162
163
164
165
166
167
168 public static AFVSOCKSocketAddress ofAnyHostPort() throws SocketException {
169 return ofPortAndCID(VMADDR_PORT_ANY, VMADDR_CID_HOST);
170 }
171
172
173
174
175
176
177
178
179 public static AFVSOCKSocketAddress ofAnyPort() throws SocketException {
180 return ofPortAndCID(VMADDR_PORT_ANY, VMADDR_CID_ANY);
181 }
182
183
184
185
186
187
188
189
190
191 public static AFVSOCKSocketAddress ofPortWithAnyCID(int port) throws SocketException {
192 return ofPortAndCID(port, VMADDR_CID_ANY);
193 }
194
195
196
197
198
199
200
201
202
203
204 public static AFVSOCKSocketAddress ofPortAndCID(int javaPort, int vsockPort, int cid)
205 throws SocketException {
206 return resolveAddress(toBytes(vsockPort, cid), javaPort, addressFamily());
207 }
208
209
210
211
212
213
214
215
216
217
218
219 public static AFVSOCKSocketAddress unwrap(InetAddress address, int port) throws SocketException {
220 return AFSocketAddress.unwrap(address, port, addressFamily());
221 }
222
223
224
225
226
227
228
229
230
231
232
233
234 public static AFVSOCKSocketAddress unwrap(String hostname, int port) throws SocketException {
235 return AFSocketAddress.unwrap(hostname, port, addressFamily());
236 }
237
238
239
240
241
242
243
244
245
246 public static AFVSOCKSocketAddress unwrap(SocketAddress address) throws SocketException {
247 Objects.requireNonNull(address);
248 if (!isSupportedAddress(address)) {
249 throw new SocketException("Unsupported address");
250 }
251 return (AFVSOCKSocketAddress) address;
252 }
253
254
255
256
257
258
259
260 public int getVSOCKPort() {
261 ByteBuffer bb = ByteBuffer.wrap(getBytes());
262 return bb.getInt(1 * 4);
263 }
264
265
266
267
268
269
270 public int getVSOCKCID() {
271 ByteBuffer bb = ByteBuffer.wrap(getBytes());
272 return bb.getInt(2 * 4);
273 }
274
275
276
277
278
279
280 public int getVSOCKReserved1() {
281 ByteBuffer bb = ByteBuffer.wrap(getBytes());
282 return bb.getInt(0 * 4);
283 }
284
285 @Override
286 public String toString() {
287 int port = getPort();
288
289 byte[] bytes = getBytes();
290 if (bytes.length != (3 * 4)) {
291 return getClass().getName() + "[" + (port == 0 ? "" : "port=" + port) + ";UNKNOWN" + "]";
292 }
293
294 ByteBuffer bb = ByteBuffer.wrap(bytes);
295 int reserved1 = bb.getInt();
296 int vsockPort = bb.getInt();
297 int cid = bb.getInt();
298
299 String vsockPortString;
300 if (vsockPort >= -1) {
301 vsockPortString = Integer.toString(vsockPort);
302 } else {
303 vsockPortString = String.format(Locale.ENGLISH, "0x%08x", vsockPort);
304 }
305
306 String typeString = (reserved1 == 0 ? "" : "reserved1=" + reserved1 + ";") + "vsockPort="
307 + vsockPortString + ";cid=" + cid;
308
309 return getClass().getName() + "[" + (port == 0 ? "" : "port=" + port + ";") + typeString + "]";
310 }
311
312 @Override
313 public boolean hasFilename() {
314 return false;
315 }
316
317 @Override
318 public File getFile() throws FileNotFoundException {
319 throw new FileNotFoundException("no file");
320 }
321
322
323
324
325
326
327
328
329
330 public static boolean isSupportedAddress(InetAddress addr) {
331 return AFSocketAddress.isSupportedAddress(addr, addressFamily());
332 }
333
334
335
336
337
338
339
340
341 public static boolean isSupportedAddress(SocketAddress addr) {
342 return (addr instanceof AFVSOCKSocketAddress);
343 }
344
345 @SuppressWarnings("cast")
346 private static byte[] toBytes(int port, int cid) {
347 ByteBuffer bb = ByteBuffer.allocate(3 * 4);
348 bb.putInt(0);
349 bb.putInt(port);
350 bb.putInt(cid);
351 return (byte[]) bb.flip().array();
352 }
353
354
355
356
357
358
359 @SuppressWarnings("null")
360 public static synchronized AFAddressFamily<AFVSOCKSocketAddress> addressFamily() {
361 if (afVsock == null) {
362 afVsock = AFAddressFamily.registerAddressFamily("vsock",
363 AFVSOCKSocketAddress.class, new AFSocketAddressConfig<AFVSOCKSocketAddress>() {
364
365 private final AFSocketAddressConstructor<AFVSOCKSocketAddress> addrConstr =
366 isUseDeserializationForInit() ? AFVSOCKSocketAddress::newAFSocketAddress
367 : AFVSOCKSocketAddress::new;
368
369 @Override
370 protected AFVSOCKSocketAddress parseURI(URI u, int port) throws SocketException {
371 return AFVSOCKSocketAddress.of(u, port);
372 }
373
374 @Override
375 protected AFSocketAddressConstructor<AFVSOCKSocketAddress> addressConstructor() {
376 return addrConstr;
377 }
378
379 @Override
380 protected String selectorProviderClassname() {
381 return "org.newsclub.net.unix.vsock.AFVSOCKSelectorProvider";
382 }
383
384 @Override
385 protected Set<String> uriSchemes() {
386 return new HashSet<>(Arrays.asList("vsock", "http+vsock", "https+vsock"));
387 }
388 });
389 try {
390 Class.forName("org.newsclub.net.unix.vsock.AFVSOCKSelectorProvider");
391 } catch (ClassNotFoundException e) {
392
393 }
394 }
395 return afVsock;
396 }
397
398
399
400
401
402
403
404
405 @SuppressWarnings("PMD.ShortMethodName")
406 public static AFVSOCKSocketAddress of(URI uri) throws SocketException {
407 return of(uri, -1);
408 }
409
410
411
412
413
414
415
416
417
418 @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", "PMD.ShortMethodName"})
419 public static AFVSOCKSocketAddress of(URI uri, int overridePort) throws SocketException {
420 switch (uri.getScheme()) {
421 case "vsock":
422 case "http+vsock":
423 case "https+vsock":
424 break;
425 default:
426 throw new SocketException("Unsupported URI scheme: " + uri.getScheme());
427 }
428
429 String host = uri.getHost();
430 if (host == null) {
431 host = uri.getAuthority();
432 if (host != null) {
433 int at = host.indexOf('@');
434 if (at >= 0) {
435 host = host.substring(at + 1);
436 }
437 }
438 }
439 if (host == null) {
440 throw new SocketException("Cannot get hostname from URI: " + uri);
441 }
442
443 try {
444 Matcher m = PAT_VSOCK_URI_HOST_AND_PORT.matcher(host);
445 if (!m.matches()) {
446 throw new SocketException("Invalid VSOCK URI: " + uri);
447 }
448
449 String cidStr = m.group("cid");
450 String portStr = m.group("port");
451 String javaPortStr = m.group("javaPort");
452
453 int cid;
454 switch (cidStr == null ? "" : cidStr) {
455 case "":
456 case "any":
457 cid = VMADDR_CID_ANY;
458 break;
459 case "hypervisor":
460 cid = VMADDR_CID_HYPERVISOR;
461 break;
462 case "local":
463 cid = VMADDR_CID_LOCAL;
464 break;
465 case "host":
466 cid = VMADDR_CID_HOST;
467 break;
468 default:
469 cid = parseInt(cidStr);
470 break;
471 }
472
473 int port;
474 switch (portStr == null ? "" : portStr) {
475 case "any":
476 case "":
477 port = VMADDR_PORT_ANY;
478 break;
479 default:
480 port = parseInt(portStr);
481 break;
482 }
483
484 int javaPort = overridePort != -1 ? overridePort : uri.getPort();
485 if (javaPortStr != null && !javaPortStr.isEmpty()) {
486 javaPort = parseInt(javaPortStr);
487 }
488
489 return ofPortAndCID(javaPort, port, cid);
490 } catch (IllegalArgumentException e) {
491 throw (SocketException) new SocketException("Invalid VSOCK URI: " + uri).initCause(e);
492 }
493 }
494
495 @Override
496 public URI toURI(String scheme, URI template) throws IOException {
497 switch (scheme) {
498 case "vsock":
499 case "http+vsock":
500 case "https+vsock":
501 break;
502 default:
503 return super.toURI(scheme, template);
504 }
505
506 byte[] bytes = getBytes();
507 if (bytes.length != (3 * 4)) {
508 return super.toURI(scheme, template);
509 }
510
511 StringBuilder sb = new StringBuilder();
512
513 String portStr;
514 int port;
515 switch ((port = getVSOCKPort())) {
516 case VMADDR_PORT_ANY:
517 portStr = "any";
518 break;
519 default:
520 portStr = toUnsignedString(port);
521 break;
522 }
523
524 sb.append(portStr);
525 sb.append('.');
526 String cidStr;
527 int cid;
528 switch ((cid = getVSOCKCID())) {
529 case VMADDR_CID_ANY:
530 cidStr = "any";
531 break;
532 case VMADDR_CID_HYPERVISOR:
533 cidStr = "hypervisor";
534 break;
535 case VMADDR_CID_LOCAL:
536 cidStr = "local";
537 break;
538 case VMADDR_CID_HOST:
539 cidStr = "host";
540 break;
541 default:
542 cidStr = toUnsignedString(cid);
543 break;
544 }
545
546 sb.append(cidStr);
547
548 return new HostAndPort(sb.toString(), getPort()).toURI(scheme, template);
549 }
550
551 private static int parseInt(String v) {
552 if (v.startsWith("0x")) {
553 return parseUnsignedInt(v.substring(2), 16);
554 } else if (v.startsWith("-")) {
555 return Integer.parseInt(v);
556 } else {
557 return parseUnsignedInt(v, 10);
558 }
559 }
560
561
562
563
564
565
566
567
568
569
570
571
572
573 @Override
574 public boolean covers(AFSocketAddress covered) {
575 if (super.covers(covered)) {
576 return true;
577 } else if (covered instanceof AFVSOCKSocketAddress) {
578 AFVSOCKSocketAddress other = (AFVSOCKSocketAddress) covered;
579
580 if (getVSOCKCID() == VMADDR_CID_ANY) {
581 if (getVSOCKPort() == VMADDR_PORT_ANY) {
582 return true;
583 } else {
584 return getVSOCKPort() == other.getVSOCKPort();
585 }
586 } else if (getVSOCKPort() == VMADDR_PORT_ANY) {
587 return getVSOCKCID() == other.getVSOCKCID();
588 }
589 }
590
591 return equals(covered);
592 }
593 }