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 }