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 }