View Javadoc
1   /*
2    * junixsocket
3    *
4    * Copyright 2009-2026 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  import com.kohlschutter.annotations.compiletime.SuppressFBWarnings;
32  
33  /**
34   * Implementation of an {@code AF_VSOCK} socket.
35   *
36   * @author Christian Kohlschütter
37   */
38  public final class AFVSOCKSocket extends AFSocket<AFVSOCKSocketAddress> implements
39      AFVSOCKSocketExtensions {
40    private static AFVSOCKSocketImplExtensions staticExtensions = null;
41  
42    AFVSOCKSocket(FileDescriptor fdObj, AFSocketFactory<AFVSOCKSocketAddress> factory)
43        throws SocketException {
44      super(new AFVSOCKSocketImpl(fdObj), factory);
45    }
46  
47    private static synchronized AFVSOCKSocketImplExtensions getStaticImplExtensions()
48        throws IOException {
49      if (staticExtensions == null) {
50        try (AFVSOCKSocket socket = new AFVSOCKSocket(null, null)) {
51          staticExtensions = (AFVSOCKSocketImplExtensions) socket.getImplExtensions();
52        }
53      }
54      return staticExtensions;
55    }
56  
57    /**
58     * Returns <code>true</code> iff {@link AFVSOCKSocket}s (sockets of type "AF_VSOCK") are supported
59     * by the current Java VM and the kernel.
60     *
61     * To support {@link AFVSOCKSocket}s, a custom JNI library must be loaded that is supplied with
62     * <em>junixsocket</em>, and the system must support AF_VSOCK sockets.
63     *
64     * This call is equivalent to checking {@link AFSocket#isSupported()} and
65     * {@link AFSocket#supports(AFSocketCapability)} with {@link AFSocketCapability#CAPABILITY_VSOCK}.
66     *
67     * @return {@code true} iff supported.
68     */
69    @SuppressFBWarnings("HSM_HIDING_METHOD")
70    public static boolean isSupported() {
71      return AFSocket.isSupported() && AFSocket.supports(AFSocketCapability.CAPABILITY_VSOCK);
72    }
73  
74    @Override
75    protected AFVSOCKSocketChannel newChannel() {
76      return new AFVSOCKSocketChannel(this);
77    }
78  
79    /**
80     * Creates a new, unbound {@link AFSocket}.
81     *
82     * This "default" implementation is a bit "lenient" with respect to the specification.
83     *
84     * In particular, we ignore calls to {@link Socket#getTcpNoDelay()} and
85     * {@link Socket#setTcpNoDelay(boolean)}.
86     *
87     * @return A new, unbound socket.
88     * @throws IOException if the operation fails.
89     */
90    public static AFVSOCKSocket newInstance() throws IOException {
91      return (AFVSOCKSocket) AFSocket.newInstance(AFVSOCKSocket::new, (AFVSOCKSocketFactory) null);
92    }
93  
94    static AFVSOCKSocket newInstance(AFVSOCKSocketFactory factory) throws SocketException {
95      return (AFVSOCKSocket) AFSocket.newInstance(AFVSOCKSocket::new, factory);
96    }
97  
98    /**
99     * Creates a new, unbound, "strict" {@link AFSocket}.
100    *
101    * This call uses an implementation that tries to be closer to the specification than
102    * {@link #newInstance()}, at least for some cases.
103    *
104    * @return A new, unbound socket.
105    * @throws IOException if the operation fails.
106    */
107   public static AFVSOCKSocket newStrictInstance() throws IOException {
108     return (AFVSOCKSocket) AFSocket.newInstance(AFVSOCKSocket::new, (AFVSOCKSocketFactory) null);
109   }
110 
111   /**
112    * Creates a new {@link AFSocket} and connects it to the given {@link AFVSOCKSocketAddress}.
113    *
114    * @param addr The address to connect to.
115    * @return A new, connected socket.
116    * @throws IOException if the operation fails.
117    */
118   public static AFVSOCKSocket connectTo(AFVSOCKSocketAddress addr) throws IOException {
119     return (AFVSOCKSocket) AFSocket.connectTo(AFVSOCKSocket::new, addr);
120   }
121 
122   @Override
123   public AFVSOCKSocketChannel getChannel() {
124     return (AFVSOCKSocketChannel) super.getChannel();
125   }
126 
127   /**
128    * Returns the local CID.
129    *
130    * If the system does not support vsock, or status about support cannot be retrieved, -1
131    * ({@link AFVSOCKSocketAddress#VMADDR_CID_ANY}) is returned. The value may be cached upon
132    * initialization of the library.
133    *
134    * @return The CID, or -1.
135    * @throws IOException on error.
136    */
137   public static int getLocalCID() throws IOException {
138     return getStaticImplExtensions().getLocalCID();
139   }
140 
141   /**
142    * Very basic self-test function.
143    *
144    * Prints "supported" and "capabilities" status to System.out.
145    *
146    * @param args ignored.
147    */
148   public static void main(String[] args) {
149     // If you want to run this directly from within Eclipse, see
150     // org.newsclub.net.unix.vsock.SocketTest#testMain.
151     System.out.print(AFVSOCKSocket.class.getName() + ".isSupported(): ");
152     System.out.flush();
153     System.out.println(AFVSOCKSocket.isSupported());
154   }
155 }