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 static org.newsclub.net.unix.NativeUnixSocket.SHUT_RD;
21 import static org.newsclub.net.unix.NativeUnixSocket.SHUT_RD_WR;
22 import static org.newsclub.net.unix.NativeUnixSocket.SHUT_WR;
23
24 import java.io.EOFException;
25 import java.io.FileDescriptor;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.InterruptedIOException;
29 import java.io.OutputStream;
30 import java.net.InetAddress;
31 import java.net.SocketAddress;
32 import java.net.SocketException;
33 import java.net.SocketImpl;
34 import java.net.SocketOption;
35 import java.net.SocketOptions;
36 import java.net.SocketTimeoutException;
37 import java.nio.ByteBuffer;
38 import java.util.Set;
39 import java.util.concurrent.atomic.AtomicBoolean;
40 import java.util.concurrent.atomic.AtomicInteger;
41
42 import org.eclipse.jdt.annotation.NonNull;
43 import org.eclipse.jdt.annotation.Nullable;
44
45
46
47
48
49
50
51 @SuppressWarnings({
52 "PMD.CyclomaticComplexity", "PMD.CouplingBetweenObjects",
53 "UnsafeFinalization" })
54 public abstract class AFSocketImpl<A extends AFSocketAddress> extends SocketImplShim {
55 private static final int SHUTDOWN_RD_WR = (1 << SHUT_RD) | (1 << SHUT_WR);
56
57 private final AFSocketStreamCore core;
58 final AncillaryDataSupport ancillaryDataSupport = new AncillaryDataSupport();
59
60 private final AtomicBoolean bound = new AtomicBoolean(false);
61 private Boolean createType = null;
62 private final AtomicBoolean connected = new AtomicBoolean(false);
63
64 private volatile boolean closedInputStream = false;
65 private volatile boolean closedOutputStream = false;
66
67 private final AFInputStream in;
68 private final AFOutputStream out;
69
70 private boolean reuseAddr = true;
71
72 private final AtomicInteger socketTimeout = new AtomicInteger(0);
73 private final AFAddressFamily<A> addressFamily;
74
75 private int shutdownState = 0;
76
77 private AFSocketImplExtensions<A> implExtensions = null;
78
79
80
81
82
83
84
85 static final class AFSocketStreamCore extends AFSocketCore {
86 AFSocketStreamCore(AFSocketImpl<?> observed, FileDescriptor fd,
87 AncillaryDataSupport ancillaryDataSupport, AFAddressFamily<?> af) {
88 super(observed, fd, ancillaryDataSupport, af, false);
89 }
90
91 void createSocket(FileDescriptor fdTarget, AFSocketType type) throws IOException {
92 NativeUnixSocket.createSocket(fdTarget, addressFamily().getDomain(), type.getId());
93 }
94
95
96
97
98
99 @Override
100 protected void unblockAccepts() {
101 if (socketAddress == null || socketAddress.getBytes() == null || inode.get() < 0) {
102 return;
103 }
104
105 while (hasPendingAccepts()) {
106 try {
107 FileDescriptor tmpFd = new FileDescriptor();
108
109 try {
110 createSocket(tmpFd, AFSocketType.SOCK_STREAM);
111 ByteBuffer ab = socketAddress.getNativeAddressDirectBuffer();
112 NativeUnixSocket.connect(ab, ab.limit(), tmpFd, inode.get());
113 } catch (IOException e) {
114
115
116 return;
117 }
118 if (isShutdownOnClose()) {
119 try {
120 NativeUnixSocket.shutdown(tmpFd, SHUT_RD_WR);
121 } catch (Exception e) {
122
123 }
124 }
125 try {
126 NativeUnixSocket.close(tmpFd);
127 } catch (Exception e) {
128
129 }
130 } catch (RuntimeException e) {
131
132 }
133
134
135 try {
136 Thread.sleep(5);
137 } catch (InterruptedException e) {
138
139 }
140 }
141 }
142 }
143
144
145
146
147
148
149
150 protected AFSocketImpl(AFAddressFamily<@NonNull A> addressFamily, FileDescriptor fdObj) {
151 super();
152 this.addressFamily = addressFamily;
153 this.address = InetAddress.getLoopbackAddress();
154 this.core = new AFSocketStreamCore(this, fdObj, ancillaryDataSupport, addressFamily);
155 this.fd = core.fd;
156 this.in = newInputStream();
157 this.out = newOutputStream();
158 }
159
160
161
162
163
164
165 protected final AFInputStream newInputStream() {
166 return new AFInputStreamImpl();
167 }
168
169
170
171
172
173
174 protected final AFOutputStream newOutputStream() {
175 return new AFOutputStreamImpl();
176 }
177
178 final FileDescriptor getFD() {
179 return fd;
180 }
181
182
183 final boolean isConnected() {
184 if (connected.get()) {
185 return true;
186 }
187 if (isClosed()) {
188 return false;
189 }
190 if (core.isConnected(false)) {
191 connected.set(true);
192 return true;
193 }
194 return false;
195 }
196
197 final boolean isBound() {
198 if (bound.get()) {
199 return true;
200 }
201 if (isClosed()) {
202 return false;
203 }
204 if (core.isConnected(true)) {
205 bound.set(true);
206 return true;
207 }
208 return false;
209 }
210
211 final AFSocketCore getCore() {
212 return core;
213 }
214
215 boolean isClosed() {
216 return core.isClosed();
217 }
218
219
220 @Override
221 protected final void accept(SocketImpl socket) throws IOException {
222 accept0(socket);
223 }
224
225 @SuppressWarnings("Finally" )
226 final boolean accept0(SocketImpl socket) throws IOException {
227 FileDescriptor fdesc = core.validFdOrException();
228 if (isClosed()) {
229 throw new SocketException("Socket is closed");
230 } else if (!isBound()) {
231 throw new SocketException("Socket is not bound");
232 }
233
234 AFSocketAddress socketAddress = core.socketAddress;
235 AFSocketAddress boundSocketAddress = getLocalSocketAddress();
236 if (boundSocketAddress != null) {
237
238 core.socketAddress = socketAddress = boundSocketAddress;
239 }
240
241 if (socketAddress == null) {
242 throw new SocketException("Socket is not bound");
243 }
244
245 @SuppressWarnings("unchecked")
246 final AFSocketImpl<A> si = (AFSocketImpl<A>) socket;
247 core.incPendingAccepts();
248 try {
249 ByteBuffer ab = socketAddress.getNativeAddressDirectBuffer();
250
251 SocketException caught = null;
252 try {
253 if (!NativeUnixSocket.accept(ab, ab.limit(), fdesc, si.fd, core.inode.get(), socketTimeout
254 .get())) {
255 return false;
256 }
257 } catch (SocketException e) {
258 caught = e;
259 } finally {
260 if (!isBound() || isClosed()) {
261 if (getCore().isShutdownOnClose()) {
262 try {
263 NativeUnixSocket.shutdown(si.fd, SHUT_RD_WR);
264 } catch (Exception e) {
265
266 }
267 }
268 try {
269 NativeUnixSocket.close(si.fd);
270 } catch (Exception e) {
271
272 }
273 if (caught != null) {
274 throw caught;
275 } else {
276 throw new SocketClosedException("Socket is closed");
277 }
278 } else if (caught != null) {
279 throw caught;
280 }
281 }
282 } finally {
283 core.decPendingAccepts();
284 }
285 si.setSocketAddress(socketAddress);
286 si.connected.set(true);
287
288 return true;
289 }
290
291 final void setSocketAddress(AFSocketAddress socketAddress) {
292 if (socketAddress == null) {
293 this.core.socketAddress = null;
294 this.address = null;
295 this.localport = -1;
296 } else {
297 this.core.socketAddress = socketAddress;
298 this.address = socketAddress.getAddress();
299 if (this.localport <= 0) {
300 this.localport = socketAddress.getPort();
301 }
302 }
303 }
304
305 @Override
306 protected final int available() throws IOException {
307 FileDescriptor fdesc = core.validFdOrException();
308 return NativeUnixSocket.available(fdesc, core.getThreadLocalDirectByteBuffer(0));
309 }
310
311 final void bind(SocketAddress addr, int options) throws IOException {
312 if (addr == null) {
313 throw new IllegalArgumentException("Cannot bind to null address");
314 }
315 if (!(addr instanceof AFSocketAddress)) {
316 throw new SocketException("Cannot bind to this type of address: " + addr.getClass());
317 }
318
319 bound.set(true);
320
321 if (addr == AFSocketAddress.INTERNAL_DUMMY_BIND) {
322 core.inode.set(0);
323 return;
324 }
325
326 AFSocketAddress socketAddress = (AFSocketAddress) addr;
327
328 this.setSocketAddress(socketAddress);
329 ByteBuffer ab = socketAddress.getNativeAddressDirectBuffer();
330 core.inode.set(NativeUnixSocket.bind(ab, ab.limit(), fd, options));
331 core.validFdOrException();
332 }
333
334 @Override
335 @SuppressWarnings("hiding")
336 protected final void bind(InetAddress host, int port) throws IOException {
337
338 }
339
340 private void checkClose() throws IOException {
341 if (closedInputStream && closedOutputStream) {
342 close();
343 }
344 }
345
346 @Override
347 protected final void close() throws IOException {
348 shutdown();
349 core.runCleaner();
350 }
351
352 @Override
353 @SuppressWarnings("hiding")
354 protected final void connect(String host, int port) throws IOException {
355 throw new SocketException("Cannot bind to this type of address: " + InetAddress.class);
356 }
357
358 @Override
359 @SuppressWarnings("hiding")
360 protected final void connect(InetAddress address, int port) throws IOException {
361 throw new SocketException("Cannot bind to this type of address: " + InetAddress.class);
362 }
363
364 @Override
365 protected final void connect(SocketAddress addr, int connectTimeout) throws IOException {
366 connect0(addr, connectTimeout);
367 }
368
369 final boolean connect0(SocketAddress addr, int connectTimeout) throws IOException {
370 if (addr == AFSocketAddress.INTERNAL_DUMMY_CONNECT) {
371 this.connected.set(true);
372 return true;
373 } else if (addr == AFSocketAddress.INTERNAL_DUMMY_DONT_CONNECT) {
374 return false;
375 }
376
377 if (!(addr instanceof AFSocketAddress)) {
378 throw new SocketException("Cannot connect to this type of address: " + addr.getClass());
379 }
380
381 AFSocketAddress socketAddress = (AFSocketAddress) addr;
382 ByteBuffer ab = socketAddress.getNativeAddressDirectBuffer();
383 boolean success = false;
384 boolean ignoreSpuriousTimeout = true;
385 do {
386 try {
387 success = NativeUnixSocket.connect(ab, ab.limit(), fd, -1);
388 break;
389 } catch (SocketTimeoutException e) {
390
391
392 if (ignoreSpuriousTimeout) {
393 Object o = getOption(SocketOptions.SO_TIMEOUT);
394 if (o instanceof Integer) {
395 if (((Integer) o) == 0) {
396 ignoreSpuriousTimeout = false;
397 continue;
398 }
399 } else if (o == null) {
400 ignoreSpuriousTimeout = false;
401 continue;
402 }
403 }
404 throw e;
405 }
406 } while (!Thread.interrupted());
407 if (success) {
408 setSocketAddress(socketAddress);
409 this.connected.set(true);
410 }
411 core.validFdOrException();
412 return success;
413 }
414
415 @Override
416 protected final void create(boolean stream) throws IOException {
417 if (isClosed()) {
418 throw new SocketException("Already closed");
419 }
420 if (fd.valid()) {
421 if (createType != null) {
422 if (createType.booleanValue() != stream) {
423 throw new IllegalStateException("Already created with different mode");
424 }
425 } else {
426 createType = stream;
427 }
428 return;
429 }
430 createType = stream;
431 createSocket(fd, stream ? AFSocketType.SOCK_STREAM : AFSocketType.SOCK_DGRAM);
432 }
433
434 @Override
435 protected final AFInputStream getInputStream() throws IOException {
436 if (!isConnected() && !isBound()) {
437 throw new SocketClosedException("Not connected/not bound");
438 }
439 core.validFdOrException();
440 return in;
441 }
442
443 @Override
444 protected final AFOutputStream getOutputStream() throws IOException {
445 if (!isClosed() && !isBound()) {
446 throw new SocketClosedException("Not connected/not bound");
447 }
448 core.validFdOrException();
449 return out;
450 }
451
452 @Override
453 protected final void listen(int backlog) throws IOException {
454 FileDescriptor fdesc = core.validFdOrException();
455 if (backlog <= 0) {
456 backlog = 50;
457 }
458 NativeUnixSocket.listen(fdesc, backlog);
459 }
460
461 @Override
462 protected final boolean supportsUrgentData() {
463 return false;
464 }
465
466 @Override
467 protected final void sendUrgentData(int data) throws IOException {
468 throw new UnsupportedOperationException();
469 }
470
471 private final class AFInputStreamImpl extends AFInputStream {
472 private volatile boolean streamClosed = false;
473 private final AtomicBoolean eofReached = new AtomicBoolean(false);
474
475 private final int opt = (core.isBlocking() ? 0 : NativeUnixSocket.OPT_NON_BLOCKING);
476
477 @Override
478 public int read(byte[] buf, int off, int len) throws IOException {
479 if (streamClosed) {
480 throw new SocketClosedException("This InputStream has already been closed.");
481 }
482 if (eofReached.get()) {
483 return -1;
484 }
485
486 FileDescriptor fdesc = core.validFdOrException();
487 if (len == 0) {
488 return 0;
489 } else if (off < 0 || len < 0 || (len > buf.length - off)) {
490 throw new IndexOutOfBoundsException();
491 }
492
493 try {
494 return NativeUnixSocket.read(fdesc, buf, off, len, opt, ancillaryDataSupport, socketTimeout
495 .get());
496 } catch (EOFException e) {
497 eofReached.set(true);
498 throw e;
499 }
500 }
501
502 @Override
503 public int read() throws IOException {
504 FileDescriptor fdesc = core.validFdOrException();
505
506 if (eofReached.get()) {
507 return -1;
508 }
509
510 int byteRead = NativeUnixSocket.read(fdesc, null, 0, 1, opt, ancillaryDataSupport,
511 socketTimeout.get());
512 if (byteRead < 0) {
513 eofReached.set(true);
514 return -1;
515 } else {
516 return byteRead;
517 }
518 }
519
520 @Override
521 public synchronized void close() throws IOException {
522 streamClosed = true;
523 FileDescriptor fdesc = core.validFd();
524 if (fdesc != null && getCore().isShutdownOnClose()) {
525 NativeUnixSocket.shutdown(fdesc, SHUT_RD);
526 }
527
528 closedInputStream = true;
529 checkClose();
530 }
531
532 @Override
533 public int available() throws IOException {
534 if (streamClosed) {
535 throw new SocketClosedException("This InputStream has already been closed.");
536 }
537
538 return AFSocketImpl.this.available();
539 }
540
541 @Override
542 public FileDescriptor getFileDescriptor() throws IOException {
543 return getFD();
544 }
545 }
546
547 private static boolean checkWriteInterruptedException(int bytesTransferred)
548 throws InterruptedIOException {
549 if (Thread.interrupted()) {
550 InterruptedIOException ex = new InterruptedIOException("Thread interrupted during write");
551 ex.bytesTransferred = bytesTransferred;
552 Thread.currentThread().interrupt();
553 throw ex;
554 }
555 return true;
556 }
557
558 private final class AFOutputStreamImpl extends AFOutputStream {
559 private volatile boolean streamClosed = false;
560
561 private final int opt = (core.isBlocking() ? 0 : NativeUnixSocket.OPT_NON_BLOCKING);
562
563 @Override
564 public void write(int oneByte) throws IOException {
565 FileDescriptor fdesc = core.validFdOrException();
566
567 int written;
568 do {
569 written = NativeUnixSocket.write(fdesc, null, oneByte, 1, opt, ancillaryDataSupport);
570 if (written != 0) {
571 break;
572 }
573 } while (checkWriteInterruptedException(0));
574 }
575
576 @Override
577 public void write(byte[] buf, int off, int len) throws IOException {
578 if (streamClosed) {
579 throw new SocketException("This OutputStream has already been closed.");
580 }
581 if (len < 0 || off < 0 || len > buf.length - off) {
582 throw new IndexOutOfBoundsException();
583 }
584 FileDescriptor fdesc = core.validFdOrException();
585
586
587
588 if (len == 0 && !AFSocket.supports(AFSocketCapability.CAPABILITY_ZERO_LENGTH_SEND)) {
589 return;
590 }
591
592 int writtenTotal = 0;
593
594 do {
595 final int written = NativeUnixSocket.write(fdesc, buf, off, len, opt, ancillaryDataSupport);
596 if (written < 0) {
597 if (len == 0) {
598
599
600
601
602
603
604
605 return;
606 } else {
607 throw new IOException("Unspecific error while writing");
608 }
609 }
610
611 len -= written;
612 off += written;
613 writtenTotal += written;
614 } while (len > 0 && checkWriteInterruptedException(writtenTotal));
615 }
616
617 @Override
618 public synchronized void close() throws IOException {
619 if (streamClosed) {
620 return;
621 }
622 streamClosed = true;
623 FileDescriptor fdesc = core.validFd();
624 if (fdesc != null && getCore().isShutdownOnClose()) {
625 NativeUnixSocket.shutdown(fdesc, SHUT_WR);
626 }
627 closedOutputStream = true;
628 checkClose();
629 }
630
631 @Override
632 public FileDescriptor getFileDescriptor() throws IOException {
633 return getFD();
634 }
635 }
636
637 @Override
638 public final String toString() {
639 return super.toString() + "[fd=" + fd + "; addr=" + this.core.socketAddress + "; connected="
640 + connected + "; bound=" + bound + "]";
641 }
642
643 private static int expectInteger(Object value) throws SocketException {
644 if (value == null) {
645 throw (SocketException) new SocketException("Value must not be null").initCause(
646 new NullPointerException());
647 }
648 try {
649 return (Integer) value;
650 } catch (final ClassCastException e) {
651 throw (SocketException) new SocketException("Unsupported value: " + value).initCause(e);
652 }
653 }
654
655 private static int expectBoolean(Object value) throws SocketException {
656 if (value == null) {
657 throw (SocketException) new SocketException("Value must not be null").initCause(
658 new NullPointerException());
659 }
660 try {
661 return ((Boolean) value) ? 1 : 0;
662 } catch (final ClassCastException e) {
663 throw (SocketException) new SocketException("Unsupported value: " + value).initCause(e);
664 }
665 }
666
667 @Override
668 public Object getOption(int optID) throws SocketException {
669 return getOption0(optID);
670 }
671
672 private Object getOption0(int optID) throws SocketException {
673 if (isClosed()) {
674 throw new SocketException("Socket is closed");
675 }
676 if (optID == SocketOptions.SO_REUSEADDR) {
677 return reuseAddr;
678 }
679
680 FileDescriptor fdesc = core.validFdOrException();
681 return getOptionDefault(fdesc, optID, socketTimeout, addressFamily);
682 }
683
684 static final Object getOptionDefault(FileDescriptor fdesc, int optID, AtomicInteger acceptTimeout,
685 AFAddressFamily<?> af) throws SocketException {
686 try {
687 switch (optID) {
688 case SocketOptions.SO_KEEPALIVE:
689 try {
690 return (NativeUnixSocket.getSocketOptionInt(fdesc, optID) != 0);
691 } catch (SocketException e) {
692
693 return false;
694 }
695 case SocketOptions.TCP_NODELAY:
696 return (NativeUnixSocket.getSocketOptionInt(fdesc, optID) != 0);
697 case SocketOptions.SO_TIMEOUT:
698 int v = Math.max(NativeUnixSocket.getSocketOptionInt(fdesc, 0x1005), NativeUnixSocket
699 .getSocketOptionInt(fdesc, 0x1006));
700 if (v == -1) {
701
702 return 0;
703 }
704 return Math.max((acceptTimeout == null ? 0 : acceptTimeout.get()), v);
705 case SocketOptions.SO_LINGER:
706 case SocketOptions.SO_RCVBUF:
707 case SocketOptions.SO_SNDBUF:
708 return NativeUnixSocket.getSocketOptionInt(fdesc, optID);
709 case SocketOptions.IP_TOS:
710 return 0;
711 case SocketOptions.SO_BINDADDR:
712 return AFSocketAddress.getInetAddress(fdesc, false, af);
713 case SocketOptions.SO_REUSEADDR:
714 return false;
715 default:
716 throw new SocketException("Unsupported option: " + optID);
717 }
718 } catch (final SocketException e) {
719 throw e;
720 } catch (final Exception e) {
721 throw (SocketException) new SocketException("Could not get option").initCause(e);
722 }
723 }
724
725 @Override
726 public void setOption(int optID, Object value) throws SocketException {
727 setOption0(optID, value);
728 }
729
730 private void setOption0(int optID, Object value) throws SocketException {
731 if (isClosed()) {
732 throw new SocketException("Socket is closed");
733 }
734 if (optID == SocketOptions.SO_REUSEADDR) {
735 reuseAddr = (expectBoolean(value) != 0);
736 return;
737 }
738
739 FileDescriptor fdesc = core.validFdOrException();
740 setOptionDefault(fdesc, optID, value, socketTimeout);
741 }
742
743
744
745
746
747
748
749
750 protected final Object getOptionLenient(int optID) throws SocketException {
751 try {
752 return getOption0(optID);
753 } catch (SocketException e) {
754 switch (optID) {
755 case SocketOptions.TCP_NODELAY:
756 case SocketOptions.SO_KEEPALIVE:
757 return false;
758 default:
759 throw e;
760 }
761 }
762 }
763
764
765
766
767
768
769
770
771 protected final void setOptionLenient(int optID, Object value) throws SocketException {
772 try {
773 setOption0(optID, value);
774 } catch (SocketException e) {
775 switch (optID) {
776 case SocketOptions.TCP_NODELAY:
777 return;
778 default:
779 throw e;
780 }
781 }
782 }
783
784 static final void setOptionDefault(FileDescriptor fdesc, int optID, Object value,
785 AtomicInteger acceptTimeout) throws SocketException {
786 try {
787 switch (optID) {
788 case SocketOptions.SO_LINGER:
789
790 if (value instanceof Boolean) {
791 final boolean b = (Boolean) value;
792 if (b) {
793 throw new SocketException("Only accepting Boolean.FALSE here");
794 }
795 NativeUnixSocket.setSocketOptionInt(fdesc, optID, -1);
796 return;
797 }
798 NativeUnixSocket.setSocketOptionInt(fdesc, optID, expectInteger(value));
799 return;
800 case SocketOptions.SO_TIMEOUT: {
801 int timeout = expectInteger(value);
802 try {
803 NativeUnixSocket.setSocketOptionInt(fdesc, 0x1005, timeout);
804 } catch (InvalidArgumentSocketException e) {
805
806 }
807 try {
808 NativeUnixSocket.setSocketOptionInt(fdesc, 0x1006, timeout);
809 } catch (InvalidArgumentSocketException e) {
810
811 }
812 if (acceptTimeout != null) {
813 acceptTimeout.set(timeout);
814 }
815 return;
816 }
817 case SocketOptions.SO_RCVBUF:
818 case SocketOptions.SO_SNDBUF:
819 NativeUnixSocket.setSocketOptionInt(fdesc, optID, expectInteger(value));
820 return;
821 case SocketOptions.SO_KEEPALIVE:
822 try {
823 NativeUnixSocket.setSocketOptionInt(fdesc, optID, expectBoolean(value));
824 } catch (SocketException e) {
825
826 }
827 return;
828 case SocketOptions.TCP_NODELAY:
829 NativeUnixSocket.setSocketOptionInt(fdesc, optID, expectBoolean(value));
830 return;
831 case SocketOptions.IP_TOS:
832
833 return;
834 case SocketOptions.SO_REUSEADDR:
835
836 return;
837 default:
838 throw new SocketException("Unsupported option: " + optID);
839 }
840 } catch (final SocketException e) {
841 throw e;
842 } catch (final Exception e) {
843 throw (SocketException) new SocketException("Error while setting option").initCause(e);
844 }
845 }
846
847
848
849
850
851
852
853 protected final void shutdown() throws IOException {
854 FileDescriptor fdesc = core.validFd();
855 if (fdesc != null) {
856 NativeUnixSocket.shutdown(fdesc, SHUT_RD_WR);
857 shutdownState = 0;
858 }
859 }
860
861 @Override
862 protected final void shutdownInput() throws IOException {
863 FileDescriptor fdesc = core.validFd();
864 if (fdesc != null) {
865 NativeUnixSocket.shutdown(fdesc, SHUT_RD);
866 shutdownState |= 1 << (SHUT_RD);
867 if (shutdownState == SHUTDOWN_RD_WR) {
868 NativeUnixSocket.shutdown(fdesc, SHUT_RD_WR);
869 shutdownState = 0;
870 }
871 }
872 }
873
874 @Override
875 protected final void shutdownOutput() throws IOException {
876 FileDescriptor fdesc = core.validFd();
877 if (fdesc != null) {
878 NativeUnixSocket.shutdown(fdesc, SHUT_WR);
879 shutdownState |= 1 << (SHUT_RD_WR);
880 if (shutdownState == SHUTDOWN_RD_WR) {
881 NativeUnixSocket.shutdown(fdesc, SHUT_RD_WR);
882 shutdownState = 0;
883 }
884 }
885 }
886
887 final int getAncillaryReceiveBufferSize() {
888 return ancillaryDataSupport.getAncillaryReceiveBufferSize();
889 }
890
891 final void setAncillaryReceiveBufferSize(int size) {
892 ancillaryDataSupport.setAncillaryReceiveBufferSize(size);
893 }
894
895 final void ensureAncillaryReceiveBufferSize(int minSize) {
896 ancillaryDataSupport.ensureAncillaryReceiveBufferSize(minSize);
897 }
898
899 AncillaryDataSupport getAncillaryDataSupport() {
900 return ancillaryDataSupport;
901 }
902
903 final SocketAddress receive(ByteBuffer dst) throws IOException {
904 return core.receive(dst);
905 }
906
907 final int send(ByteBuffer src, SocketAddress target) throws IOException {
908 return core.write(src, target, 0);
909 }
910
911 final int read(ByteBuffer dst, ByteBuffer socketAddressBuffer) throws IOException {
912 return core.read(dst, socketAddressBuffer, 0);
913 }
914
915 final int write(ByteBuffer src) throws IOException {
916 return core.write(src);
917 }
918
919 @Override
920 protected final FileDescriptor getFileDescriptor() {
921 return core.fd;
922 }
923
924 final void updatePorts(int local, int remote) {
925 this.localport = local;
926 if (remote >= 0) {
927 this.port = remote;
928 }
929 }
930
931 final @Nullable A getLocalSocketAddress() {
932 return AFSocketAddress.getSocketAddress(getFileDescriptor(), false, localport, addressFamily);
933 }
934
935 final @Nullable A getRemoteSocketAddress() {
936 return AFSocketAddress.getSocketAddress(getFileDescriptor(), true, port, addressFamily);
937 }
938
939 final int getLocalPort1() {
940 return localport;
941 }
942
943 final int getRemotePort() {
944 return port;
945 }
946
947 @Override
948 protected final InetAddress getInetAddress() {
949 @Nullable
950 A rsa = getRemoteSocketAddress();
951 if (rsa == null) {
952 return InetAddress.getLoopbackAddress();
953 } else {
954 return rsa.getInetAddress();
955 }
956 }
957
958 final void createSocket(FileDescriptor fdTarget, AFSocketType type) throws IOException {
959 NativeUnixSocket.createSocket(fdTarget, addressFamily.getDomain(), type.getId());
960 }
961
962 final AFAddressFamily<A> getAddressFamily() {
963 return addressFamily;
964 }
965
966 @Override
967 protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
968 if (name instanceof AFSocketOption<?>) {
969 getCore().setOption((AFSocketOption<T>) name, value);
970 return;
971 }
972 Integer optionId = SocketOptionsMapper.resolve(name);
973 if (optionId == null) {
974 super.setOption(name, value);
975 } else {
976 setOption(optionId, value);
977 }
978 }
979
980 @SuppressWarnings("unchecked")
981 @Override
982 protected <T> T getOption(SocketOption<T> name) throws IOException {
983 if (name instanceof AFSocketOption<?>) {
984 return getCore().getOption((AFSocketOption<T>) name);
985 }
986 Integer optionId = SocketOptionsMapper.resolve(name);
987 if (optionId == null) {
988 return super.getOption(name);
989 } else {
990 return (T) getOption(optionId);
991 }
992 }
993
994 @Override
995 protected Set<SocketOption<?>> supportedOptions() {
996 return SocketOptionsMapper.SUPPORTED_SOCKET_OPTIONS;
997 }
998
999
1000
1001
1002
1003
1004
1005
1006 protected final synchronized AFSocketImplExtensions<A> getImplExtensions() {
1007 if (implExtensions == null) {
1008 implExtensions = addressFamily.initImplExtensions(ancillaryDataSupport);
1009 }
1010 return implExtensions;
1011 }
1012 }