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.File;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.net.InetAddress;
24 import java.net.SocketAddress;
25 import java.net.SocketException;
26 import java.net.URI;
27 import java.nio.ByteBuffer;
28 import java.util.Arrays;
29 import java.util.HashSet;
30 import java.util.Objects;
31 import java.util.Set;
32
33 import org.eclipse.jdt.annotation.NonNull;
34 import org.eclipse.jdt.annotation.NonNullByDefault;
35 import org.newsclub.net.unix.pool.ObjectPool.Lease;
36
37
38
39
40
41
42 public final class AFSYSTEMSocketAddress extends AFSocketAddress {
43 private static final long serialVersionUID = 1L;
44
45 private static AFAddressFamily<AFSYSTEMSocketAddress> afSystem;
46 private static final String SELECTOR_PROVIDER_CLASS =
47 "org.newsclub.net.unix.darwin.system.AFSYSTEMSelectorProvider";
48
49
50
51
52
53
54 @NonNullByDefault
55 public static final class SysAddr extends NamedInteger {
56 private static final long serialVersionUID = 1L;
57
58
59
60
61 public static final SysAddr AF_SYS_CONTROL;
62
63 private static final @NonNull SysAddr[] VALUES = init(new @NonNull SysAddr[] {
64 AF_SYS_CONTROL = new SysAddr("AF_SYS_CONTROL", 2)
65 });
66
67 private SysAddr(int id) {
68 super(id);
69 }
70
71 private SysAddr(String name, int id) {
72 super(name, id);
73 }
74
75
76
77
78
79
80
81 public static SysAddr ofValue(int v) {
82 return ofValue(VALUES, SysAddr::new, v);
83 }
84 }
85
86 private AFSYSTEMSocketAddress(int port, final byte[] socketAddress,
87 Lease<ByteBuffer> nativeAddress) throws SocketException {
88 super(port, socketAddress, nativeAddress, addressFamily());
89 }
90
91 private static AFSYSTEMSocketAddress newAFSocketAddress(int port, final byte[] socketAddress,
92 Lease<ByteBuffer> nativeAddress) throws SocketException {
93 return newDeserializedAFSocketAddress(port, socketAddress, nativeAddress, addressFamily(),
94 AFSYSTEMSocketAddress::new);
95 }
96
97
98
99
100
101
102
103
104
105
106
107
108
109 public static AFSYSTEMSocketAddress ofSysAddrIdUnit(int javaPort, SysAddr sysAddr, int id,
110 int unit) throws SocketException {
111 return resolveAddress(toBytes(sysAddr, id, unit), javaPort, addressFamily());
112 }
113
114
115
116
117
118
119
120
121
122
123
124 public static AFSYSTEMSocketAddress ofSysAddrIdUnit(SysAddr sysAddr, int id, int unit)
125 throws SocketException {
126 return ofSysAddrIdUnit(0, sysAddr, id, unit);
127 }
128
129
130
131
132
133
134
135
136
137
138
139 public static AFSYSTEMSocketAddress unwrap(InetAddress address, int port) throws SocketException {
140 return AFSocketAddress.unwrap(address, port, addressFamily());
141 }
142
143
144
145
146
147
148
149
150
151
152
153
154 public static AFSYSTEMSocketAddress unwrap(String hostname, int port) throws SocketException {
155 return AFSocketAddress.unwrap(hostname, port, addressFamily());
156 }
157
158
159
160
161
162
163
164
165
166 public static AFSYSTEMSocketAddress unwrap(SocketAddress address) throws SocketException {
167 Objects.requireNonNull(address);
168 if (!isSupportedAddress(address)) {
169 throw new SocketException("Unsupported address");
170 }
171 return (AFSYSTEMSocketAddress) address;
172 }
173
174 @Override
175 public String toString() {
176 int port = getPort();
177
178 byte[] bytes = getBytes();
179 if (bytes.length != (8 * 4)) {
180 return getClass().getName() + "[" + (port == 0 ? "" : "port=" + port) + ";UNKNOWN" + "]";
181 }
182
183 ByteBuffer bb = ByteBuffer.wrap(bytes);
184 SysAddr sysAddr = SysAddr.ofValue(bb.getInt());
185 int id = bb.getInt();
186 int unit = bb.getInt();
187
188 return getClass().getName() + "[" + (port == 0 ? "" : "port=" + port + ";") + sysAddr + ";id="
189 + id + ";unit=" + unit + "]";
190 }
191
192
193
194
195
196
197 public @NonNull SysAddr getSysAddr() {
198 ByteBuffer bb = ByteBuffer.wrap(getBytes());
199 return SysAddr.ofValue(bb.getInt(0));
200 }
201
202
203
204
205
206
207 public int getId() {
208 ByteBuffer bb = ByteBuffer.wrap(getBytes());
209 return bb.getInt(4);
210 }
211
212
213
214
215
216
217 public int getUnit() {
218 ByteBuffer bb = ByteBuffer.wrap(getBytes());
219 return bb.getInt(8);
220 }
221
222 @Override
223 public boolean hasFilename() {
224 return false;
225 }
226
227 @Override
228 public File getFile() throws FileNotFoundException {
229 throw new FileNotFoundException("no file");
230 }
231
232
233
234
235
236
237
238
239
240 public static boolean isSupportedAddress(InetAddress addr) {
241 return AFSocketAddress.isSupportedAddress(addr, addressFamily());
242 }
243
244
245
246
247
248
249
250
251 public static boolean isSupportedAddress(SocketAddress addr) {
252 return (addr instanceof AFSYSTEMSocketAddress);
253 }
254
255 @SuppressWarnings("cast")
256 private static byte[] toBytes(SysAddr sysAddr, int id, int unit) {
257 ByteBuffer bb = ByteBuffer.allocate(8 * 4);
258 bb.putInt(sysAddr.value());
259 bb.putInt(id);
260 bb.putInt(unit);
261 bb.putInt(0);
262 bb.putInt(0);
263 bb.putInt(0);
264 bb.putInt(0);
265 bb.putInt(0);
266 return (byte[]) bb.flip().array();
267 }
268
269
270
271
272
273
274 @SuppressWarnings("null")
275 public static synchronized AFAddressFamily<AFSYSTEMSocketAddress> addressFamily() {
276 if (afSystem == null) {
277 afSystem = AFAddressFamily.registerAddressFamily("system",
278 AFSYSTEMSocketAddress.class, new AFSocketAddressConfig<AFSYSTEMSocketAddress>() {
279
280 private final AFSocketAddressConstructor<AFSYSTEMSocketAddress> addrConstr =
281 isUseDeserializationForInit() ? AFSYSTEMSocketAddress::newAFSocketAddress
282 : AFSYSTEMSocketAddress::new;
283
284 @Override
285 protected AFSYSTEMSocketAddress parseURI(URI u, int port) throws SocketException {
286 return AFSYSTEMSocketAddress.of(u, port);
287 }
288
289 @Override
290 protected AFSocketAddressConstructor<AFSYSTEMSocketAddress> addressConstructor() {
291 return addrConstr;
292 }
293
294 @Override
295 protected String selectorProviderClassname() {
296 return SELECTOR_PROVIDER_CLASS;
297 }
298
299 @Override
300 protected Set<String> uriSchemes() {
301 return new HashSet<>(Arrays.asList("afsystem"));
302 }
303 });
304 try {
305 Class.forName(SELECTOR_PROVIDER_CLASS);
306 } catch (ClassNotFoundException e) {
307
308 }
309 }
310 return afSystem;
311 }
312
313
314
315
316
317
318
319
320 @SuppressWarnings("PMD.ShortMethodName")
321 public static AFSYSTEMSocketAddress of(URI uri) throws SocketException {
322 return of(uri, -1);
323 }
324
325
326
327
328
329
330
331
332
333 @SuppressWarnings({
334 "PMD.CognitiveComplexity", "PMD.CyclomaticComplexity", "PMD.ExcessiveMethodLength",
335 "PMD.NcssCount", "PMD.NPathComplexity", "PMD.ShortMethodName"})
336 public static AFSYSTEMSocketAddress of(URI uri, int overridePort) throws SocketException {
337 switch (uri.getScheme()) {
338 case "afsystem":
339 break;
340 default:
341 throw new SocketException("Unsupported URI scheme: " + uri.getScheme());
342 }
343
344 String host;
345 if ((host = uri.getHost()) == null || host.isEmpty()) {
346 String ssp = uri.getSchemeSpecificPart();
347 if (ssp == null || !ssp.startsWith("//")) {
348 throw new SocketException("Unsupported URI: " + uri);
349 }
350 ssp = ssp.substring(2);
351 int i = ssp.indexOf('/');
352 host = i == -1 ? ssp : ssp.substring(0, i);
353 if (host.isEmpty()) {
354 throw new SocketException("Unsupported URI: " + uri);
355 }
356 }
357
358 ByteBuffer bb = ByteBuffer.allocate(8 * 4);
359 for (String p : host.split("\\.")) {
360 int v;
361 try {
362 v = parseUnsignedInt(p, 10);
363 } catch (NumberFormatException e) {
364 throw (SocketException) new SocketException("Unsupported URI: " + uri).initCause(e);
365 }
366 bb.putInt(v);
367 }
368 bb.flip();
369 if (bb.remaining() > 8 * 4) {
370 throw new SocketException("Unsupported URI: " + uri);
371 }
372 SysAddr.ofValue(bb.getInt());
373 bb.getInt();
374 bb.getInt();
375
376 while (bb.remaining() > 0) {
377 if (bb.getInt() != 0) {
378 throw new SocketException("Unsupported URI: " + uri);
379 }
380 }
381
382 return
383
384 resolveAddress(bb.array(), uri.getPort(), addressFamily());
385 }
386
387 @Override
388 @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CompareObjectsWithEquals"})
389 public URI toURI(String scheme, URI template) throws IOException {
390 switch (scheme) {
391 case "afsystem":
392 break;
393 default:
394 return super.toURI(scheme, template);
395 }
396
397 ByteBuffer bb = ByteBuffer.wrap(getBytes());
398 StringBuilder sb = new StringBuilder();
399 while (bb.remaining() > 0) {
400 sb.append(toUnsignedString(bb.getInt()));
401 if (bb.remaining() > 0) {
402 sb.append('.');
403 }
404 }
405
406 return new HostAndPort(sb.toString(), getPort()).toURI(scheme, template);
407 }
408 }