1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel.unix;
17
18 import io.netty.channel.ChannelException;
19 import io.netty.util.CharsetUtil;
20 import io.netty.util.NetUtil;
21
22 import java.io.IOException;
23 import java.net.Inet6Address;
24 import java.net.InetAddress;
25 import java.net.InetSocketAddress;
26 import java.net.PortUnreachableException;
27 import java.net.SocketAddress;
28 import java.nio.ByteBuffer;
29 import java.nio.channels.ClosedChannelException;
30 import java.util.concurrent.atomic.AtomicBoolean;
31
32 import static io.netty.channel.unix.Errors.ERRNO_EAGAIN_NEGATIVE;
33 import static io.netty.channel.unix.Errors.ERROR_ECONNREFUSED_NEGATIVE;
34 import static io.netty.channel.unix.Errors.ERRNO_EINPROGRESS_NEGATIVE;
35 import static io.netty.channel.unix.Errors.ERRNO_EWOULDBLOCK_NEGATIVE;
36 import static io.netty.channel.unix.Errors.ioResult;
37 import static io.netty.channel.unix.Errors.throwConnectException;
38 import static io.netty.channel.unix.Errors.newIOException;
39 import static io.netty.channel.unix.NativeInetAddress.address;
40 import static io.netty.channel.unix.NativeInetAddress.ipv4MappedIpv6Address;
41 import static io.netty.util.internal.ThrowableUtil.unknownStackTrace;
42
43
44
45
46
47 public final class Socket extends FileDescriptor {
48 private static final ClosedChannelException SHUTDOWN_CLOSED_CHANNEL_EXCEPTION = unknownStackTrace(
49 new ClosedChannelException(), Socket.class, "shutdown(..)");
50 private static final ClosedChannelException SEND_TO_CLOSED_CHANNEL_EXCEPTION = unknownStackTrace(
51 new ClosedChannelException(), Socket.class, "sendTo(..)");
52 private static final ClosedChannelException SEND_TO_ADDRESS_CLOSED_CHANNEL_EXCEPTION =
53 unknownStackTrace(new ClosedChannelException(), Socket.class, "sendToAddress(..)");
54 private static final ClosedChannelException SEND_TO_ADDRESSES_CLOSED_CHANNEL_EXCEPTION =
55 unknownStackTrace(new ClosedChannelException(), Socket.class, "sendToAddresses(..)");
56 private static final Errors.NativeIoException SEND_TO_CONNECTION_RESET_EXCEPTION = unknownStackTrace(
57 Errors.newConnectionResetException("syscall:sendto", Errors.ERRNO_EPIPE_NEGATIVE),
58 Socket.class, "sendTo(..)");
59 private static final Errors.NativeIoException SEND_TO_ADDRESS_CONNECTION_RESET_EXCEPTION =
60 unknownStackTrace(Errors.newConnectionResetException("syscall:sendto",
61 Errors.ERRNO_EPIPE_NEGATIVE), Socket.class, "sendToAddress");
62 private static final Errors.NativeIoException CONNECTION_RESET_EXCEPTION_SENDMSG = unknownStackTrace(
63 Errors.newConnectionResetException("syscall:sendmsg",
64 Errors.ERRNO_EPIPE_NEGATIVE), Socket.class, "sendToAddresses(..)");
65 private static final Errors.NativeIoException CONNECTION_RESET_SHUTDOWN_EXCEPTION =
66 unknownStackTrace(Errors.newConnectionResetException("syscall:shutdown",
67 Errors.ERRNO_ECONNRESET_NEGATIVE), Socket.class, "shutdown");
68 private static final Errors.NativeConnectException FINISH_CONNECT_REFUSED_EXCEPTION =
69 unknownStackTrace(new Errors.NativeConnectException("syscall:getsockopt",
70 Errors.ERROR_ECONNREFUSED_NEGATIVE), Socket.class, "finishConnect(..)");
71 private static final Errors.NativeConnectException CONNECT_REFUSED_EXCEPTION =
72 unknownStackTrace(new Errors.NativeConnectException("syscall:connect",
73 Errors.ERROR_ECONNREFUSED_NEGATIVE), Socket.class, "connect(..)");
74 public Socket(int fd) {
75 super(fd);
76 }
77
78 public void shutdown() throws IOException {
79 shutdown(true, true);
80 }
81
82 public void shutdown(boolean read, boolean write) throws IOException {
83 for (;;) {
84
85
86
87
88 final int oldState = this.state;
89 if (isClosed(oldState)) {
90 throw new ClosedChannelException();
91 }
92 int newState = oldState;
93 if (read && !isInputShutdown(newState)) {
94 newState = inputShutdown(newState);
95 }
96 if (write && !isOutputShutdown(newState)) {
97 newState = outputShutdown(newState);
98 }
99
100
101 if (newState == oldState) {
102 return;
103 }
104 if (casState(oldState, newState)) {
105 break;
106 }
107 }
108 int res = shutdown(fd, read, write);
109 if (res < 0) {
110 ioResult("shutdown", res, CONNECTION_RESET_SHUTDOWN_EXCEPTION, SHUTDOWN_CLOSED_CHANNEL_EXCEPTION);
111 }
112 }
113
114 public boolean isShutdown() {
115 int state = this.state;
116 return isInputShutdown(state) && isOutputShutdown(state);
117 }
118
119 public boolean isInputShutdown() {
120 return isInputShutdown(state);
121 }
122
123 public boolean isOutputShutdown() {
124 return isOutputShutdown(state);
125 }
126
127 public int sendTo(ByteBuffer buf, int pos, int limit, InetAddress addr, int port) throws IOException {
128
129
130 byte[] address;
131 int scopeId;
132 if (addr instanceof Inet6Address) {
133 address = addr.getAddress();
134 scopeId = ((Inet6Address) addr).getScopeId();
135 } else {
136
137 scopeId = 0;
138 address = ipv4MappedIpv6Address(addr.getAddress());
139 }
140 int res = sendTo(fd, buf, pos, limit, address, scopeId, port);
141 if (res >= 0) {
142 return res;
143 }
144 if (res == ERROR_ECONNREFUSED_NEGATIVE) {
145 throw new PortUnreachableException("sendTo failed");
146 }
147 return ioResult("sendTo", res, SEND_TO_CONNECTION_RESET_EXCEPTION, SEND_TO_CLOSED_CHANNEL_EXCEPTION);
148 }
149
150 public int sendToAddress(long memoryAddress, int pos, int limit, InetAddress addr, int port)
151 throws IOException {
152
153
154 byte[] address;
155 int scopeId;
156 if (addr instanceof Inet6Address) {
157 address = addr.getAddress();
158 scopeId = ((Inet6Address) addr).getScopeId();
159 } else {
160
161 scopeId = 0;
162 address = ipv4MappedIpv6Address(addr.getAddress());
163 }
164 int res = sendToAddress(fd, memoryAddress, pos, limit, address, scopeId, port);
165 if (res >= 0) {
166 return res;
167 }
168 if (res == ERROR_ECONNREFUSED_NEGATIVE) {
169 throw new PortUnreachableException("sendToAddress failed");
170 }
171 return ioResult("sendToAddress", res,
172 SEND_TO_ADDRESS_CONNECTION_RESET_EXCEPTION, SEND_TO_ADDRESS_CLOSED_CHANNEL_EXCEPTION);
173 }
174
175 public int sendToAddresses(long memoryAddress, int length, InetAddress addr, int port) throws IOException {
176
177
178 byte[] address;
179 int scopeId;
180 if (addr instanceof Inet6Address) {
181 address = addr.getAddress();
182 scopeId = ((Inet6Address) addr).getScopeId();
183 } else {
184
185 scopeId = 0;
186 address = ipv4MappedIpv6Address(addr.getAddress());
187 }
188 int res = sendToAddresses(fd, memoryAddress, length, address, scopeId, port);
189 if (res >= 0) {
190 return res;
191 }
192
193 if (res == ERROR_ECONNREFUSED_NEGATIVE) {
194 throw new PortUnreachableException("sendToAddresses failed");
195 }
196 return ioResult("sendToAddresses", res,
197 CONNECTION_RESET_EXCEPTION_SENDMSG, SEND_TO_ADDRESSES_CLOSED_CHANNEL_EXCEPTION);
198 }
199
200 public DatagramSocketAddress recvFrom(ByteBuffer buf, int pos, int limit) throws IOException {
201 return recvFrom(fd, buf, pos, limit);
202 }
203
204 public DatagramSocketAddress recvFromAddress(long memoryAddress, int pos, int limit) throws IOException {
205 return recvFromAddress(fd, memoryAddress, pos, limit);
206 }
207
208 public boolean connect(SocketAddress socketAddress) throws IOException {
209 int res;
210 if (socketAddress instanceof InetSocketAddress) {
211 InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
212 NativeInetAddress address = NativeInetAddress.newInstance(inetSocketAddress.getAddress());
213 res = connect(fd, address.address, address.scopeId, inetSocketAddress.getPort());
214 } else if (socketAddress instanceof DomainSocketAddress) {
215 DomainSocketAddress unixDomainSocketAddress = (DomainSocketAddress) socketAddress;
216 res = connectDomainSocket(fd, unixDomainSocketAddress.path().getBytes(CharsetUtil.UTF_8));
217 } else {
218 throw new Error("Unexpected SocketAddress implementation " + socketAddress);
219 }
220 if (res < 0) {
221 if (res == ERRNO_EINPROGRESS_NEGATIVE) {
222
223 return false;
224 }
225 throwConnectException("connect", CONNECT_REFUSED_EXCEPTION, res);
226 }
227 return true;
228 }
229
230 public boolean finishConnect() throws IOException {
231 int res = finishConnect(fd);
232 if (res < 0) {
233 if (res == ERRNO_EINPROGRESS_NEGATIVE) {
234
235 return false;
236 }
237 throwConnectException("finishConnect", FINISH_CONNECT_REFUSED_EXCEPTION, res);
238 }
239 return true;
240 }
241
242 public void disconnect() throws IOException {
243 int res = disconnect(fd);
244 if (res < 0) {
245 throwConnectException("disconnect", FINISH_CONNECT_REFUSED_EXCEPTION, res);
246 }
247 }
248
249 public void bind(SocketAddress socketAddress) throws IOException {
250 if (socketAddress instanceof InetSocketAddress) {
251 InetSocketAddress addr = (InetSocketAddress) socketAddress;
252 NativeInetAddress address = NativeInetAddress.newInstance(addr.getAddress());
253 int res = bind(fd, address.address, address.scopeId, addr.getPort());
254 if (res < 0) {
255 throw newIOException("bind", res);
256 }
257 } else if (socketAddress instanceof DomainSocketAddress) {
258 DomainSocketAddress addr = (DomainSocketAddress) socketAddress;
259 int res = bindDomainSocket(fd, addr.path().getBytes(CharsetUtil.UTF_8));
260 if (res < 0) {
261 throw newIOException("bind", res);
262 }
263 } else {
264 throw new Error("Unexpected SocketAddress implementation " + socketAddress);
265 }
266 }
267
268 public void listen(int backlog) throws IOException {
269 int res = listen(fd, backlog);
270 if (res < 0) {
271 throw newIOException("listen", res);
272 }
273 }
274
275 public int accept(byte[] addr) throws IOException {
276 int res = accept(fd, addr);
277 if (res >= 0) {
278 return res;
279 }
280 if (res == ERRNO_EAGAIN_NEGATIVE || res == ERRNO_EWOULDBLOCK_NEGATIVE) {
281
282 return -1;
283 }
284 throw newIOException("accept", res);
285 }
286
287 public InetSocketAddress remoteAddress() {
288 byte[] addr = remoteAddress(fd);
289
290
291 if (addr == null) {
292 return null;
293 }
294 return address(addr, 0, addr.length);
295 }
296
297 public InetSocketAddress localAddress() {
298 byte[] addr = localAddress(fd);
299
300
301 if (addr == null) {
302 return null;
303 }
304 return address(addr, 0, addr.length);
305 }
306
307 public int getReceiveBufferSize() throws IOException {
308 return getReceiveBufferSize(fd);
309 }
310
311 public int getSendBufferSize() throws IOException {
312 return getSendBufferSize(fd);
313 }
314
315 public boolean isKeepAlive() throws IOException {
316 return isKeepAlive(fd) != 0;
317 }
318
319 public boolean isTcpNoDelay() throws IOException {
320 return isTcpNoDelay(fd) != 0;
321 }
322
323 public boolean isTcpCork() throws IOException {
324 return isTcpCork(fd) != 0;
325 }
326
327 public int getSoLinger() throws IOException {
328 return getSoLinger(fd);
329 }
330
331 public int getTcpDeferAccept() throws IOException {
332 return getTcpDeferAccept(fd);
333 }
334
335 public boolean isTcpQuickAck() throws IOException {
336 return isTcpQuickAck(fd) != 0;
337 }
338
339 public int getSoError() throws IOException {
340 return getSoError(fd);
341 }
342
343 public PeerCredentials getPeerCredentials() throws IOException {
344 return getPeerCredentials(fd);
345 }
346
347 public void setKeepAlive(boolean keepAlive) throws IOException {
348 setKeepAlive(fd, keepAlive ? 1 : 0);
349 }
350
351 public void setReceiveBufferSize(int receiveBufferSize) throws IOException {
352 setReceiveBufferSize(fd, receiveBufferSize);
353 }
354
355 public void setSendBufferSize(int sendBufferSize) throws IOException {
356 setSendBufferSize(fd, sendBufferSize);
357 }
358
359 public void setTcpNoDelay(boolean tcpNoDelay) throws IOException {
360 setTcpNoDelay(fd, tcpNoDelay ? 1 : 0);
361 }
362
363 public void setTcpCork(boolean tcpCork) throws IOException {
364 setTcpCork(fd, tcpCork ? 1 : 0);
365 }
366
367 public void setSoLinger(int soLinger) throws IOException {
368 setSoLinger(fd, soLinger);
369 }
370
371 public void setTcpDeferAccept(int deferAccept) throws IOException {
372 setTcpDeferAccept(fd, deferAccept);
373 }
374
375 public void setTcpQuickAck(boolean quickAck) throws IOException {
376 setTcpQuickAck(fd, quickAck ? 1 : 0);
377 }
378
379 @Override
380 public String toString() {
381 return "Socket{" +
382 "fd=" + fd +
383 '}';
384 }
385
386 private static final AtomicBoolean INITIALIZED = new AtomicBoolean();
387
388 public static void initialize() {
389 if (INITIALIZED.compareAndSet(false, true)) {
390 initialize(NetUtil.isIpV4StackPreferred());
391 }
392 }
393
394 public static Socket newSocketStream() {
395 int res = newSocketStreamFd();
396 if (res < 0) {
397 throw new ChannelException(newIOException("newSocketStream", res));
398 }
399 return new Socket(res);
400 }
401
402 public static Socket newSocketDgram() {
403 int res = newSocketDgramFd();
404 if (res < 0) {
405 throw new ChannelException(newIOException("newSocketDgram", res));
406 }
407 return new Socket(res);
408 }
409
410 public static Socket newSocketDomain() {
411 int res = newSocketDomainFd();
412 if (res < 0) {
413 throw new ChannelException(newIOException("newSocketDomain", res));
414 }
415 return new Socket(res);
416 }
417
418 private static native int shutdown(int fd, boolean read, boolean write);
419 private static native int connect(int fd, byte[] address, int scopeId, int port);
420 private static native int connectDomainSocket(int fd, byte[] path);
421 private static native int finishConnect(int fd);
422 private static native int disconnect(int fd);
423 private static native int bind(int fd, byte[] address, int scopeId, int port);
424 private static native int bindDomainSocket(int fd, byte[] path);
425 private static native int listen(int fd, int backlog);
426 private static native int accept(int fd, byte[] addr);
427
428 private static native byte[] remoteAddress(int fd);
429 private static native byte[] localAddress(int fd);
430
431 private static native int sendTo(
432 int fd, ByteBuffer buf, int pos, int limit, byte[] address, int scopeId, int port);
433 private static native int sendToAddress(
434 int fd, long memoryAddress, int pos, int limit, byte[] address, int scopeId, int port);
435 private static native int sendToAddresses(
436 int fd, long memoryAddress, int length, byte[] address, int scopeId, int port);
437
438 private static native DatagramSocketAddress recvFrom(
439 int fd, ByteBuffer buf, int pos, int limit) throws IOException;
440 private static native DatagramSocketAddress recvFromAddress(
441 int fd, long memoryAddress, int pos, int limit) throws IOException;
442
443 private static native int newSocketStreamFd();
444 private static native int newSocketDgramFd();
445 private static native int newSocketDomainFd();
446
447 private static native int getReceiveBufferSize(int fd) throws IOException;
448 private static native int getSendBufferSize(int fd) throws IOException;
449 private static native int isKeepAlive(int fd) throws IOException;
450 private static native int isTcpNoDelay(int fd) throws IOException;
451 private static native int isTcpCork(int fd) throws IOException;
452 private static native int getSoLinger(int fd) throws IOException;
453 private static native int getSoError(int fd) throws IOException;
454 private static native int getTcpDeferAccept(int fd) throws IOException;
455 private static native int isTcpQuickAck(int fd) throws IOException;
456 private static native PeerCredentials getPeerCredentials(int fd) throws IOException;
457
458 private static native void setKeepAlive(int fd, int keepAlive) throws IOException;
459 private static native void setReceiveBufferSize(int fd, int receiveBufferSize) throws IOException;
460 private static native void setSendBufferSize(int fd, int sendBufferSize) throws IOException;
461 private static native void setTcpNoDelay(int fd, int tcpNoDelay) throws IOException;
462 private static native void setTcpCork(int fd, int tcpCork) throws IOException;
463 private static native void setSoLinger(int fd, int soLinger) throws IOException;
464 private static native void setTcpDeferAccept(int fd, int deferAccept) throws IOException;
465 private static native void setTcpQuickAck(int fd, int quickAck) throws IOException;
466 private static native void initialize(boolean ipv4Preferred);
467 }