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.lang.reflect.InvocationTargetException;
23 import java.net.SocketException;
24 import java.nio.ByteBuffer;
25 import java.util.concurrent.atomic.AtomicBoolean;
26 import java.util.concurrent.atomic.AtomicInteger;
27 import java.util.concurrent.atomic.AtomicLong;
28
29 import org.newsclub.net.unix.pool.ObjectPool.Lease;
30
31
32
33
34
35
36 class AFSocketCore extends AFCore {
37 private final AtomicInteger pendingAccepts = new AtomicInteger(0);
38 private static final int SHUT_RD_WR = 2;
39
40
41
42
43 final AtomicLong inode = new AtomicLong(-1);
44
45 AFSocketAddress socketAddress;
46
47 private final AFAddressFamily<?> af;
48 private final AtomicBoolean shutdownOnClose = new AtomicBoolean(true);
49
50 protected AFSocketCore(Object observed, FileDescriptor fd,
51 AncillaryDataSupport ancillaryDataSupport, AFAddressFamily<?> af, boolean datagramMode) {
52 super(observed, fd, ancillaryDataSupport, datagramMode);
53 this.af = af;
54 }
55
56 protected AFAddressFamily<?> addressFamily() {
57 return af;
58 }
59
60 @Override
61 @SuppressWarnings("UnsafeFinalization" )
62 protected void doClose() throws IOException {
63 if (isShutdownOnClose()) {
64 NativeUnixSocket.shutdown(fd, SHUT_RD_WR);
65 unblockAccepts();
66 }
67
68 super.doClose();
69 }
70
71 protected void unblockAccepts() {
72
73 }
74
75 AFSocketAddress receive(ByteBuffer dst, AFSupplier<Integer> socketTimeout) throws IOException {
76 try (Lease<ByteBuffer> socketAddressBufferLease = AFSocketAddress.SOCKETADDRESS_BUFFER_TL
77 .take()) {
78 ByteBuffer socketAddressBuffer = socketAddressBufferLease.get();
79
80 int read = read(dst, socketTimeout, socketAddressBuffer, 0);
81 if (read > 0) {
82 return AFSocketAddress.ofInternal(socketAddressBuffer, af);
83 } else {
84 return null;
85 }
86 }
87 }
88
89 boolean isConnected(boolean boundOk) {
90 try {
91 if (fd.valid()) {
92 switch (NativeUnixSocket.socketStatus(fd)) {
93 case NativeUnixSocket.SOCKETSTATUS_CONNECTED:
94 return true;
95 case NativeUnixSocket.SOCKETSTATUS_BOUND:
96 if (boundOk) {
97 return true;
98 }
99 break;
100 default:
101 }
102 }
103 } catch (IOException e) {
104 throw new IllegalStateException(e);
105 }
106 return false;
107 }
108
109 @SuppressWarnings({"unchecked"})
110 <T> T getOption(AFSocketOption<T> name) throws IOException {
111 Class<T> type = name.type();
112 if (Boolean.class.isAssignableFrom(type)) {
113 return (T) (Object) (NativeUnixSocket.getSocketOption(fd, name.level(), name.optionName(),
114 Integer.class) != 0);
115 } else if (NamedInteger.HasOfValue.class.isAssignableFrom(type)) {
116 @SuppressWarnings("all")
117 int v = NativeUnixSocket.getSocketOption(fd, name.level(), name.optionName(), Integer.class);
118 try {
119 return (T) type.getMethod("ofValue", int.class).invoke(null, v);
120 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
121 | NoSuchMethodException | SecurityException e) {
122 throw new IOException("Value casting problem", e);
123 }
124 } else {
125 return NativeUnixSocket.getSocketOption(fd, name.level(), name.optionName(), type);
126 }
127 }
128
129 <T> void setOption(AFSocketOption<T> name, T value) throws IOException {
130 final Object val;
131 if (value instanceof Boolean) {
132 val = (((Boolean) value) ? 1 : 0);
133 } else if (value instanceof NamedInteger) {
134 val = ((NamedInteger) value).value();
135 } else {
136 val = value;
137 }
138 int level = name.level();
139 int optionName = name.optionName();
140 NativeUnixSocket.setSocketOption(fd, level, optionName, val);
141 if (level == 271 && optionName == 135) {
142
143
144 try {
145 Thread.sleep(1);
146 } catch (InterruptedException e) {
147
148 }
149 }
150 }
151
152 protected void incPendingAccepts() throws SocketException {
153 if (pendingAccepts.incrementAndGet() >= Integer.MAX_VALUE) {
154 pendingAccepts.decrementAndGet();
155 throw new SocketException("Too many pending accepts");
156 }
157 }
158
159 protected void decPendingAccepts() {
160 pendingAccepts.decrementAndGet();
161 }
162
163 protected boolean hasPendingAccepts() {
164 return pendingAccepts.get() > 0;
165 }
166
167 boolean isShutdownOnClose() {
168 return shutdownOnClose.get();
169 }
170
171 void setShutdownOnClose(boolean enabled) {
172 this.shutdownOnClose.set(enabled);
173 }
174 }