1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel.uring;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.ByteBufAllocator;
20 import io.netty.buffer.ByteBufHolder;
21 import io.netty.buffer.ByteBufUtil;
22 import io.netty.buffer.Unpooled;
23 import io.netty.channel.AbstractChannel;
24 import io.netty.channel.Channel;
25 import io.netty.channel.ChannelConfig;
26 import io.netty.channel.ChannelFuture;
27 import io.netty.channel.ChannelFutureListener;
28 import io.netty.channel.ChannelOption;
29 import io.netty.channel.ChannelOutboundBuffer;
30 import io.netty.channel.ChannelPromise;
31 import io.netty.channel.ConnectTimeoutException;
32 import io.netty.channel.EventLoop;
33 import io.netty.channel.IoEvent;
34 import io.netty.channel.IoEventLoop;
35 import io.netty.channel.IoRegistration;
36 import io.netty.channel.RecvByteBufAllocator;
37 import io.netty.channel.ServerChannel;
38 import io.netty.channel.socket.ChannelInputShutdownEvent;
39 import io.netty.channel.socket.ChannelInputShutdownReadComplete;
40 import io.netty.channel.socket.SocketChannelConfig;
41 import io.netty.channel.unix.Buffer;
42 import io.netty.channel.unix.DomainSocketAddress;
43 import io.netty.channel.unix.Errors;
44 import io.netty.channel.unix.FileDescriptor;
45 import io.netty.channel.unix.IovArray;
46 import io.netty.channel.unix.UnixChannel;
47 import io.netty.channel.unix.UnixChannelUtil;
48 import io.netty.util.ReferenceCountUtil;
49 import io.netty.util.concurrent.PromiseNotifier;
50 import io.netty.util.internal.CleanableDirectBuffer;
51 import io.netty.util.internal.StringUtil;
52 import io.netty.util.internal.logging.InternalLogger;
53 import io.netty.util.internal.logging.InternalLoggerFactory;
54
55 import java.io.IOException;
56 import java.net.InetSocketAddress;
57 import java.net.SocketAddress;
58 import java.nio.ByteBuffer;
59 import java.nio.channels.AlreadyConnectedException;
60 import java.nio.channels.ClosedChannelException;
61 import java.nio.channels.ConnectionPendingException;
62 import java.nio.channels.NotYetConnectedException;
63 import java.nio.channels.UnresolvedAddressException;
64 import java.util.concurrent.ScheduledFuture;
65 import java.util.concurrent.TimeUnit;
66
67 import static io.netty.channel.unix.Errors.ERRNO_EINPROGRESS_NEGATIVE;
68 import static io.netty.channel.unix.Errors.ERROR_EALREADY_NEGATIVE;
69 import static io.netty.channel.unix.UnixChannelUtil.computeRemoteAddr;
70 import static io.netty.util.internal.ObjectUtil.checkNotNull;
71 import static io.netty.util.internal.StringUtil.className;
72
73
74 abstract class AbstractIoUringChannel extends AbstractChannel implements UnixChannel {
75 private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractIoUringChannel.class);
76 final LinuxSocket socket;
77 protected volatile boolean active;
78
79
80 private static final int POLL_IN_SCHEDULED = 1;
81 private static final int POLL_OUT_SCHEDULED = 1 << 2;
82 private static final int POLL_RDHUP_SCHEDULED = 1 << 3;
83 private static final int WRITE_SCHEDULED = 1 << 4;
84 private static final int READ_SCHEDULED = 1 << 5;
85 private static final int CONNECT_SCHEDULED = 1 << 6;
86
87 private short opsId = Short.MIN_VALUE;
88
89 private long pollInId;
90 private long pollOutId;
91 private long pollRdhupId;
92 private long connectId;
93
94
95 private byte ioState;
96
97
98
99
100 private short numOutstandingWrites;
101
102 private short numOutstandingReads;
103
104 private boolean readPending;
105 private boolean inReadComplete;
106 private boolean socketHasMoreData;
107
108 private static final class DelayedClose {
109 private final ChannelPromise promise;
110 private final Throwable cause;
111 private final ClosedChannelException closeCause;
112
113 DelayedClose(ChannelPromise promise, Throwable cause, ClosedChannelException closeCause) {
114 this.promise = promise;
115 this.cause = cause;
116 this.closeCause = closeCause;
117 }
118 }
119 private DelayedClose delayedClose;
120 private boolean inputClosedSeenErrorOnRead;
121
122
123
124
125 private ChannelPromise connectPromise;
126 private ScheduledFuture<?> connectTimeoutFuture;
127 private SocketAddress requestedRemoteAddress;
128 private CleanableDirectBuffer cleanable;
129 private ByteBuffer remoteAddressMemory;
130 private MsgHdrMemoryArray msgHdrMemoryArray;
131
132 private IoRegistration registration;
133
134 private volatile SocketAddress local;
135 private volatile SocketAddress remote;
136
137 AbstractIoUringChannel(final Channel parent, LinuxSocket socket, boolean active) {
138 super(parent);
139 this.socket = checkNotNull(socket, "fd");
140
141 if (active) {
142
143
144 this.active = true;
145 this.local = socket.localAddress();
146 this.remote = socket.remoteAddress();
147 }
148
149 logger.trace("Create {} Socket: {}", this instanceof ServerChannel ? "Server" : "Channel", socket.intValue());
150 }
151
152 AbstractIoUringChannel(Channel parent, LinuxSocket fd, SocketAddress remote) {
153 super(parent);
154 this.socket = checkNotNull(fd, "fd");
155 this.active = true;
156
157
158
159 this.remote = remote;
160 this.local = fd.localAddress();
161 }
162
163
164 final void autoReadCleared() {
165 if (!isRegistered()) {
166 return;
167 }
168 IoRegistration registration = this.registration;
169 if (registration == null || !registration.isValid()) {
170 return;
171 }
172 if (eventLoop().inEventLoop()) {
173 clearRead();
174 } else {
175 eventLoop().execute(this::clearRead);
176 }
177 }
178
179 private void clearRead() {
180 assert eventLoop().inEventLoop();
181 readPending = false;
182 IoRegistration registration = this.registration;
183 if (registration == null || !registration.isValid()) {
184 return;
185 }
186
187 cancelOutstandingReads(registration(), numOutstandingReads);
188 }
189
190
191
192
193
194
195 protected final short nextOpsId() {
196 short id = opsId++;
197
198
199 if (id == 0) {
200 id = opsId++;
201 }
202 return id;
203 }
204
205 public final boolean isOpen() {
206 return socket.isOpen();
207 }
208
209 @Override
210 public boolean isActive() {
211 return active;
212 }
213
214 @Override
215 public final FileDescriptor fd() {
216 return socket;
217 }
218
219 private AbstractUringUnsafe ioUringUnsafe() {
220 return (AbstractUringUnsafe) unsafe();
221 }
222
223 @Override
224 protected boolean isCompatible(final EventLoop loop) {
225 return loop instanceof IoEventLoop && ((IoEventLoop) loop).isCompatible(AbstractUringUnsafe.class);
226 }
227
228 protected final ByteBuf newDirectBuffer(ByteBuf buf) {
229 return newDirectBuffer(buf, buf);
230 }
231
232 protected boolean allowMultiShotPollIn() {
233 return IoUring.isPollAddMultishotEnabled();
234 }
235
236 protected final ByteBuf newDirectBuffer(Object holder, ByteBuf buf) {
237 final int readableBytes = buf.readableBytes();
238 if (readableBytes == 0) {
239 ReferenceCountUtil.release(holder);
240 return Unpooled.EMPTY_BUFFER;
241 }
242
243 final ByteBufAllocator alloc = alloc();
244 if (alloc.isDirectBufferPooled()) {
245 return newDirectBuffer0(holder, buf, alloc, readableBytes);
246 }
247
248 final ByteBuf directBuf = ByteBufUtil.threadLocalDirectBuffer();
249 if (directBuf == null) {
250 return newDirectBuffer0(holder, buf, alloc, readableBytes);
251 }
252
253 directBuf.writeBytes(buf, buf.readerIndex(), readableBytes);
254 ReferenceCountUtil.safeRelease(holder);
255 return directBuf;
256 }
257
258 private static ByteBuf newDirectBuffer0(Object holder, ByteBuf buf, ByteBufAllocator alloc, int capacity) {
259 final ByteBuf directBuf = alloc.directBuffer(capacity);
260 directBuf.writeBytes(buf, buf.readerIndex(), capacity);
261 ReferenceCountUtil.safeRelease(holder);
262 return directBuf;
263 }
264
265
266
267
268
269
270
271 protected abstract void cancelOutstandingReads(IoRegistration registration, int numOutstandingReads);
272
273
274
275
276
277
278
279 protected abstract void cancelOutstandingWrites(IoRegistration registration, int numOutstandingWrites);
280
281 @Override
282 protected void doDisconnect() throws Exception {
283 }
284
285 private void freeRemoteAddressMemory() {
286 if (remoteAddressMemory != null) {
287 cleanable.clean();
288 cleanable = null;
289 remoteAddressMemory = null;
290 }
291 }
292
293 private void freeMsgHdrArray() {
294 if (msgHdrMemoryArray != null) {
295 msgHdrMemoryArray.release();
296 msgHdrMemoryArray = null;
297 }
298 }
299
300 @Override
301 protected void doClose() throws Exception {
302 active = false;
303
304 if (registration != null) {
305 if (socket.markClosed()) {
306 int fd = fd().intValue();
307 IoUringIoOps ops = IoUringIoOps.newClose(fd, (byte) 0, nextOpsId());
308 registration.submit(ops);
309 }
310 } else {
311
312 socket.close();
313 ioUringUnsafe().unregistered();
314 }
315 }
316
317 @Override
318 protected final void doBeginRead() {
319 if (inputClosedSeenErrorOnRead) {
320
321 return;
322 }
323 if (readPending) {
324
325 return;
326 }
327 readPending = true;
328 if (inReadComplete || !isActive()) {
329
330
331
332 return;
333 }
334 doBeginReadNow();
335 }
336
337 private void doBeginReadNow() {
338 if (inputClosedSeenErrorOnRead) {
339
340 return;
341 }
342 if (!isPollInFirst() ||
343
344
345 socketHasMoreData) {
346
347 ioUringUnsafe().scheduleFirstReadIfNeeded();
348 } else if ((ioState & POLL_IN_SCHEDULED) == 0) {
349 ioUringUnsafe().schedulePollIn();
350 }
351 }
352
353 @Override
354 protected void doWrite(ChannelOutboundBuffer in) {
355 scheduleWriteIfNeeded(in, true);
356 }
357
358 protected void scheduleWriteIfNeeded(ChannelOutboundBuffer in, boolean submitAndRunNow) {
359 if ((ioState & WRITE_SCHEDULED) != 0) {
360 return;
361 }
362 if (scheduleWrite(in) > 0) {
363 ioState |= WRITE_SCHEDULED;
364 if (submitAndRunNow && !isWritable()) {
365 submitAndRunNow();
366 }
367 }
368 }
369
370 protected void submitAndRunNow() {
371
372 }
373
374 private int scheduleWrite(ChannelOutboundBuffer in) {
375 if (delayedClose != null || numOutstandingWrites == Short.MAX_VALUE) {
376 return 0;
377 }
378 if (in == null) {
379 return 0;
380 }
381
382 int msgCount = in.size();
383 if (msgCount == 0) {
384 return 0;
385 }
386 Object msg = in.current();
387
388 if (msgCount > 1 && in.current() instanceof ByteBuf) {
389 numOutstandingWrites = (short) ioUringUnsafe().scheduleWriteMultiple(in);
390 } else if (msg instanceof ByteBuf && ((ByteBuf) msg).nioBufferCount() > 1 ||
391 (msg instanceof ByteBufHolder && ((ByteBufHolder) msg).content().nioBufferCount() > 1)) {
392
393 numOutstandingWrites = (short) ioUringUnsafe().scheduleWriteMultiple(in);
394 } else {
395 numOutstandingWrites = (short) ioUringUnsafe().scheduleWriteSingle(msg);
396 }
397
398 assert numOutstandingWrites > 0;
399 return numOutstandingWrites;
400 }
401
402 protected final IoRegistration registration() {
403 assert registration != null;
404 return registration;
405 }
406
407 private void schedulePollOut() {
408 pollOutId = schedulePollAdd(POLL_OUT_SCHEDULED, Native.POLLOUT, false);
409 }
410
411 final void schedulePollRdHup() {
412 pollRdhupId = schedulePollAdd(POLL_RDHUP_SCHEDULED, Native.POLLRDHUP, false);
413 }
414
415 protected abstract boolean isStreamSocket();
416
417 private long schedulePollAdd(int ioMask, int mask, boolean multishot) {
418 assert (ioState & ioMask) == 0;
419 int fd = fd().intValue();
420 IoRegistration registration = registration();
421 IoUringIoOps ops = IoUringIoOps.newPollAdd(
422 fd, (byte) 0, mask, multishot ? Native.IORING_POLL_ADD_MULTI : 0, nextOpsId());
423 long id = registration.submit(ops);
424 if (id != 0) {
425 ioState |= (byte) ioMask;
426 }
427 return id;
428 }
429
430 final void resetCachedAddresses() {
431 local = socket.localAddress();
432 remote = socket.remoteAddress();
433 }
434
435 protected abstract class AbstractUringUnsafe extends AbstractUnsafe implements IoUringIoHandle {
436 private IoUringRecvByteAllocatorHandle allocHandle;
437 private boolean closed;
438 private boolean socketIsEmpty;
439 private ChannelPromise deregisterPromise;
440
441
442
443
444
445 protected abstract int scheduleWriteMultiple(ChannelOutboundBuffer in);
446
447
448
449
450
451 protected abstract int scheduleWriteSingle(Object msg);
452
453 @Override
454 public final void handle(IoRegistration registration, IoEvent ioEvent) {
455 IoUringIoEvent event = (IoUringIoEvent) ioEvent;
456 byte op = event.opcode();
457 int res = event.res();
458 int flags = event.flags();
459 short data = (short) event.userData();
460 switch (op) {
461 case Native.IORING_OP_RECV:
462 case Native.IORING_OP_ACCEPT:
463 case Native.IORING_OP_RECVMSG:
464 case Native.IORING_OP_READ:
465 readComplete(op, res, flags, data);
466 break;
467 case Native.IORING_OP_WRITEV:
468 case Native.IORING_OP_SEND:
469 case Native.IORING_OP_SENDMSG:
470 case Native.IORING_OP_WRITE:
471 case Native.IORING_OP_SPLICE:
472 case Native.IORING_OP_SEND_ZC:
473 case Native.IORING_OP_SENDMSG_ZC:
474 writeComplete(op, res, flags, data);
475 break;
476 case Native.IORING_OP_POLL_ADD:
477 pollAddComplete(res, flags, data);
478 break;
479 case Native.IORING_OP_ASYNC_CANCEL:
480 cancelComplete0(op, res, flags, data);
481 break;
482 case Native.IORING_OP_CONNECT:
483 connectComplete(op, res, flags, data);
484
485
486 freeMsgHdrArray();
487 freeRemoteAddressMemory();
488 break;
489 case Native.IORING_OP_CLOSE:
490 if (res != Native.ERRNO_ECANCELED_NEGATIVE) {
491 if (delayedClose != null) {
492 delayedClose.promise.setSuccess();
493 }
494 closed = true;
495 }
496 break;
497 default:
498 break;
499 }
500
501
502
503 handleDelayedClosed();
504
505 if (ioState == 0 && (closed || !isRegistered())) {
506
507 registration.cancel();
508 }
509 }
510
511 @Override
512 public void unregistered() {
513 freeMsgHdrArray();
514 freeRemoteAddressMemory();
515
516
517 if (deregisterPromise != null) {
518 ChannelPromise promise = deregisterPromise;
519 deregisterPromise = null;
520 promise.setSuccess();
521 }
522 }
523
524 private void handleDelayedClosed() {
525 if (delayedClose != null && canCloseNow()) {
526 closeNow();
527 }
528 }
529
530 private void pollAddComplete(int res, int flags, short data) {
531 if ((res & Native.POLLOUT) != 0) {
532 pollOut(res);
533 }
534 if ((res & Native.POLLIN) != 0) {
535 pollIn(res, flags, data);
536 }
537 if ((res & Native.POLLRDHUP) != 0) {
538 pollRdHup(res);
539 }
540 }
541
542 @Override
543 public final void close() throws Exception {
544 close(voidPromise());
545 }
546
547 @Override
548 protected void close(ChannelPromise promise, Throwable cause, ClosedChannelException closeCause) {
549 if (closeFuture().isDone()) {
550
551 safeSetSuccess(promise);
552 return;
553 }
554 if (delayedClose == null) {
555
556
557
558 delayedClose = new DelayedClose(promise.isVoid() ? newPromise() : promise, cause, closeCause);
559 } else {
560 delayedClose.promise.addListener(new PromiseNotifier<>(false, promise));
561 return;
562 }
563
564 boolean cancelConnect = false;
565 try {
566 ChannelPromise connectPromise = AbstractIoUringChannel.this.connectPromise;
567 if (connectPromise != null) {
568
569 connectPromise.tryFailure(new ClosedChannelException());
570 AbstractIoUringChannel.this.connectPromise = null;
571 cancelConnect = true;
572 }
573
574 cancelConnectTimeoutFuture();
575 } finally {
576
577
578 cancelOps(cancelConnect);
579 }
580
581 if (canCloseNow()) {
582
583 closeNow();
584 }
585 }
586
587 private boolean cancelOps(boolean cancelConnect) {
588 if (registration == null || !registration.isValid()) {
589 return false;
590 }
591 boolean cancelled = false;
592 byte flags = (byte) 0;
593 if ((ioState & POLL_RDHUP_SCHEDULED) != 0 && pollRdhupId != 0) {
594 long id = registration.submit(
595 IoUringIoOps.newAsyncCancel(flags, pollRdhupId, Native.IORING_OP_POLL_ADD));
596 assert id != 0;
597 pollRdhupId = 0;
598 cancelled = true;
599 }
600 if ((ioState & POLL_IN_SCHEDULED) != 0 && pollInId != 0) {
601 long id = registration.submit(
602 IoUringIoOps.newAsyncCancel(flags, pollInId, Native.IORING_OP_POLL_ADD));
603 assert id != 0;
604 pollInId = 0;
605 cancelled = true;
606 }
607 if ((ioState & POLL_OUT_SCHEDULED) != 0 && pollOutId != 0) {
608 long id = registration.submit(
609 IoUringIoOps.newAsyncCancel(flags, pollOutId, Native.IORING_OP_POLL_ADD));
610 assert id != 0;
611 pollOutId = 0;
612 cancelled = true;
613 }
614 if (cancelConnect && connectId != 0) {
615
616 long id = registration.submit(IoUringIoOps.newAsyncCancel(flags, connectId, Native.IORING_OP_CONNECT));
617 assert id != 0;
618 connectId = 0;
619 cancelled = true;
620 }
621 if (numOutstandingReads != 0 || numOutstandingWrites != 0) {
622 cancelled = true;
623 }
624 cancelOutstandingReads(registration, numOutstandingReads);
625 cancelOutstandingWrites(registration, numOutstandingWrites);
626 return cancelled;
627 }
628
629 private boolean canCloseNow() {
630
631
632 return canCloseNow0() && (ioState & (WRITE_SCHEDULED | READ_SCHEDULED)) == 0;
633 }
634
635 protected boolean canCloseNow0() {
636 return true;
637 }
638
639 private void closeNow() {
640 super.close(newPromise(), delayedClose.cause, delayedClose.closeCause);
641 }
642
643 @Override
644 protected final void flush0() {
645
646
647
648 if ((ioState & POLL_OUT_SCHEDULED) == 0) {
649 super.flush0();
650 }
651 }
652
653 private void fulfillConnectPromise(ChannelPromise promise, Throwable cause) {
654 if (promise == null) {
655
656 return;
657 }
658
659
660 promise.tryFailure(cause);
661 closeIfClosed();
662 }
663
664 private void fulfillConnectPromise(ChannelPromise promise, boolean wasActive) {
665 if (promise == null) {
666
667 return;
668 }
669 active = true;
670
671 if (local == null) {
672 local = socket.localAddress();
673 }
674 computeRemote();
675
676 if (isStreamSocket()) {
677
678 schedulePollRdHup();
679 }
680
681
682
683 boolean active = isActive();
684
685
686 boolean promiseSet = promise.trySuccess();
687
688
689
690 if (!wasActive && active) {
691 pipeline().fireChannelActive();
692 }
693
694
695 if (!promiseSet) {
696 close(voidPromise());
697 }
698 }
699
700 @Override
701 public final IoUringRecvByteAllocatorHandle recvBufAllocHandle() {
702 if (allocHandle == null) {
703 allocHandle = new IoUringRecvByteAllocatorHandle(
704 (RecvByteBufAllocator.ExtendedHandle) super.recvBufAllocHandle());
705 }
706 return allocHandle;
707 }
708
709 final void shutdownInput(boolean allDataRead) {
710 logger.trace("shutdownInput Fd: {}", fd().intValue());
711 if (!socket.isInputShutdown()) {
712 if (isAllowHalfClosure(config())) {
713 try {
714 socket.shutdown(true, false);
715 } catch (IOException ignored) {
716
717
718 fireEventAndClose(ChannelInputShutdownEvent.INSTANCE);
719 return;
720 } catch (NotYetConnectedException ignore) {
721
722
723 }
724 pipeline().fireUserEventTriggered(ChannelInputShutdownEvent.INSTANCE);
725 } else {
726
727 inputClosedSeenErrorOnRead = true;
728 close(voidPromise());
729 return;
730 }
731 }
732 if (allDataRead && !inputClosedSeenErrorOnRead) {
733 inputClosedSeenErrorOnRead = true;
734 pipeline().fireUserEventTriggered(ChannelInputShutdownReadComplete.INSTANCE);
735 }
736 }
737
738 private void fireEventAndClose(Object evt) {
739 pipeline().fireUserEventTriggered(evt);
740 close(voidPromise());
741 }
742
743 final void schedulePollIn() {
744 assert (ioState & POLL_IN_SCHEDULED) == 0;
745 if (!isActive() || shouldBreakIoUringInReady(config())) {
746 return;
747 }
748 pollInId = schedulePollAdd(POLL_IN_SCHEDULED, Native.POLLIN, allowMultiShotPollIn());
749 }
750
751 protected final boolean isReadMultishot() {
752 return numOutstandingReads == -1;
753 }
754
755 private void readComplete(byte op, int res, int flags, short data) {
756 assert numOutstandingReads > 0 || numOutstandingReads == -1 : numOutstandingReads;
757
758 boolean multishot = isReadMultishot();
759 boolean rearm = (flags & Native.IORING_CQE_F_MORE) == 0;
760 boolean pending = readPending;
761 if (multishot) {
762 if (rearm) {
763
764 ioState &= ~READ_SCHEDULED;
765 }
766
767
768 readPending = false;
769 } else if (--numOutstandingReads == 0) {
770
771 readPending = false;
772 ioState &= ~READ_SCHEDULED;
773 }
774 inReadComplete = true;
775 try {
776 socketIsEmpty = socketIsEmpty(flags);
777 socketHasMoreData = IoUring.isCqeFSockNonEmptySupported() &&
778 (flags & Native.IORING_CQE_F_SOCK_NONEMPTY) != 0;
779 readComplete0(op, res, flags, data, numOutstandingReads);
780 } finally {
781 try {
782
783 if (recvBufAllocHandle().isReadComplete()) {
784
785 recvBufAllocHandle().reset(config());
786
787
788 if (!multishot) {
789 if (readPending) {
790
791
792 doBeginReadNow();
793 }
794 } else {
795
796
797
798 if (res == Native.ERRNO_ECANCELED_NEGATIVE) {
799
800
801
802
803 if (pending) {
804 readPending = true;
805 doBeginReadNow();
806 }
807 } else if (rearm) {
808
809 doBeginReadNow();
810 } else if (!readPending) {
811
812
813 cancelOutstandingReads(registration, numOutstandingReads);
814 }
815 }
816 } else if (res == Native.ERRNO_ECANCELED_NEGATIVE) {
817
818
819
820
821 if (pending) {
822 readPending = true;
823 doBeginReadNow();
824 }
825 } else if (multishot && rearm) {
826
827 doBeginReadNow();
828 }
829 } finally {
830 inReadComplete = false;
831 socketIsEmpty = false;
832 }
833 }
834 }
835
836
837
838
839 protected abstract void readComplete0(byte op, int res, int flags, short data, int outstandingCompletes);
840
841
842
843
844 private void pollRdHup(int res) {
845 ioState &= ~POLL_RDHUP_SCHEDULED;
846 pollRdhupId = 0;
847 if (res == Native.ERRNO_ECANCELED_NEGATIVE) {
848 return;
849 }
850
851
852 recvBufAllocHandle().rdHupReceived();
853
854 if (isActive()) {
855 scheduleFirstReadIfNeeded();
856 } else {
857
858 shutdownInput(false);
859 }
860 }
861
862
863
864
865 private void pollIn(int res, int flags, short data) {
866
867 boolean rearm = (flags & Native.IORING_CQE_F_MORE) == 0;
868 if (rearm) {
869 ioState &= ~POLL_IN_SCHEDULED;
870 pollInId = 0;
871 }
872 if (res == Native.ERRNO_ECANCELED_NEGATIVE) {
873 return;
874 }
875 if (!readPending) {
876
877
878 socketHasMoreData = true;
879 return;
880 }
881 scheduleFirstReadIfNeeded();
882 }
883
884 private void scheduleFirstReadIfNeeded() {
885 if ((ioState & READ_SCHEDULED) == 0) {
886 scheduleFirstRead();
887 }
888 }
889
890 private void scheduleFirstRead() {
891
892 final ChannelConfig config = config();
893 final IoUringRecvByteAllocatorHandle allocHandle = recvBufAllocHandle();
894 allocHandle.reset(config);
895 scheduleRead(true);
896 }
897
898 protected final void scheduleRead(boolean first) {
899
900 if (delayedClose == null && fd().isOpen() && (ioState & READ_SCHEDULED) == 0) {
901 numOutstandingReads = (short) scheduleRead0(first, socketIsEmpty);
902 if (numOutstandingReads > 0 || numOutstandingReads == -1) {
903 ioState |= READ_SCHEDULED;
904 }
905 }
906 }
907
908
909
910
911
912
913
914
915
916
917
918 protected abstract int scheduleRead0(boolean first, boolean socketIsEmpty);
919
920
921
922
923
924
925 private void pollOut(int res) {
926 ioState &= ~POLL_OUT_SCHEDULED;
927 pollOutId = 0;
928 if (res == Native.ERRNO_ECANCELED_NEGATIVE) {
929 return;
930 }
931
932 if (connectPromise != null) {
933
934
935
936 assert eventLoop().inEventLoop();
937
938 boolean connectStillInProgress = false;
939 try {
940 boolean wasActive = isActive();
941 if (!socket.finishConnect()) {
942 connectStillInProgress = true;
943 return;
944 }
945 fulfillConnectPromise(connectPromise, wasActive);
946 } catch (Throwable t) {
947 fulfillConnectPromise(connectPromise, annotateConnectException(t, requestedRemoteAddress));
948 } finally {
949 if (!connectStillInProgress) {
950
951
952
953 cancelConnectTimeoutFuture();
954 connectPromise = null;
955 } else {
956
957 schedulePollOut();
958 }
959 }
960 } else if (!socket.isOutputShutdown()) {
961
962 super.flush0();
963 }
964 }
965
966
967
968
969
970
971
972
973
974 private void writeComplete(byte op, int res, int flags, short data) {
975 if ((ioState & CONNECT_SCHEDULED) != 0) {
976
977
978 freeMsgHdrArray();
979 if (res > 0) {
980
981 outboundBuffer().removeBytes(res);
982
983
984 connectComplete(op, 0, flags, data);
985 } else if (res == ERRNO_EINPROGRESS_NEGATIVE || res == 0) {
986
987
988
989
990 submitConnect((InetSocketAddress) requestedRemoteAddress);
991 } else {
992
993 connectComplete(op, res, flags, data);
994 }
995 return;
996 }
997
998 if ((flags & Native.IORING_CQE_F_NOTIF) == 0) {
999 assert numOutstandingWrites > 0;
1000 --numOutstandingWrites;
1001 }
1002
1003 boolean writtenAll = writeComplete0(op, res, flags, data, numOutstandingWrites);
1004 if (!writtenAll && (ioState & POLL_OUT_SCHEDULED) == 0) {
1005
1006
1007 schedulePollOut();
1008 }
1009
1010
1011
1012 if (numOutstandingWrites == 0) {
1013 ioState &= ~WRITE_SCHEDULED;
1014
1015
1016 if (writtenAll && (ioState & POLL_OUT_SCHEDULED) == 0) {
1017 scheduleWriteIfNeeded(unsafe().outboundBuffer(), false);
1018 }
1019 }
1020 }
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030 abstract boolean writeComplete0(byte op, int res, int flags, short data, int outstanding);
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040 void cancelComplete0(byte op, int res, int flags, short data) {
1041
1042 }
1043
1044
1045
1046
1047
1048
1049
1050
1051 void connectComplete(byte op, int res, int flags, short data) {
1052 ioState &= ~CONNECT_SCHEDULED;
1053 freeRemoteAddressMemory();
1054
1055 if (res == ERRNO_EINPROGRESS_NEGATIVE || res == ERROR_EALREADY_NEGATIVE) {
1056
1057 schedulePollOut();
1058 } else {
1059 try {
1060 if (res == 0) {
1061 fulfillConnectPromise(connectPromise, active);
1062 if (readPending) {
1063 doBeginReadNow();
1064 }
1065 } else {
1066 try {
1067 Errors.throwConnectException("io_uring connect", res);
1068 } catch (Throwable cause) {
1069 fulfillConnectPromise(connectPromise, cause);
1070 }
1071 }
1072 } finally {
1073
1074
1075
1076 cancelConnectTimeoutFuture();
1077 connectPromise = null;
1078 }
1079 }
1080 }
1081
1082 @Override
1083 public void connect(
1084 final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
1085
1086
1087 if (promise.isDone() || !ensureOpen(promise)) {
1088 return;
1089 }
1090
1091 if (delayedClose != null) {
1092 promise.tryFailure(annotateConnectException(new ClosedChannelException(), remoteAddress));
1093 return;
1094 }
1095 try {
1096 if (connectPromise != null) {
1097 throw new ConnectionPendingException();
1098 }
1099 if (localAddress instanceof InetSocketAddress) {
1100 checkResolvable((InetSocketAddress) localAddress);
1101 }
1102
1103 if (remoteAddress instanceof InetSocketAddress) {
1104 checkResolvable((InetSocketAddress) remoteAddress);
1105 }
1106
1107 if (remote != null) {
1108
1109
1110
1111 throw new AlreadyConnectedException();
1112 }
1113
1114 if (localAddress != null) {
1115 socket.bind(localAddress);
1116 }
1117
1118 if (remoteAddress instanceof InetSocketAddress) {
1119 InetSocketAddress inetSocketAddress = (InetSocketAddress) remoteAddress;
1120 ByteBuf initialData = null;
1121 if (IoUring.isTcpFastOpenClientSideAvailable() &&
1122 config().getOption(ChannelOption.TCP_FASTOPEN_CONNECT) == Boolean.TRUE) {
1123 ChannelOutboundBuffer outbound = unsafe().outboundBuffer();
1124 outbound.addFlush();
1125 Object curr;
1126 if ((curr = outbound.current()) instanceof ByteBuf) {
1127 initialData = (ByteBuf) curr;
1128 }
1129 }
1130 if (initialData != null) {
1131 msgHdrMemoryArray = new MsgHdrMemoryArray((short) 1);
1132 MsgHdrMemory hdr = msgHdrMemoryArray.hdr(0);
1133 fillTFOInitData(hdr, inetSocketAddress, initialData);
1134
1135 int fd = fd().intValue();
1136 IoRegistration registration = registration();
1137 IoUringIoOps ops = IoUringIoOps.newSendmsg(fd, (byte) 0, Native.MSG_FASTOPEN,
1138 hdr.address(), hdr.idx());
1139 connectId = registration.submit(ops);
1140 if (connectId == 0) {
1141
1142 freeMsgHdrArray();
1143 }
1144 } else {
1145 submitConnect(inetSocketAddress);
1146 }
1147 } else if (remoteAddress instanceof DomainSocketAddress) {
1148 DomainSocketAddress unixDomainSocketAddress = (DomainSocketAddress) remoteAddress;
1149 submitConnect(unixDomainSocketAddress);
1150 } else {
1151 throw new Error("Unexpected SocketAddress implementation " + className(remoteAddress));
1152 }
1153
1154 if (connectId != 0) {
1155 ioState |= CONNECT_SCHEDULED;
1156 }
1157 } catch (Throwable t) {
1158 closeIfClosed();
1159 promise.tryFailure(annotateConnectException(t, remoteAddress));
1160 return;
1161 }
1162 connectPromise = promise;
1163 requestedRemoteAddress = remoteAddress;
1164
1165 int connectTimeoutMillis = config().getConnectTimeoutMillis();
1166 if (connectTimeoutMillis > 0) {
1167 connectTimeoutFuture = eventLoop().schedule(new Runnable() {
1168 @Override
1169 public void run() {
1170 ChannelPromise connectPromise = AbstractIoUringChannel.this.connectPromise;
1171 if (connectPromise != null && !connectPromise.isDone() &&
1172 connectPromise.tryFailure(new ConnectTimeoutException(
1173 "connection timed out: " + remoteAddress))) {
1174 close(voidPromise());
1175 }
1176 }
1177 }, connectTimeoutMillis, TimeUnit.MILLISECONDS);
1178 }
1179
1180 promise.addListener(new ChannelFutureListener() {
1181 @Override
1182 public void operationComplete(ChannelFuture future) {
1183
1184
1185 if (future.isCancelled()) {
1186 cancelConnectTimeoutFuture();
1187 connectPromise = null;
1188 close(voidPromise());
1189 }
1190 }
1191 });
1192 }
1193
1194 private void fillTFOInitData(MsgHdrMemory hdr, InetSocketAddress inetSocketAddress,
1195 ByteBuf initialData) throws Exception {
1196 if (initialData.hasMemoryAddress()) {
1197 hdr.set(socket, inetSocketAddress,
1198 initialData.memoryAddress() + initialData.readerIndex(),
1199 initialData.readableBytes(), (short) 0);
1200 } else {
1201
1202
1203 IoUringIoHandler handler = registration().attachment();
1204 IovArray iovArray = handler.iovArray();
1205 int iovOffset = iovArray.count();
1206 iovArray.processMessage(initialData);
1207 long iovArrayAddress = iovArray.memoryAddress(iovOffset);
1208 int iovArrayLength = iovArray.count() - iovOffset;
1209 hdr.setWithIovArrayAddress(socket, inetSocketAddress, iovArrayAddress, iovArrayLength, (short) 0);
1210 }
1211 }
1212
1213 @Override
1214 public final void deregister(ChannelPromise promise) {
1215 if (deregisterPromise != null) {
1216
1217 PromiseNotifier.cascade(deregisterPromise, promise);
1218 } else if (!isRegistered()) {
1219 promise.setSuccess();
1220 } else {
1221
1222
1223 deregisterPromise = promise;
1224 super.deregister(newPromise().addListener(f -> {
1225 if (!f.isSuccess()) {
1226 this.deregisterPromise = null;
1227 promise.setFailure(f.cause());
1228 }
1229 }));
1230 }
1231 }
1232 }
1233
1234 private void submitConnect(InetSocketAddress inetSocketAddress) {
1235 cleanable = Buffer.allocateDirectBufferWithNativeOrder(Native.SIZEOF_SOCKADDR_STORAGE);
1236 remoteAddressMemory = cleanable.buffer();
1237
1238 SockaddrIn.set(socket.isIpv6(), remoteAddressMemory, inetSocketAddress);
1239
1240 int fd = fd().intValue();
1241 IoRegistration registration = registration();
1242 IoUringIoOps ops = IoUringIoOps.newConnect(
1243 fd, (byte) 0, Buffer.memoryAddress(remoteAddressMemory), nextOpsId());
1244 connectId = registration.submit(ops);
1245 if (connectId == 0) {
1246
1247 freeRemoteAddressMemory();
1248 }
1249 }
1250
1251 private void submitConnect(DomainSocketAddress unixDomainSocketAddress) {
1252 cleanable = Buffer.allocateDirectBufferWithNativeOrder(Native.SIZEOF_SOCKADDR_UN);
1253 remoteAddressMemory = cleanable.buffer();
1254 int addrLen = SockaddrIn.setUds(remoteAddressMemory, unixDomainSocketAddress);
1255 int fd = fd().intValue();
1256 IoRegistration registration = registration();
1257 long addr = Buffer.memoryAddress(remoteAddressMemory);
1258 IoUringIoOps ops = IoUringIoOps.newConnect(fd, (byte) 0, addr, addrLen, nextOpsId());
1259 connectId = registration.submit(ops);
1260 if (connectId == 0) {
1261
1262 freeRemoteAddressMemory();
1263 }
1264 }
1265
1266 @Override
1267 protected Object filterOutboundMessage(Object msg) {
1268 if (msg instanceof ByteBuf) {
1269 ByteBuf buf = (ByteBuf) msg;
1270 return UnixChannelUtil.isBufferCopyNeededForWrite(buf)? newDirectBuffer(buf) : buf;
1271 }
1272 throw new UnsupportedOperationException("unsupported message type: " + StringUtil.simpleClassName(msg));
1273 }
1274
1275 @Override
1276 protected void doRegister(ChannelPromise promise) {
1277 IoEventLoop eventLoop = (IoEventLoop) eventLoop();
1278 eventLoop.register(ioUringUnsafe()).addListener(f -> {
1279 if (f.isSuccess()) {
1280 registration = (IoRegistration) f.getNow();
1281 promise.setSuccess();
1282 } else {
1283 promise.setFailure(f.cause());
1284 }
1285 });
1286 }
1287
1288 @Override
1289 protected final void doDeregister() {
1290
1291 if (!ioUringUnsafe().cancelOps(connectPromise != null)) {
1292
1293
1294 if (registration != null) {
1295 registration.cancel();
1296 }
1297 }
1298 }
1299
1300 @Override
1301 protected void doBind(final SocketAddress local) throws Exception {
1302 if (local instanceof InetSocketAddress) {
1303 checkResolvable((InetSocketAddress) local);
1304 }
1305 socket.bind(local);
1306 this.local = socket.localAddress();
1307 }
1308
1309 protected static void checkResolvable(InetSocketAddress addr) {
1310 if (addr.isUnresolved()) {
1311 throw new UnresolvedAddressException();
1312 }
1313 }
1314
1315 @Override
1316 protected final SocketAddress localAddress0() {
1317 return local;
1318 }
1319
1320 @Override
1321 protected final SocketAddress remoteAddress0() {
1322 return remote;
1323 }
1324
1325 private static boolean isAllowHalfClosure(ChannelConfig config) {
1326 return config instanceof SocketChannelConfig &&
1327 ((SocketChannelConfig) config).isAllowHalfClosure();
1328 }
1329
1330 private void cancelConnectTimeoutFuture() {
1331 if (connectTimeoutFuture != null) {
1332 connectTimeoutFuture.cancel(false);
1333 connectTimeoutFuture = null;
1334 }
1335 }
1336
1337 private void computeRemote() {
1338 if (requestedRemoteAddress instanceof InetSocketAddress) {
1339 remote = computeRemoteAddr((InetSocketAddress) requestedRemoteAddress, socket.remoteAddress());
1340 }
1341 }
1342
1343 private boolean shouldBreakIoUringInReady(ChannelConfig config) {
1344 return socket.isInputShutdown() && (inputClosedSeenErrorOnRead || !isAllowHalfClosure(config));
1345 }
1346
1347
1348
1349
1350
1351
1352
1353 protected abstract boolean socketIsEmpty(int flags);
1354
1355 abstract boolean isPollInFirst();
1356 }