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
39
40
41
42
43 public final class AFVSOCKSocketAddress extends AFSocketAddress {
44 private static final long serialVersionUID = 1L;
45
46 private static final Pattern PAT_VSOCK_URI_HOST_AND_PORT = Pattern.compile(
47 "^(?<port>any|[0-9a-fx\\-]+)(\\.(?<cid>any|hypervisor|local|host|[0-9a-fx\\-]+))?(?:\\:(?<javaPort>[0-9]+))?$");
48
49 private static AFAddressFamily<AFVSOCKSocketAddress> afVsock;
50
51
52
53
54 public static final int VMADDR_CID_ANY = -1;
55
56
57
58
59 public static final int VMADDR_CID_HYPERVISOR = 0;
60
61
62
63
64 public static final int VMADDR_CID_LOCAL = 1;
65
66
67
68
69 public static final int VMADDR_CID_HOST = 2;
70
71
72
73
74 public static final int VMADDR_PORT_ANY = -1;
75
76 private AFVSOCKSocketAddress(int port, final byte[] socketAddress,
77 Lease<ByteBuffer> nativeAddress) throws SocketException {
78 super(port, socketAddress, nativeAddress, addressFamily());
79 }
80
81 private static AFVSOCKSocketAddress newAFSocketAddress(int port, final byte[] socketAddress,
82 Lease<ByteBuffer> nativeAddress) throws SocketException {
83 return newDeserializedAFSocketAddress(port, socketAddress, nativeAddress, addressFamily(),
84 AFVSOCKSocketAddress::new);
85 }
86
87
88
89
90
91
92
93
94
95
96 public static AFVSOCKSocketAddress ofPortAndCID(int port, int cid) throws SocketException {
97 return ofPortAndCID(-1, port, cid);
98 }
99
100
101
102
103
104
105
106
107
108 public static AFVSOCKSocketAddress ofHypervisorPort(int port) throws SocketException {
109 return ofPortAndCID(port, VMADDR_CID_HYPERVISOR);
110 }
111
112
113
114
115
116
117
118
119 public static AFVSOCKSocketAddress ofAnyHypervisorPort() throws SocketException {
120 return ofPortAndCID(VMADDR_PORT_ANY, VMADDR_CID_HYPERVISOR);
121 }
122
123
124
125
126
127
128
129
130
131 public static AFVSOCKSocketAddress ofLocalPort(int port) throws SocketException {
132 return ofPortAndCID(port, VMADDR_CID_LOCAL);
133 }
134
135
136
137
138
139
140
141
142 public static AFVSOCKSocketAddress ofAnyLocalPort() throws SocketException {
143 return ofPortAndCID(VMADDR_PORT_ANY, VMADDR_CID_LOCAL);
144 }
145
146
147
148
149
150
151
152
153
154 public static AFVSOCKSocketAddress ofHostPort(int port) throws SocketException {
155 return ofPortAndCID(port, VMADDR_CID_HOST);
156 }
157
158
159
160
161
162
163
164
165 public static AFVSOCKSocketAddress ofAnyHostPort() throws SocketException {
166 return ofPortAndCID(VMADDR_PORT_ANY, VMADDR_CID_HOST);
167 }
168
169
170
171
172
173
174
175
176 public static AFVSOCKSocketAddress ofAnyPort() throws SocketException {
177 return ofPortAndCID(VMADDR_PORT_ANY, VMADDR_CID_ANY);
178 }
179
180
181
182
183
184
185
186
187
188 public static AFVSOCKSocketAddress ofPortWithAnyCID(int port) throws SocketException {
189 return ofPortAndCID(port, VMADDR_CID_ANY);
190 }
191
192
193
194
195
196
197
198
199
200
201 public static AFVSOCKSocketAddress ofPortAndCID(int javaPort, int vsockPort, int cid)
202 throws SocketException {
203 return resolveAddress(toBytes(vsockPort, cid), javaPort, addressFamily());
204 }
205
206
207
208
209
210
211
212
213
214
215
216 public static AFVSOCKSocketAddress unwrap(InetAddress address, int port) throws SocketException {
217 return AFSocketAddress.unwrap(address, port, addressFamily());
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231 public static AFVSOCKSocketAddress unwrap(String hostname, int port) throws SocketException {
232 return AFSocketAddress.unwrap(hostname, port, addressFamily());
233 }
234
235
236
237
238
239
240
241
242
243 public static AFVSOCKSocketAddress unwrap(SocketAddress address) throws SocketException {
244 Objects.requireNonNull(address);
245 if (!isSupportedAddress(address)) {
246 throw new SocketException("Unsupported address");
247 }
248 return (AFVSOCKSocketAddress) address;
249 }
250
251
252
253
254
255
256
257 public int getVSOCKPort() {
258 ByteBuffer bb = ByteBuffer.wrap(getBytes());
259 int a = bb.getInt(1 * 4);
260 return a;
261 }
262
263
264
265
266
267
268 public int getVSOCKCID() {
269 ByteBuffer bb = ByteBuffer.wrap(getBytes());
270 int a = bb.getInt(2 * 4);
271 return a;
272 }
273
274
275
276
277
278
279 public int getVSOCKReserved1() {
280 ByteBuffer bb = ByteBuffer.wrap(getBytes());
281 int a = bb.getInt(0 * 4);
282 return a;
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({
419 "PMD.CognitiveComplexity", "PMD.CyclomaticComplexity", "PMD.ExcessiveMethodLength",
420 "PMD.NcssCount", "PMD.NPathComplexity", "PMD.ShortMethodName"})
421 public static AFVSOCKSocketAddress of(URI uri, int overridePort) throws SocketException {
422 switch (uri.getScheme()) {
423 case "vsock":
424 case "http+vsock":
425 case "https+vsock":
426 break;
427 default:
428 throw new SocketException("Unsupported URI scheme: " + uri.getScheme());
429 }
430
431 String host = uri.getHost();
432 if (host == null) {
433 host = uri.getAuthority();
434 if (host != null) {
435 int at = host.indexOf('@');
436 if (at >= 0) {
437 host = host.substring(at + 1);
438 }
439 }
440 }
441 if (host == null) {
442 throw new SocketException("Cannot get hostname from URI: " + uri);
443 }
444
445 try {
446 Matcher m = PAT_VSOCK_URI_HOST_AND_PORT.matcher(host);
447 if (!m.matches()) {
448 throw new SocketException("Invalid VSOCK URI: " + uri);
449 }
450
451 String cidStr = m.group("cid");
452 String portStr = m.group("port");
453 String javaPortStr = m.group("javaPort");
454
455 int cid;
456 switch (cidStr == null ? "" : cidStr) {
457 case "":
458 case "any":
459 cid = VMADDR_CID_ANY;
460 break;
461 case "hypervisor":
462 cid = VMADDR_CID_HYPERVISOR;
463 break;
464 case "local":
465 cid = VMADDR_CID_LOCAL;
466 break;
467 case "host":
468 cid = VMADDR_CID_HOST;
469 break;
470 default:
471 cid = parseInt(cidStr);
472 break;
473 }
474
475 int port;
476 switch (portStr == null ? "" : portStr) {
477 case "any":
478 case "":
479 port = VMADDR_PORT_ANY;
480 break;
481 default:
482 port = parseInt(portStr);
483 break;
484 }
485
486 int javaPort = overridePort != -1 ? overridePort : uri.getPort();
487 if (javaPortStr != null && !javaPortStr.isEmpty()) {
488 javaPort = parseInt(javaPortStr);
489 }
490
491 return ofPortAndCID(javaPort, port, cid);
492 } catch (IllegalArgumentException e) {
493 throw (SocketException) new SocketException("Invalid VSOCK URI: " + uri).initCause(e);
494 }
495 }
496
497 @Override
498 @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CompareObjectsWithEquals"})
499 public URI toURI(String scheme, URI template) throws IOException {
500 switch (scheme) {
501 case "vsock":
502 case "http+vsock":
503 case "https+vsock":
504 break;
505 default:
506 return super.toURI(scheme, template);
507 }
508
509 byte[] bytes = getBytes();
510 if (bytes.length != (3 * 4)) {
511 return super.toURI(scheme, template);
512 }
513
514 StringBuilder sb = new StringBuilder();
515
516 String portStr;
517 int port;
518 switch ((port = getVSOCKPort())) {
519 case VMADDR_PORT_ANY:
520 portStr = "any";
521 break;
522 default:
523 portStr = toUnsignedString(port);
524 break;
525 }
526
527 sb.append(portStr);
528 sb.append('.');
529 String cidStr;
530 int cid;
531 switch ((cid = getVSOCKCID())) {
532 case VMADDR_CID_ANY:
533 cidStr = "any";
534 break;
535 case VMADDR_CID_HYPERVISOR:
536 cidStr = "hypervisor";
537 break;
538 case VMADDR_CID_LOCAL:
539 cidStr = "local";
540 break;
541 case VMADDR_CID_HOST:
542 cidStr = "host";
543 break;
544 default:
545 cidStr = toUnsignedString(cid);
546 break;
547 }
548
549 sb.append(cidStr);
550
551 return new HostAndPort(sb.toString(), getPort()).toURI(scheme, template);
552 }
553
554 private static int parseInt(String v) {
555 if (v.startsWith("0x")) {
556 return parseUnsignedInt(v.substring(2), 16);
557 } else if (v.startsWith("-")) {
558 return Integer.parseInt(v);
559 } else {
560 return parseUnsignedInt(v, 10);
561 }
562 }
563
564
565
566
567
568
569
570
571
572
573
574
575
576 @Override
577 public boolean covers(AFSocketAddress covered) {
578 if (super.covers(covered)) {
579 return true;
580 } else if (covered instanceof AFVSOCKSocketAddress) {
581 AFVSOCKSocketAddress other = (AFVSOCKSocketAddress) covered;
582
583 if (getVSOCKCID() == VMADDR_CID_ANY) {
584 if (getVSOCKPort() == VMADDR_PORT_ANY) {
585 return true;
586 } else {
587 return getVSOCKPort() == other.getVSOCKPort();
588 }
589 } else if (getVSOCKPort() == VMADDR_PORT_ANY) {
590 return getVSOCKCID() == other.getVSOCKCID();
591 }
592 }
593
594 return equals(covered);
595 }
596 }