View Javadoc
1   /*
2    * junixsocket
3    *
4    * Copyright 2009-2024 Christian Kohlschütter
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.newsclub.net.unix.vsock;
19  
20  import java.io.FileDescriptor;
21  import java.io.IOException;
22  import java.net.Socket;
23  import java.net.SocketException;
24  
25  import org.newsclub.net.unix.AFSocket;
26  import org.newsclub.net.unix.AFSocketCapability;
27  import org.newsclub.net.unix.AFSocketFactory;
28  import org.newsclub.net.unix.AFVSOCKSocketAddress;
29  import org.newsclub.net.unix.AFVSOCKSocketImplExtensions;
30  
31  /**
32   * Implementation of an {@code AF_VSOCK} socket.
33   *
34   * @author Christian Kohlschütter
35   */
36  public final class AFVSOCKSocket extends AFSocket<AFVSOCKSocketAddress> implements
37      AFVSOCKSocketExtensions {
38    private static AFVSOCKSocketImplExtensions staticExtensions = null;
39  
40    AFVSOCKSocket(FileDescriptor fdObj, AFSocketFactory<AFVSOCKSocketAddress> factory)
41        throws SocketException {
42      super(new AFVSOCKSocketImpl(fdObj), factory);
43    }
44  
45    private static synchronized AFVSOCKSocketImplExtensions getStaticImplExtensions()
46        throws IOException {
47      if (staticExtensions == null) {
48        try (AFVSOCKSocket socket = new AFVSOCKSocket(null, null)) {
49          staticExtensions = (AFVSOCKSocketImplExtensions) socket.getImplExtensions();
50        }
51      }
52      return staticExtensions;
53    }
54  
55    /**
56     * Returns <code>true</code> iff {@link AFVSOCKSocket}s (sockets of type "AF_VSOCK") are supported
57     * by the current Java VM and the kernel.
58     *
59     * To support {@link AFVSOCKSocket}s, a custom JNI library must be loaded that is supplied with
60     * <em>junixsocket</em>, and the system must support AF_VSOCK sockets.
61     *
62     * This call is equivalent to checking {@link AFSocket#isSupported()} and
63     * {@link AFSocket#supports(AFSocketCapability)} with {@link AFSocketCapability#CAPABILITY_VSOCK}.
64     *
65     * @return {@code true} iff supported.
66     */
67    public static boolean isSupported() {
68      return AFSocket.isSupported() && AFSocket.supports(AFSocketCapability.CAPABILITY_VSOCK);
69    }
70  
71    @Override
72    protected AFVSOCKSocketChannel newChannel() {
73      return new AFVSOCKSocketChannel(this);
74    }
75  
76    /**
77     * Creates a new, unbound {@link AFSocket}.
78     *
79     * This "default" implementation is a bit "lenient" with respect to the specification.
80     *
81     * In particular, we ignore calls to {@link Socket#getTcpNoDelay()} and
82     * {@link Socket#setTcpNoDelay(boolean)}.
83     *
84     * @return A new, unbound socket.
85     * @throws IOException if the operation fails.
86     */
87    public static AFVSOCKSocket newInstance() throws IOException {
88      return (AFVSOCKSocket) AFSocket.newInstance(AFVSOCKSocket::new, (AFVSOCKSocketFactory) null);
89    }
90  
91    static AFVSOCKSocket newInstance(AFVSOCKSocketFactory factory) throws SocketException {
92      return (AFVSOCKSocket) AFSocket.newInstance(AFVSOCKSocket::new, factory);
93    }
94  
95    /**
96     * Creates a new, unbound, "strict" {@link AFSocket}.
97     *
98     * This call uses an implementation that tries to be closer to the specification than
99     * {@link #newInstance()}, at least for some cases.
100    *
101    * @return A new, unbound socket.
102    * @throws IOException if the operation fails.
103    */
104   public static AFVSOCKSocket newStrictInstance() throws IOException {
105     return (AFVSOCKSocket) AFSocket.newInstance(AFVSOCKSocket::new, (AFVSOCKSocketFactory) null);
106   }
107 
108   /**
109    * Creates a new {@link AFSocket} and connects it to the given {@link AFVSOCKSocketAddress}.
110    *
111    * @param addr The address to connect to.
112    * @return A new, connected socket.
113    * @throws IOException if the operation fails.
114    */
115   public static AFVSOCKSocket connectTo(AFVSOCKSocketAddress addr) throws IOException {
116     return (AFVSOCKSocket) AFSocket.connectTo(AFVSOCKSocket::new, addr);
117   }
118 
119   @Override
120   public AFVSOCKSocketChannel getChannel() {
121     return (AFVSOCKSocketChannel) super.getChannel();
122   }
123 
124   /**
125    * Returns the local CID.
126    *
127    * If the system does not support vsock, or status about support cannot be retrieved, -1
128    * ({@link AFVSOCKSocketAddress#VMADDR_CID_ANY}) is returned. The value may be cached upon
129    * initialization of the library.
130    *
131    * @return The CID, or -1.
132    * @throws IOException on error.
133    */
134   public static int getLocalCID() throws IOException {
135     return getStaticImplExtensions().getLocalCID();
136   }
137 
138   /**
139    * Very basic self-test function.
140    *
141    * Prints "supported" and "capabilities" status to System.out.
142    *
143    * @param args ignored.
144    */
145   public static void main(String[] args) {
146     // If you want to run this directly from within Eclipse, see
147     // org.newsclub.net.unix.vsock.SocketTest#testMain.
148     System.out.print(AFVSOCKSocket.class.getName() + ".isSupported(): ");
149     System.out.flush();
150     System.out.println(AFVSOCKSocket.isSupported());
151   }
152 }