1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.channel.unix;
17
18 import io.netty5.channel.ChannelException;
19 import io.netty5.channel.socket.DomainSocketAddress;
20 import io.netty5.channel.socket.SocketProtocolFamily;
21 import io.netty5.util.CharsetUtil;
22 import io.netty5.util.NetUtil;
23
24 import java.io.IOException;
25 import java.net.Inet6Address;
26 import java.net.InetAddress;
27 import java.net.InetSocketAddress;
28 import java.net.PortUnreachableException;
29 import java.net.ProtocolFamily;
30 import java.net.SocketAddress;
31 import java.nio.ByteBuffer;
32 import java.nio.channels.ClosedChannelException;
33 import java.util.Objects;
34
35 import static io.netty5.channel.unix.Errors.ERRNO_EAGAIN_NEGATIVE;
36 import static io.netty5.channel.unix.Errors.ERRNO_EINPROGRESS_NEGATIVE;
37 import static io.netty5.channel.unix.Errors.ERRNO_EWOULDBLOCK_NEGATIVE;
38 import static io.netty5.channel.unix.Errors.ERROR_ECONNREFUSED_NEGATIVE;
39 import static io.netty5.channel.unix.Errors.handleConnectErrno;
40 import static io.netty5.channel.unix.Errors.ioResult;
41 import static io.netty5.channel.unix.Errors.newIOException;
42 import static io.netty5.channel.unix.NativeInetAddress.address;
43 import static io.netty5.channel.unix.NativeInetAddress.ipv4MappedIpv6Address;
44
45
46
47
48
49 public class Socket extends FileDescriptor {
50
51 private static volatile boolean isIpv6Preferred;
52
53 @Deprecated
54 public static final int UDS_SUN_PATH_SIZE = 100;
55
56 private final SocketProtocolFamily protocolFamily;
57
58 protected final boolean ipv6;
59
60 public Socket(int fd, SocketProtocolFamily protocolFamily) {
61 super(fd);
62 ipv6 = isIPv6(fd);
63 this.protocolFamily = Objects.requireNonNull(protocolFamily, "protocolFamily");
64 }
65
66
67
68 private boolean useIpv6(InetAddress address) {
69 return useIpv6(this, address);
70 }
71
72
73
74
75
76 protected static boolean useIpv6(Socket socket, InetAddress address) {
77 return socket.ipv6 || address instanceof Inet6Address;
78 }
79
80 public final SocketProtocolFamily protocolFamily() {
81 return protocolFamily;
82 }
83
84 public final void shutdown() throws IOException {
85 shutdown(true, true);
86 }
87
88 public final void shutdown(boolean read, boolean write) throws IOException {
89 for (;;) {
90
91
92
93
94 final int oldState = state;
95 if (isClosed(oldState)) {
96 throw new ClosedChannelException();
97 }
98 int newState = oldState;
99 if (read && !isInputShutdown(newState)) {
100 newState = inputShutdown(newState);
101 }
102 if (write && !isOutputShutdown(newState)) {
103 newState = outputShutdown(newState);
104 }
105
106
107 if (newState == oldState) {
108 return;
109 }
110 if (casState(oldState, newState)) {
111 break;
112 }
113 }
114 int res = shutdown(fd, read, write);
115 if (res < 0) {
116 ioResult("shutdown", res);
117 }
118 }
119
120 public final boolean isShutdown() {
121 int state = this.state;
122 return isInputShutdown(state) && isOutputShutdown(state);
123 }
124
125 public final boolean isInputShutdown() {
126 return isInputShutdown(state);
127 }
128
129 public final boolean isOutputShutdown() {
130 return isOutputShutdown(state);
131 }
132
133 public final int sendTo(ByteBuffer buf, int pos, int limit, InetAddress addr, int port) throws IOException {
134 return sendTo(buf, pos, limit, addr, port, false);
135 }
136
137 public final int sendTo(ByteBuffer buf, int pos, int limit, InetAddress addr, int port, boolean fastOpen)
138 throws IOException {
139
140
141 byte[] address;
142 int scopeId;
143 if (addr instanceof Inet6Address) {
144 address = addr.getAddress();
145 scopeId = ((Inet6Address) addr).getScopeId();
146 } else {
147
148 scopeId = 0;
149 address = ipv4MappedIpv6Address(addr.getAddress());
150 }
151 int flags = fastOpen ? msgFastopen() : 0;
152 int res = sendTo(fd, useIpv6(addr), buf, pos, limit, address, scopeId, port, flags);
153 if (res >= 0) {
154 return res;
155 }
156 if (res == ERRNO_EINPROGRESS_NEGATIVE && fastOpen) {
157
158
159
160 return 0;
161 }
162 if (res == ERROR_ECONNREFUSED_NEGATIVE) {
163 throw new PortUnreachableException("sendTo failed");
164 }
165 return ioResult("sendTo", res);
166 }
167
168 public final int sendToDomainSocket(ByteBuffer buf, int pos, int limit, byte[] path) throws IOException {
169 int res = sendToDomainSocket(fd, buf, pos, limit, path);
170 if (res >= 0) {
171 return res;
172 }
173 return ioResult("sendToDomainSocket", res);
174 }
175
176 public final int sendToAddress(long memoryAddress, int pos, int limit, InetAddress addr, int port)
177 throws IOException {
178 return sendToAddress(memoryAddress, pos, limit, addr, port, false);
179 }
180
181 public final int sendToAddress(long memoryAddress, int pos, int limit, InetAddress addr, int port,
182 boolean fastOpen) throws IOException {
183
184
185 byte[] address;
186 int scopeId;
187 if (addr instanceof Inet6Address) {
188 address = addr.getAddress();
189 scopeId = ((Inet6Address) addr).getScopeId();
190 } else {
191
192 scopeId = 0;
193 address = ipv4MappedIpv6Address(addr.getAddress());
194 }
195 int flags = fastOpen ? msgFastopen() : 0;
196 int res = sendToAddress(fd, useIpv6(addr), memoryAddress, pos, limit, address, scopeId, port, flags);
197 if (res >= 0) {
198 return res;
199 }
200 if (res == ERRNO_EINPROGRESS_NEGATIVE && fastOpen) {
201
202
203
204 return 0;
205 }
206 if (res == ERROR_ECONNREFUSED_NEGATIVE) {
207 throw new PortUnreachableException("sendToAddress failed");
208 }
209 return ioResult("sendToAddress", res);
210 }
211
212 public final int sendToAddressDomainSocket(long memoryAddress, int pos, int limit, byte[] path) throws IOException {
213 int res = sendToAddressDomainSocket(fd, memoryAddress, pos, limit, path);
214 if (res >= 0) {
215 return res;
216 }
217 return ioResult("sendToAddressDomainSocket", res);
218 }
219
220 public final int sendToAddresses(long memoryAddress, int length, InetAddress addr, int port) throws IOException {
221 return sendToAddresses(memoryAddress, length, addr, port, false);
222 }
223
224 public final int sendToAddresses(long memoryAddress, int length, InetAddress addr, int port, boolean fastOpen)
225 throws IOException {
226
227
228 byte[] address;
229 int scopeId;
230 if (addr instanceof Inet6Address) {
231 address = addr.getAddress();
232 scopeId = ((Inet6Address) addr).getScopeId();
233 } else {
234
235 scopeId = 0;
236 address = ipv4MappedIpv6Address(addr.getAddress());
237 }
238 int flags = fastOpen ? msgFastopen() : 0;
239 int res = sendToAddresses(fd, useIpv6(addr), memoryAddress, length, address, scopeId, port, flags);
240 if (res >= 0) {
241 return res;
242 }
243 if (res == ERRNO_EINPROGRESS_NEGATIVE && fastOpen) {
244
245
246
247 return 0;
248 }
249 if (res == ERROR_ECONNREFUSED_NEGATIVE) {
250 throw new PortUnreachableException("sendToAddresses failed");
251 }
252 return ioResult("sendToAddresses", res);
253 }
254
255 public final int sendToAddressesDomainSocket(long memoryAddress, int length, byte[] path) throws IOException {
256 int res = sendToAddressesDomainSocket(fd, memoryAddress, length, path);
257 if (res >= 0) {
258 return res;
259 }
260 return ioResult("sendToAddressesDomainSocket", res);
261 }
262
263 public final DatagramSocketAddress recvFrom(ByteBuffer buf, int pos, int limit) throws IOException {
264 return recvFrom(fd, buf, pos, limit);
265 }
266
267 public final DatagramSocketAddress recvFromAddress(long memoryAddress, int pos, int limit) throws IOException {
268 return recvFromAddress(fd, memoryAddress, pos, limit);
269 }
270
271 public final DomainDatagramSocketAddress recvFromDomainSocket(ByteBuffer buf, int pos, int limit)
272 throws IOException {
273 return recvFromDomainSocket(fd, buf, pos, limit);
274 }
275
276 public final DomainDatagramSocketAddress recvFromAddressDomainSocket(long memoryAddress, int pos, int limit)
277 throws IOException {
278 return recvFromAddressDomainSocket(fd, memoryAddress, pos, limit);
279 }
280
281 public final int recvFd() throws IOException {
282 int res = recvFd(fd);
283 if (res > 0) {
284 return res;
285 }
286 if (res == 0) {
287 return -1;
288 }
289
290 if (res == ERRNO_EAGAIN_NEGATIVE || res == ERRNO_EWOULDBLOCK_NEGATIVE) {
291
292 return 0;
293 }
294 throw newIOException("recvFd", res);
295 }
296
297 public final int sendFd(int fdToSend) throws IOException {
298 int res = sendFd(fd, fdToSend);
299 if (res >= 0) {
300 return res;
301 }
302 if (res == ERRNO_EAGAIN_NEGATIVE || res == ERRNO_EWOULDBLOCK_NEGATIVE) {
303
304 return -1;
305 }
306 throw newIOException("sendFd", res);
307 }
308
309 public final boolean connect(SocketAddress socketAddress) throws IOException {
310 int res;
311 if (socketAddress instanceof InetSocketAddress) {
312 InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
313 InetAddress inetAddress = inetSocketAddress.getAddress();
314 NativeInetAddress address = NativeInetAddress.newInstance(inetAddress);
315 res = connect(fd, useIpv6(inetAddress), address.address, address.scopeId, inetSocketAddress.getPort());
316 } else if (socketAddress instanceof DomainSocketAddress) {
317 DomainSocketAddress unixDomainSocketAddress = (DomainSocketAddress) socketAddress;
318 res = connectDomainSocket(fd, unixDomainSocketAddress.path().getBytes(CharsetUtil.UTF_8));
319 } else {
320 throw new Error("Unexpected SocketAddress implementation " + socketAddress);
321 }
322 if (res < 0) {
323 return handleConnectErrno("connect", res);
324 }
325 return true;
326 }
327
328 public final boolean finishConnect() throws IOException {
329 int res = finishConnect(fd);
330 if (res < 0) {
331 return handleConnectErrno("finishConnect", res);
332 }
333 return true;
334 }
335
336 public final void disconnect() throws IOException {
337 int res = disconnect(fd, ipv6);
338 if (res < 0) {
339 handleConnectErrno("disconnect", res);
340 }
341 }
342
343 public final void bind(SocketAddress socketAddress) throws IOException {
344 if (socketAddress instanceof InetSocketAddress) {
345 InetSocketAddress addr = (InetSocketAddress) socketAddress;
346 InetAddress inetAddress = addr.getAddress();
347 NativeInetAddress address = NativeInetAddress.newInstance(inetAddress);
348 int res = bind(fd, useIpv6(inetAddress), address.address, address.scopeId, addr.getPort());
349 if (res < 0) {
350 throw newIOException("bind", res);
351 }
352 } else if (socketAddress instanceof DomainSocketAddress) {
353 DomainSocketAddress addr = (DomainSocketAddress) socketAddress;
354 int res = bindDomainSocket(fd, addr.path().getBytes(CharsetUtil.UTF_8));
355 if (res < 0) {
356 throw newIOException("bind", res);
357 }
358 } else {
359 throw new Error("Unexpected SocketAddress implementation " + socketAddress);
360 }
361 }
362
363 public final void listen(int backlog) throws IOException {
364 int res = listen(fd, backlog);
365 if (res < 0) {
366 throw newIOException("listen", res);
367 }
368 }
369
370 public final int accept(byte[] addr) throws IOException {
371 int res = accept(fd, addr);
372 if (res >= 0) {
373 return res;
374 }
375 if (res == ERRNO_EAGAIN_NEGATIVE || res == ERRNO_EWOULDBLOCK_NEGATIVE) {
376
377 return -1;
378 }
379 throw newIOException("accept", res);
380 }
381
382 public final InetSocketAddress remoteAddress() {
383 byte[] addr = remoteAddress(fd);
384
385
386 return addr == null ? null : address(addr, 0, addr.length);
387 }
388
389 public final InetSocketAddress localAddress() {
390 byte[] addr = localAddress(fd);
391
392
393 return addr == null ? null : address(addr, 0, addr.length);
394 }
395
396 public final int getReceiveBufferSize() throws IOException {
397 return getReceiveBufferSize(fd);
398 }
399
400 public final int getSendBufferSize() throws IOException {
401 return getSendBufferSize(fd);
402 }
403
404 public final boolean isKeepAlive() throws IOException {
405 return isKeepAlive(fd) != 0;
406 }
407
408 public final boolean isTcpNoDelay() throws IOException {
409 return isTcpNoDelay(fd) != 0;
410 }
411
412 public final boolean isReuseAddress() throws IOException {
413 return isReuseAddress(fd) != 0;
414 }
415
416 public final boolean isReusePort() throws IOException {
417 return isReusePort(fd) != 0;
418 }
419
420 public final boolean isBroadcast() throws IOException {
421 return isBroadcast(fd) != 0;
422 }
423
424 public final int getSoLinger() throws IOException {
425 return getSoLinger(fd);
426 }
427
428 public final int getSoError() throws IOException {
429 return getSoError(fd);
430 }
431
432 public final int getTrafficClass() throws IOException {
433 return getTrafficClass(fd, ipv6);
434 }
435
436 public final void setKeepAlive(boolean keepAlive) throws IOException {
437 setKeepAlive(fd, keepAlive ? 1 : 0);
438 }
439
440 public final void setReceiveBufferSize(int receiveBufferSize) throws IOException {
441 setReceiveBufferSize(fd, receiveBufferSize);
442 }
443
444 public final void setSendBufferSize(int sendBufferSize) throws IOException {
445 setSendBufferSize(fd, sendBufferSize);
446 }
447
448 public final void setTcpNoDelay(boolean tcpNoDelay) throws IOException {
449 setTcpNoDelay(fd, tcpNoDelay ? 1 : 0);
450 }
451
452 public final void setSoLinger(int soLinger) throws IOException {
453 setSoLinger(fd, soLinger);
454 }
455
456 public final void setReuseAddress(boolean reuseAddress) throws IOException {
457 setReuseAddress(fd, reuseAddress ? 1 : 0);
458 }
459
460 public final void setReusePort(boolean reusePort) throws IOException {
461 setReusePort(fd, reusePort ? 1 : 0);
462 }
463
464 public final void setBroadcast(boolean broadcast) throws IOException {
465 setBroadcast(fd, broadcast ? 1 : 0);
466 }
467
468 public final void setTrafficClass(int trafficClass) throws IOException {
469 setTrafficClass(fd, ipv6, trafficClass);
470 }
471
472 public void setIntOpt(int level, int optname, int optvalue) throws IOException {
473 setIntOpt(fd, level, optname, optvalue);
474 }
475
476 public void setRawOpt(int level, int optname, ByteBuffer optvalue) throws IOException {
477 int limit = optvalue.limit();
478 if (optvalue.isDirect()) {
479 setRawOptAddress(fd, level, optname,
480 Buffer.nativeAddressOf(optvalue) + optvalue.position(), optvalue.remaining());
481 } else if (optvalue.hasArray()) {
482 setRawOptArray(fd, level, optname,
483 optvalue.array(), optvalue.arrayOffset() + optvalue.position(), optvalue.remaining());
484 } else {
485 byte[] bytes = new byte[optvalue.remaining()];
486 optvalue.duplicate().get(bytes);
487 setRawOptArray(fd, level, optname, bytes, 0, bytes.length);
488 }
489 optvalue.position(limit);
490 }
491
492 public int getIntOpt(int level, int optname) throws IOException {
493 return getIntOpt(fd, level, optname);
494 }
495
496 public void getRawOpt(int level, int optname, ByteBuffer out) throws IOException {
497 if (out.isDirect()) {
498 getRawOptAddress(fd, level, optname, Buffer.nativeAddressOf(out) + out.position() , out.remaining());
499 } else if (out.hasArray()) {
500 getRawOptArray(fd, level, optname, out.array(), out.position() + out.arrayOffset(), out.remaining());
501 } else {
502 byte[] outArray = new byte[out.remaining()];
503 getRawOptArray(fd, level, optname, outArray, 0, outArray.length);
504 out.put(outArray);
505 }
506 out.position(out.limit());
507 }
508
509 public static boolean isIPv6Preferred() {
510 return isIpv6Preferred;
511 }
512
513 public static boolean shouldUseIpv6(ProtocolFamily family) {
514 if (family == null) {
515 return isIPv6Preferred();
516 }
517 if (family == SocketProtocolFamily.INET) {
518 return false;
519 }
520 if (family == SocketProtocolFamily.INET6) {
521 return true;
522 }
523 throw new IllegalArgumentException("ProtocolFamily not supported: " + family);
524 }
525
526 private static native boolean isIPv6Preferred0(boolean ipv4Preferred);
527
528 private static native boolean isIPv6(int fd);
529
530 @Override
531 public String toString() {
532 return "Socket{" +
533 "fd=" + fd +
534 ", family=" + protocolFamily +
535 '}';
536 }
537
538 public static Socket newSocketStream() {
539 return new Socket(newSocketStream0(), isIPv6Preferred() ?
540 SocketProtocolFamily.INET6 : SocketProtocolFamily.INET);
541 }
542
543 public static Socket newSocketDgram() {
544 return new Socket(newSocketDgram0(), isIPv6Preferred() ?
545 SocketProtocolFamily.INET6 : SocketProtocolFamily.INET);
546 }
547
548 public static Socket newSocketDomain() {
549 return new Socket(newSocketDomain0(), SocketProtocolFamily.UNIX);
550 }
551
552 public static Socket newSocketDomainDgram() {
553 return new Socket(newSocketDomainDgram0(), SocketProtocolFamily.UNIX);
554 }
555
556 public static void initialize() {
557 isIpv6Preferred = isIPv6Preferred0(NetUtil.isIpV4StackPreferred());
558 }
559
560 protected static int newSocketStream0() {
561 return newSocketStream0(isIPv6Preferred());
562 }
563
564 protected static int newSocketStream0(ProtocolFamily protocol) {
565 return newSocketStream0(shouldUseIpv6(protocol));
566 }
567
568 protected static int newSocketStream0(boolean ipv6) {
569 int res = newSocketStreamFd(ipv6);
570 if (res < 0) {
571 throw new ChannelException(newIOException("newSocketStream", res));
572 }
573 return res;
574 }
575
576 protected static int newSocketDgram0() {
577 return newSocketDgram0(isIPv6Preferred());
578 }
579
580 protected static int newSocketDgram0(ProtocolFamily family) {
581 return newSocketDgram0(shouldUseIpv6(family));
582 }
583
584 protected static int newSocketDgram0(boolean ipv6) {
585 int res = newSocketDgramFd(ipv6);
586 if (res < 0) {
587 throw new ChannelException(newIOException("newSocketDgram", res));
588 }
589 return res;
590 }
591
592 protected static int newSocketDomain0() {
593 int res = newSocketDomainFd();
594 if (res < 0) {
595 throw new ChannelException(newIOException("newSocketDomain", res));
596 }
597 return res;
598 }
599
600 protected static int newSocketDomainDgram0() {
601 int res = newSocketDomainDgramFd();
602 if (res < 0) {
603 throw new ChannelException(newIOException("newSocketDomainDgram", res));
604 }
605 return res;
606 }
607
608 private static native int shutdown(int fd, boolean read, boolean write);
609 private static native int connect(int fd, boolean ipv6, byte[] address, int scopeId, int port);
610 private static native int connectDomainSocket(int fd, byte[] path);
611 private static native int finishConnect(int fd);
612 private static native int disconnect(int fd, boolean ipv6);
613 private static native int bind(int fd, boolean ipv6, byte[] address, int scopeId, int port);
614 private static native int bindDomainSocket(int fd, byte[] path);
615 private static native int listen(int fd, int backlog);
616 private static native int accept(int fd, byte[] addr);
617
618 private static native byte[] remoteAddress(int fd);
619 private static native byte[] localAddress(int fd);
620
621 private static native int sendTo(
622 int fd, boolean ipv6, ByteBuffer buf, int pos, int limit, byte[] address, int scopeId, int port,
623 int flags);
624
625 private static native int sendToAddress(
626 int fd, boolean ipv6, long memoryAddress, int pos, int limit, byte[] address, int scopeId, int port,
627 int flags);
628
629 private static native int sendToAddresses(
630 int fd, boolean ipv6, long memoryAddress, int length, byte[] address, int scopeId, int port,
631 int flags);
632
633 private static native int sendToDomainSocket(int fd, ByteBuffer buf, int pos, int limit, byte[] path);
634 private static native int sendToAddressDomainSocket(int fd, long memoryAddress, int pos, int limit, byte[] path);
635 private static native int sendToAddressesDomainSocket(int fd, long memoryAddress, int length, byte[] path);
636
637 private static native DatagramSocketAddress recvFrom(
638 int fd, ByteBuffer buf, int pos, int limit) throws IOException;
639 private static native DatagramSocketAddress recvFromAddress(
640 int fd, long memoryAddress, int pos, int limit) throws IOException;
641 private static native DomainDatagramSocketAddress recvFromDomainSocket(
642 int fd, ByteBuffer buf, int pos, int limit) throws IOException;
643 private static native DomainDatagramSocketAddress recvFromAddressDomainSocket(
644 int fd, long memoryAddress, int pos, int limit) throws IOException;
645 private static native int recvFd(int fd);
646 private static native int sendFd(int socketFd, int fd);
647 private static native int msgFastopen();
648
649 private static native int newSocketStreamFd(boolean ipv6);
650 private static native int newSocketDgramFd(boolean ipv6);
651 private static native int newSocketDomainFd();
652 private static native int newSocketDomainDgramFd();
653
654 private static native int isReuseAddress(int fd) throws IOException;
655 private static native int isReusePort(int fd) throws IOException;
656 private static native int getReceiveBufferSize(int fd) throws IOException;
657 private static native int getSendBufferSize(int fd) throws IOException;
658 private static native int isKeepAlive(int fd) throws IOException;
659 private static native int isTcpNoDelay(int fd) throws IOException;
660 private static native int isBroadcast(int fd) throws IOException;
661 private static native int getSoLinger(int fd) throws IOException;
662 private static native int getSoError(int fd) throws IOException;
663 private static native int getTrafficClass(int fd, boolean ipv6) throws IOException;
664
665 private static native void setReuseAddress(int fd, int reuseAddress) throws IOException;
666 private static native void setReusePort(int fd, int reuseAddress) throws IOException;
667 private static native void setKeepAlive(int fd, int keepAlive) throws IOException;
668 private static native void setReceiveBufferSize(int fd, int receiveBufferSize) throws IOException;
669 private static native void setSendBufferSize(int fd, int sendBufferSize) throws IOException;
670 private static native void setTcpNoDelay(int fd, int tcpNoDelay) throws IOException;
671 private static native void setSoLinger(int fd, int soLinger) throws IOException;
672 private static native void setBroadcast(int fd, int broadcast) throws IOException;
673 private static native void setTrafficClass(int fd, boolean ipv6, int trafficClass) throws IOException;
674
675 private static native void setIntOpt(int fd, int level, int optname, int optvalue) throws IOException;
676 private static native void setRawOptArray(int fd, int level, int optname, byte[] optvalue, int offset, int length)
677 throws IOException;
678 private static native void setRawOptAddress(int fd, int level, int optname, long optvalueMemoryAddress, int length)
679 throws IOException;
680 private static native int getIntOpt(int fd, int level, int optname) throws IOException;
681 private static native void getRawOptArray(int fd, int level, int optname, byte[] out, int offset, int length)
682 throws IOException;
683 private static native void getRawOptAddress(int fd, int level, int optname, long outMemoryAddress, int length)
684 throws IOException;
685 }