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