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