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({"PMD.ShortMethodName"})
334 public static AFSYSTEMSocketAddress of(URI uri, int overridePort) throws SocketException {
335 switch (uri.getScheme()) {
336 case "afsystem":
337 break;
338 default:
339 throw new SocketException("Unsupported URI scheme: " + uri.getScheme());
340 }
341
342 String host;
343 if ((host = uri.getHost()) == null || host.isEmpty()) {
344 String ssp = uri.getSchemeSpecificPart();
345 if (ssp == null || !ssp.startsWith("//")) {
346 throw new SocketException("Unsupported URI: " + uri);
347 }
348 ssp = ssp.substring(2);
349 int i = ssp.indexOf('/');
350 host = i == -1 ? ssp : ssp.substring(0, i);
351 if (host.isEmpty()) {
352 throw new SocketException("Unsupported URI: " + uri);
353 }
354 }
355
356 ByteBuffer bb = ByteBuffer.allocate(8 * 4);
357 for (String p : host.split("\\.")) {
358 int v;
359 try {
360 v = parseUnsignedInt(p, 10);
361 } catch (NumberFormatException e) {
362 throw (SocketException) new SocketException("Unsupported URI: " + uri).initCause(e);
363 }
364 bb.putInt(v);
365 }
366 bb.flip();
367 if (bb.remaining() > 8 * 4) {
368 throw new SocketException("Unsupported URI: " + uri);
369 }
370 SysAddr.ofValue(bb.getInt());
371 bb.getInt();
372 bb.getInt();
373
374 while (bb.remaining() > 0) {
375 if (bb.getInt() != 0) {
376 throw new SocketException("Unsupported URI: " + uri);
377 }
378 }
379
380 return
381
382 resolveAddress(bb.array(), uri.getPort(), addressFamily());
383 }
384
385 @Override
386 public URI toURI(String scheme, URI template) throws IOException {
387 switch (scheme) {
388 case "afsystem":
389 break;
390 default:
391 return super.toURI(scheme, template);
392 }
393
394 ByteBuffer bb = ByteBuffer.wrap(getBytes());
395 StringBuilder sb = new StringBuilder();
396 while (bb.remaining() > 0) {
397 sb.append(toUnsignedString(bb.getInt()));
398 if (bb.remaining() > 0) {
399 sb.append('.');
400 }
401 }
402
403 return new HostAndPort(sb.toString(), getPort()).toURI(scheme, template);
404 }
405 }