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.IOException;
21 import java.lang.reflect.InvocationTargetException;
22 import java.net.SocketAddress;
23 import java.net.SocketException;
24 import java.net.URI;
25 import java.nio.channels.ServerSocketChannel;
26 import java.nio.channels.SocketChannel;
27 import java.nio.channels.UnsupportedAddressTypeException;
28 import java.nio.channels.spi.SelectorProvider;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.Map;
33 import java.util.Objects;
34 import java.util.Set;
35 import java.util.concurrent.atomic.AtomicBoolean;
36
37 import org.eclipse.jdt.annotation.NonNull;
38 import org.eclipse.jdt.annotation.Nullable;
39 import org.newsclub.net.unix.AFSocketAddress.AFSocketAddressConstructor;
40
41 import com.kohlschutter.annotations.compiletime.SuppressFBWarnings;
42
43
44
45
46
47
48
49 public final class AFAddressFamily<A extends AFSocketAddress> {
50 private static final Map<String, AFAddressFamily<?>> AF_MAP = Collections.synchronizedMap(
51 new HashMap<>());
52 private static final Map<String, AFAddressFamily<?>> URI_SCHEMES = Collections.synchronizedMap(
53 new HashMap<>());
54 private static final AtomicBoolean DEFERRED_INIT_DONE = new AtomicBoolean(false);
55
56 private final int domain;
57 private AFSocketAddressConstructor<A> addressConstructor;
58 private @Nullable Class<A> addressClass;
59 private final String juxString;
60 private final String juxInetAddressSuffix;
61 private final String addressClassname;
62
63 private String selectorProviderClassname;
64
65 private AFSocket.Constructor<A> socketConstructor;
66 private AFServerSocket.Constructor<A> serverSocketConstructor;
67 private AFSocketAddressConfig<A> addressConfig;
68
69 private SelectorProvider selectorProvider = null;
70
71 static {
72 NativeUnixSocket.isLoaded();
73 }
74
75 private AFAddressFamily(String juxString, int domain, String addressClassname) {
76 this.juxString = juxString;
77 this.domain = domain;
78 this.addressClassname = addressClassname;
79 this.juxInetAddressSuffix = "." + juxString + AFInetAddress.INETADDR_SUFFIX;
80 }
81
82 @SuppressWarnings("unchecked")
83 static synchronized <A extends AFSocketAddress> @NonNull AFAddressFamily<A> registerAddressFamily(
84 String juxString, int domain, String addressClassname) {
85 AFAddressFamily<?> af = AF_MAP.get(juxString);
86 if (af != null) {
87 if (af.getDomain() != domain) {
88 throw new IllegalStateException("Wrong domain for address family " + juxString + ": " + af
89 .getDomain() + " vs. " + domain);
90 }
91 return (AFAddressFamily<A>) af;
92 }
93
94 af = new AFAddressFamily<>(juxString, domain, addressClassname);
95 AF_MAP.put(juxString, af);
96
97 return (AFAddressFamily<A>) af;
98 }
99
100 static synchronized void triggerInit() {
101 for (AFAddressFamily<?> af : new HashSet<>(AF_MAP.values())) {
102 if (af.addressClassname != null) {
103 try {
104 Class<?> clz = Class.forName(af.addressClassname);
105 clz.getMethod("addressFamily").invoke(null);
106 } catch (Exception e) {
107
108 }
109 }
110 }
111 }
112
113 static synchronized AFAddressFamily<?> getAddressFamily(String juxString) {
114 return AF_MAP.get(juxString);
115 }
116
117 static AFAddressFamily<?> getAddressFamily(URI uri) {
118 checkDeferredInit();
119 Objects.requireNonNull(uri, "uri");
120 String scheme = uri.getScheme();
121 return URI_SCHEMES.get(scheme);
122 }
123
124 static void checkDeferredInit() {
125 if (DEFERRED_INIT_DONE.compareAndSet(false, true)) {
126 NativeUnixSocket.isLoaded();
127 AFAddressFamily.triggerInit();
128 }
129 }
130
131 int getDomain() {
132 return domain;
133 }
134
135 String getJuxString() {
136 return juxString;
137 }
138
139 AFSocketAddressConstructor<A> getAddressConstructor() {
140 if (addressConstructor == null) {
141 throw new UnsupportedAddressTypeException();
142 }
143 return addressConstructor;
144 }
145
146 private synchronized void checkProvider() {
147 if (socketConstructor == null && selectorProvider == null) {
148 try {
149 getSelectorProvider();
150 } catch (IllegalStateException e) {
151
152 }
153 }
154 }
155
156 AFSocket.Constructor<A> getSocketConstructor() {
157 checkProvider();
158 if (socketConstructor == null) {
159 throw new UnsupportedAddressTypeException();
160 }
161 return socketConstructor;
162 }
163
164 AFServerSocket.Constructor<A> getServerSocketConstructor() {
165 checkProvider();
166 if (serverSocketConstructor == null) {
167 throw new UnsupportedAddressTypeException();
168 }
169 return serverSocketConstructor;
170 }
171
172 Class<A> getSocketAddressClass() {
173 if (addressClass == null) {
174 throw new UnsupportedAddressTypeException();
175 }
176 return addressClass;
177 }
178
179 String getJuxInetAddressSuffix() {
180 return juxInetAddressSuffix;
181 }
182
183
184
185
186
187
188
189
190
191
192 @SuppressWarnings({"unchecked", "rawtypes"})
193 @SuppressFBWarnings("USO_UNSAFE_METHOD_SYNCHRONIZATION")
194 public static synchronized <A extends AFSocketAddress> AFAddressFamily<A> registerAddressFamily(
195 String juxString,
196 Class<A> addressClass, AFSocketAddressConfig<A> config) {
197 AFAddressFamily<?> af = getAddressFamily(juxString);
198 if (af == null) {
199 throw new IllegalStateException("Address family not supported by native code: " + juxString);
200 }
201 if (af.addressClassname != null && !addressClass.getName().equals(af.addressClassname)) {
202 throw new IllegalStateException("Unexpected classname for address family " + juxString + ": "
203 + addressClass.getName() + "; expected: " + af.addressClassname);
204 }
205 if (af.addressConstructor != null || af.addressClass != null) {
206 throw new IllegalStateException("Already registered: " + juxString);
207 }
208 af.addressConfig = (AFSocketAddressConfig) config;
209 af.addressConstructor = (AFSocketAddressConstructor) config.addressConstructor();
210 af.addressClass = (Class) addressClass;
211 synchronized (af) {
212 af.selectorProviderClassname = config.selectorProviderClassname();
213 }
214
215 for (String scheme : config.uriSchemes()) {
216 if (scheme.isEmpty()) {
217 throw new IllegalStateException("Invalid URI scheme; cannot register " + scheme + " for "
218 + juxString);
219
220 }
221 if (URI_SCHEMES.containsKey(scheme)) {
222 throw new IllegalStateException("URI scheme already registered; cannot register " + scheme
223 + " for " + juxString);
224 }
225 URI_SCHEMES.put(scheme, af);
226 }
227
228 return (AFAddressFamily<A>) af;
229 }
230
231
232
233
234
235
236
237
238
239
240
241 @SuppressWarnings({"unchecked", "rawtypes"})
242 public static synchronized <A extends AFSocketAddress> AFAddressFamily<A> registerAddressFamilyImpl(
243 String juxString,
244 AFAddressFamily<A> addressFamily,
245 AFAddressFamilyConfig<A> config) {
246 Objects.requireNonNull(addressFamily);
247 Objects.requireNonNull(config);
248
249 AFAddressFamily<?> af = getAddressFamily(juxString);
250 if (af == null) {
251 throw new IllegalStateException("Unknown address family: " + juxString);
252 }
253 if (addressFamily != af) {
254 throw new IllegalStateException("Address family inconsistency: " + juxString);
255 }
256 if (af.socketConstructor != null) {
257 throw new IllegalStateException("Already registered: " + juxString);
258 }
259 af.socketConstructor = (AFSocket.Constructor) config.socketConstructor();
260 af.serverSocketConstructor = (AFServerSocket.Constructor) config.serverSocketConstructor();
261
262 FileDescriptorCast.registerCastingProviders(config);
263
264 return (AFAddressFamily<A>) af;
265 }
266
267 @SuppressWarnings("unchecked")
268 AFSocketImplExtensions<A> initImplExtensions(AncillaryDataSupport ancillaryDataSupport) {
269 switch (getDomain()) {
270 case NativeUnixSocket.DOMAIN_TIPC:
271 return (AFSocketImplExtensions<A>) new AFTIPCSocketImplExtensions(ancillaryDataSupport);
272 case NativeUnixSocket.DOMAIN_VSOCK:
273 return (AFSocketImplExtensions<A>) new AFVSOCKSocketImplExtensions(ancillaryDataSupport);
274 case NativeUnixSocket.DOMAIN_SYSTEM:
275 return (AFSocketImplExtensions<A>) new AFSYSTEMSocketImplExtensions(ancillaryDataSupport);
276 default:
277 throw new UnsupportedOperationException();
278 }
279 }
280
281
282
283
284
285
286
287 public AFSocket<?> newSocket() throws IOException {
288 try {
289 return getSocketConstructor().newInstance(null, null);
290 } catch (UnsupportedOperationException e) {
291 throw (SocketException) new SocketException().initCause(e);
292 }
293 }
294
295
296
297
298
299
300
301 public AFServerSocket<?> newServerSocket() throws IOException {
302 try {
303 return getServerSocketConstructor().newInstance(null);
304 } catch (UnsupportedOperationException e) {
305 throw (SocketException) new SocketException().initCause(e);
306 }
307 }
308
309
310
311
312
313
314
315 public AFSocketChannel<?> newSocketChannel() throws IOException {
316 return newSocket().getChannel();
317 }
318
319
320
321
322
323
324
325
326 public AFServerSocketChannel<?> newServerSocketChannel() throws IOException {
327 return newServerSocket().getChannel();
328 }
329
330 AFSocketAddress parseURI(URI u, int overridePort) throws SocketException {
331 if (addressConfig == null) {
332 throw new SocketException("Cannot instantiate addresses of type " + addressClass);
333 }
334 return addressConfig.parseURI(u, overridePort);
335 }
336
337
338
339
340
341
342
343
344
345 public static synchronized Set<String> uriSchemes() {
346 checkDeferredInit();
347 return Collections.unmodifiableSet(URI_SCHEMES.keySet());
348 }
349
350
351
352
353
354
355
356
357 @SuppressFBWarnings("USO_UNSAFE_METHOD_SYNCHRONIZATION")
358 public synchronized SelectorProvider getSelectorProvider() {
359 if (selectorProvider != null) {
360 return selectorProvider;
361 }
362 if (selectorProviderClassname == null) {
363 return null;
364 }
365 try {
366 selectorProvider = (SelectorProvider) Class.forName(selectorProviderClassname).getMethod(
367 "provider", new Class<?>[0]).invoke(null);
368 } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException
369 | ClassNotFoundException | RuntimeException e) {
370 throw new IllegalStateException("Cannot instantiate selector provider for "
371 + addressClassname, e);
372 }
373 return selectorProvider;
374 }
375
376
377
378
379
380
381
382 public SocketAddress nullBindAddress() throws IOException {
383 return addressConfig.nullBindAddress();
384 }
385 }