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