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.FileDescriptor;
21 import java.io.IOException;
22 import java.net.DatagramPacket;
23 import java.net.DatagramSocket;
24 import java.net.InetAddress;
25 import java.net.InetSocketAddress;
26 import java.net.SocketAddress;
27 import java.net.SocketException;
28 import java.net.SocketImpl;
29 import java.nio.channels.AlreadyBoundException;
30 import java.nio.channels.DatagramChannel;
31 import java.nio.channels.IllegalBlockingModeException;
32 import java.util.concurrent.atomic.AtomicBoolean;
33
34 import org.eclipse.jdt.annotation.Nullable;
35
36 import com.kohlschutter.annotations.compiletime.SuppressFBWarnings;
37
38
39
40
41
42
43
44 public abstract class AFDatagramSocket<A extends AFSocketAddress> extends DatagramSocketShim
45 implements AFSomeSocket, AFSocketExtensions {
46 private static final InetSocketAddress WILDCARD_ADDRESS = new InetSocketAddress(0);
47
48 private final AFDatagramSocketImpl<A> impl;
49 private final AncillaryDataSupport ancillaryDataSupport;
50 private final AtomicBoolean created = new AtomicBoolean(false);
51 private final AtomicBoolean deleteOnClose = new AtomicBoolean(true);
52
53 @SuppressWarnings("this-escape")
54 private final AFDatagramChannel<A> channel = newChannel();
55
56
57
58
59
60
61 protected AFDatagramSocket(final AFDatagramSocketImpl<A> impl) {
62 super(impl);
63 this.impl = impl;
64 this.ancillaryDataSupport = impl.ancillaryDataSupport;
65 }
66
67
68
69
70
71
72 protected abstract AFDatagramChannel<A> newChannel();
73
74
75
76
77
78
79 final AncillaryDataSupport getAncillaryDataSupport() {
80 return ancillaryDataSupport;
81 }
82
83
84
85
86
87
88 @FunctionalInterface
89 public interface Constructor<A extends AFSocketAddress> {
90
91
92
93
94
95
96
97 AFDatagramSocket<A> newSocket(FileDescriptor fd) throws IOException;
98 }
99
100
101
102
103
104
105 protected final Class<? extends AFSocketAddress> socketAddressClass() {
106 return impl.getAddressFamily().getSocketAddressClass();
107 }
108
109
110
111
112
113
114
115
116
117 protected static final <A extends AFSocketAddress> AFDatagramSocket<A> newInstance(
118 Constructor<A> constructor) throws IOException {
119 return constructor.newSocket(null);
120 }
121
122
123
124
125
126
127
128
129
130
131
132
133 protected static final <A extends AFSocketAddress> AFDatagramSocket<A> newInstance(
134 Constructor<A> constructor, FileDescriptor fdObj, int localPort, int remotePort)
135 throws IOException {
136 if (fdObj == null) {
137 return newInstance(constructor);
138 }
139 if (!fdObj.valid()) {
140 throw new SocketException("Invalid file descriptor");
141 }
142
143 int status = NativeUnixSocket.socketStatus(fdObj);
144 if (status == NativeUnixSocket.SOCKETSTATUS_INVALID) {
145 throw new SocketException("Not a valid socket");
146 }
147
148 AFDatagramSocket<A> socket = constructor.newSocket(fdObj);
149 socket.getAFImpl().updatePorts(localPort, remotePort);
150
151 switch (status) {
152 case NativeUnixSocket.SOCKETSTATUS_CONNECTED:
153 socket.internalDummyConnect();
154 break;
155 case NativeUnixSocket.SOCKETSTATUS_BOUND:
156 socket.internalDummyBind();
157 break;
158 case NativeUnixSocket.SOCKETSTATUS_UNKNOWN:
159 break;
160 default:
161 throw new IllegalStateException("Invalid socketStatus response: " + status);
162 }
163
164 return socket;
165 }
166
167 @Override
168 public final void connect(InetAddress address, int port) {
169 throw new IllegalArgumentException("Cannot connect to InetAddress");
170 }
171
172
173
174
175
176
177
178
179
180
181
182
183 public final void peek(DatagramPacket p) throws IOException {
184 synchronized (p) {
185 if (isClosed()) {
186 throw new SocketException("Socket is closed");
187 }
188 getAFImpl().peekData(p);
189 }
190 }
191
192 @Override
193 public final void send(DatagramPacket p) throws IOException {
194 synchronized (p) {
195 if (isClosed()) {
196 throw new SocketException("Socket is closed");
197 }
198 if (!isBound()) {
199 internalDummyBind();
200 }
201 getAFImpl().send(p);
202 }
203 }
204
205 final void internalDummyConnect() throws SocketException {
206 super.connect(AFSocketAddress.INTERNAL_DUMMY_DONT_CONNECT);
207 }
208
209 final void internalDummyBind() throws SocketException {
210 bind(AFSocketAddress.INTERNAL_DUMMY_BIND);
211 }
212
213 @Override
214 public final synchronized void connect(SocketAddress addr) throws SocketException {
215 if (!isBound()) {
216 internalDummyBind();
217 }
218 internalDummyConnect();
219 try {
220 getAFImpl().connect(AFSocketAddress.preprocessSocketAddress(socketAddressClass(), addr,
221 null));
222 } catch (SocketException e) {
223 throw e;
224 } catch (IOException e) {
225 throw (SocketException) new SocketException(e.getMessage()).initCause(e);
226 }
227 }
228
229 @Override
230 public final synchronized @Nullable A getRemoteSocketAddress() {
231 return getAFImpl().getRemoteSocketAddress();
232 }
233
234 @Override
235 public final boolean isConnected() {
236 return super.isConnected() || impl.isConnected();
237 }
238
239 @Override
240 public final boolean isBound() {
241 return super.isBound() || impl.isBound();
242 }
243
244 @Override
245 public final void close() {
246
247
248 if (isClosed()) {
249 return;
250 }
251 getAFImpl().close();
252 boolean wasBound = isBound();
253 if (wasBound && deleteOnClose.get()) {
254 InetAddress addr = getLocalAddress();
255 if (AFInetAddress.isSupportedAddress(addr, addressFamily())) {
256 try {
257 AFSocketAddress socketAddress = AFSocketAddress.unwrap(addr, 0, addressFamily());
258 if (socketAddress != null && socketAddress.hasFilename()) {
259 if (!socketAddress.getFile().delete()) {
260
261 }
262 }
263 } catch (IOException e) {
264
265 }
266 }
267 }
268 super.close();
269 }
270
271 @Override
272 @SuppressWarnings("PMD.CognitiveComplexity")
273 public final synchronized void bind(SocketAddress addr) throws SocketException {
274 boolean isBound = isBound();
275 if (isBound) {
276 if (addr == AFSocketAddress.INTERNAL_DUMMY_BIND) {
277 return;
278 }
279
280 }
281 if (isClosed()) {
282 throw new SocketException("Socket is closed");
283 }
284 if (!isBound) {
285 try {
286 super.bind(AFSocketAddress.INTERNAL_DUMMY_BIND);
287 } catch (AlreadyBoundException e) {
288
289 } catch (SocketException e) {
290 String message = e.getMessage();
291 if (message != null && message.contains("already bound")) {
292
293 } else {
294 throw e;
295 }
296 }
297 }
298
299 boolean isWildcardBind = WILDCARD_ADDRESS.equals(addr);
300
301 AFSocketAddress epoint = (addr == null || isWildcardBind) ? null : AFSocketAddress
302 .preprocessSocketAddress(socketAddressClass(), addr, null);
303 if (epoint instanceof SentinelSocketAddress) {
304 return;
305 }
306
307 try {
308 getAFImpl().bind(epoint);
309 } catch (SocketException e) {
310 if (isWildcardBind) {
311
312 } else {
313 getAFImpl().close();
314 throw e;
315 }
316 }
317 }
318
319 @Override
320 public final @Nullable A getLocalSocketAddress() {
321 if (isClosed()) {
322 return null;
323 }
324 if (!isBound()) {
325 return null;
326 }
327 return getAFImpl().getLocalSocketAddress();
328 }
329
330
331
332
333
334
335
336
337
338
339 public final boolean isDeleteOnClose() {
340 return deleteOnClose.get();
341 }
342
343
344
345
346
347
348
349
350
351 public final void setDeleteOnClose(boolean b) {
352 deleteOnClose.set(b);
353 }
354
355 final AFDatagramSocketImpl<A> getAFImpl() {
356 if (created.compareAndSet(false, true)) {
357 try {
358 getSoTimeout();
359 } catch (SocketException e) {
360
361 }
362 }
363 return impl;
364 }
365
366 final AFDatagramSocketImpl<A> getAFImpl(boolean create) {
367 if (create) {
368 return getAFImpl();
369 } else {
370 return impl;
371 }
372 }
373
374 @Override
375 public final int getAncillaryReceiveBufferSize() {
376 return ancillaryDataSupport.getAncillaryReceiveBufferSize();
377 }
378
379 @Override
380 public final void setAncillaryReceiveBufferSize(int size) {
381 ancillaryDataSupport.setAncillaryReceiveBufferSize(size);
382 }
383
384 @Override
385 public final void ensureAncillaryReceiveBufferSize(int minSize) {
386 ancillaryDataSupport.ensureAncillaryReceiveBufferSize(minSize);
387 }
388
389 @Override
390 public final boolean isClosed() {
391 return super.isClosed() || getAFImpl().isClosed();
392 }
393
394 @SuppressFBWarnings("EI_EXPOSE_REP")
395 @Override
396 public AFDatagramChannel<A> getChannel() {
397 return channel;
398 }
399
400 @Override
401 public final FileDescriptor getFileDescriptor() throws IOException {
402 return getAFImpl().getFileDescriptor();
403 }
404
405 @Override
406 public final void receive(DatagramPacket p) throws IOException {
407 getAFImpl().receive(p);
408 }
409
410
411
412
413
414
415 protected final AFAddressFamily<A> addressFamily() {
416 return getAFImpl().getAddressFamily();
417 }
418
419
420
421
422
423
424
425
426 protected AFSocketImplExtensions<A> getImplExtensions() {
427 return getAFImpl(false).getImplExtensions();
428 }
429
430
431
432
433
434
435
436
437
438 @Override
439 public <T> T getOption(AFSocketOption<T> name) throws IOException {
440 return getAFImpl().getCore().getOption(name);
441 }
442
443
444
445
446
447
448
449
450
451
452 @Override
453 public <T> DatagramSocket setOption(AFSocketOption<T> name, T value) throws IOException {
454 getAFImpl().getCore().setOption(name, value);
455 return this;
456 }
457
458
459
460
461
462
463
464
465
466
467
468 public AFDatagramSocket<A> accept() throws IOException {
469 return accept1(true);
470 }
471
472
473
474
475
476
477
478
479
480
481 public final void listen(int backlog) throws IOException {
482 FileDescriptor fdesc = getAFImpl().getCore().validFdOrException();
483 if (backlog <= 0) {
484 backlog = 50;
485 }
486 NativeUnixSocket.listen(fdesc, backlog);
487 }
488
489
490
491
492
493
494
495
496 protected abstract AFDatagramSocket<A> newDatagramSocketInstance() throws IOException;
497
498
499 AFDatagramSocket<A> accept1(boolean throwOnFail) throws IOException {
500 AFDatagramSocket<A> as = newDatagramSocketInstance();
501
502 boolean success = getAFImpl().accept0(as.getAFImpl(false));
503 if (isClosed()) {
504
505 throw new SocketClosedException("Socket is closed");
506 }
507
508 if (!success) {
509 if (throwOnFail) {
510 if (getChannel().isBlocking()) {
511
512 return null;
513 } else {
514
515 throw new IllegalBlockingModeException();
516 }
517 } else {
518 return null;
519 }
520 }
521
522 as.getAFImpl(true);
523 as.connect(AFSocketAddress.INTERNAL_DUMMY_CONNECT);
524 as.getAFImpl().updatePorts(getAFImpl().getLocalPort1(), getAFImpl().getRemotePort());
525
526 return as;
527 }
528
529 @Override
530 public void setShutdownOnClose(boolean enabled) {
531 getAFImpl().getCore().setShutdownOnClose(enabled);
532 }
533 }