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