1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.quic;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.buffer.ByteBufAllocator;
20 import io.netty.buffer.Unpooled;
21 import io.netty.channel.Channel;
22 import io.netty.channel.ChannelFuture;
23 import io.netty.channel.ChannelId;
24 import io.netty.channel.ChannelMetadata;
25 import io.netty.channel.ChannelOutboundBuffer;
26 import io.netty.channel.ChannelPipeline;
27 import io.netty.channel.ChannelPromise;
28 import io.netty.channel.DefaultChannelId;
29 import io.netty.channel.DefaultChannelPipeline;
30 import io.netty.channel.EventLoop;
31 import io.netty.channel.PendingWriteQueue;
32 import io.netty.channel.RecvByteBufAllocator;
33 import io.netty.channel.VoidChannelPromise;
34 import io.netty.channel.socket.ChannelInputShutdownEvent;
35 import io.netty.channel.socket.ChannelInputShutdownReadComplete;
36 import io.netty.channel.socket.ChannelOutputShutdownException;
37 import io.netty.util.DefaultAttributeMap;
38 import io.netty.util.ReferenceCountUtil;
39 import io.netty.util.concurrent.PromiseNotifier;
40 import io.netty.util.internal.StringUtil;
41 import io.netty.util.internal.logging.InternalLogger;
42 import io.netty.util.internal.logging.InternalLoggerFactory;
43 import org.jetbrains.annotations.Nullable;
44
45 import java.net.SocketAddress;
46 import java.nio.channels.ClosedChannelException;
47 import java.util.concurrent.RejectedExecutionException;
48
49
50
51
52 final class QuicheQuicStreamChannel extends DefaultAttributeMap implements QuicStreamChannel {
53 private static final ChannelMetadata METADATA = new ChannelMetadata(false, 16);
54 private static final InternalLogger LOGGER = InternalLoggerFactory.getInstance(QuicheQuicStreamChannel.class);
55 private final QuicheQuicChannel parent;
56 private final ChannelId id;
57 private final ChannelPipeline pipeline;
58 private final QuicStreamChannelUnsafe unsafe;
59 private final ChannelPromise closePromise;
60 private final PendingWriteQueue queue;
61
62 private final QuicStreamChannelConfig config;
63 private final QuicStreamAddress address;
64
65 private boolean readable;
66 private boolean readPending;
67 private boolean inRecv;
68 private boolean inWriteQueued;
69 private boolean finReceived;
70 private boolean finSent;
71
72 private volatile boolean registered;
73 private volatile boolean writable = true;
74 private volatile boolean active = true;
75 private volatile boolean inputShutdown;
76 private volatile boolean outputShutdown;
77 private volatile QuicStreamPriority priority;
78 private volatile long capacity;
79
80 QuicheQuicStreamChannel(QuicheQuicChannel parent, long streamId) {
81 this.parent = parent;
82 this.id = DefaultChannelId.newInstance();
83 unsafe = new QuicStreamChannelUnsafe();
84 this.pipeline = new DefaultChannelPipeline(this) {
85
86 };
87 config = new QuicheQuicStreamChannelConfig(this);
88 this.address = new QuicStreamAddress(streamId);
89 this.closePromise = newPromise();
90 queue = new PendingWriteQueue(this);
91
92
93 if (parent.streamType(streamId) == QuicStreamType.UNIDIRECTIONAL && parent.isStreamLocalCreated(streamId)) {
94 inputShutdown = true;
95 }
96 }
97
98 @Override
99 public QuicStreamAddress localAddress() {
100 return address;
101 }
102
103 @Override
104 public QuicStreamAddress remoteAddress() {
105 return address;
106 }
107
108 @Override
109 public boolean isLocalCreated() {
110 return parent().isStreamLocalCreated(streamId());
111 }
112
113 @Override
114 public QuicStreamType type() {
115 return parent().streamType(streamId());
116 }
117
118 @Override
119 public long streamId() {
120 return address.streamId();
121 }
122
123 @Override
124 public QuicStreamPriority priority() {
125 return priority;
126 }
127
128 @Override
129 public ChannelFuture updatePriority(QuicStreamPriority priority, ChannelPromise promise) {
130 if (eventLoop().inEventLoop()) {
131 updatePriority0(priority, promise);
132 } else {
133 eventLoop().execute(() -> updatePriority0(priority, promise));
134 }
135 return promise;
136 }
137
138 private void updatePriority0(QuicStreamPriority priority, ChannelPromise promise) {
139 assert eventLoop().inEventLoop();
140 if (!promise.setUncancellable()) {
141 return;
142 }
143 try {
144 parent().streamPriority(streamId(), (byte) priority.urgency(), priority.isIncremental());
145 } catch (Throwable cause) {
146 promise.setFailure(cause);
147 return;
148 }
149 this.priority = priority;
150 promise.setSuccess();
151 }
152
153 @Override
154 public boolean isInputShutdown() {
155 return inputShutdown;
156 }
157
158 @Override
159 public ChannelFuture shutdownOutput(ChannelPromise promise) {
160 if (eventLoop().inEventLoop()) {
161 shutdownOutput0(promise);
162 } else {
163 eventLoop().execute(() -> shutdownOutput0(promise));
164 }
165 return promise;
166 }
167
168 private void shutdownOutput0(ChannelPromise promise) {
169 assert eventLoop().inEventLoop();
170 if (!promise.setUncancellable()) {
171 return;
172 }
173 outputShutdown = true;
174 unsafe.writeWithoutCheckChannelState(QuicStreamFrame.EMPTY_FIN, promise);
175 unsafe.flush();
176 }
177
178 @Override
179 public ChannelFuture shutdownInput(int error, ChannelPromise promise) {
180 if (eventLoop().inEventLoop()) {
181 shutdownInput0(error, promise);
182 } else {
183 eventLoop().execute(() -> shutdownInput0(error, promise));
184 }
185 return promise;
186 }
187
188 @Override
189 public ChannelFuture shutdownOutput(int error, ChannelPromise promise) {
190 if (eventLoop().inEventLoop()) {
191 shutdownOutput0(error, promise);
192 } else {
193 eventLoop().execute(() -> shutdownOutput0(error, promise));
194 }
195 return promise;
196 }
197
198 @Override
199 public QuicheQuicChannel parent() {
200 return parent;
201 }
202
203 private void shutdownInput0(int err, ChannelPromise channelPromise) {
204 assert eventLoop().inEventLoop();
205 if (!channelPromise.setUncancellable()) {
206 return;
207 }
208 inputShutdown = true;
209 parent().streamShutdown(streamId(), true, false, err, channelPromise);
210 closeIfDone();
211 }
212
213 @Override
214 public boolean isOutputShutdown() {
215 return outputShutdown;
216 }
217
218 private void shutdownOutput0(int error, ChannelPromise channelPromise) {
219 assert eventLoop().inEventLoop();
220 if (!channelPromise.setUncancellable()) {
221 return;
222 }
223 parent().streamShutdown(streamId(), false, true, error, channelPromise);
224 outputShutdown = true;
225 closeIfDone();
226 }
227
228 @Override
229 public boolean isShutdown() {
230 return outputShutdown && inputShutdown;
231 }
232
233 @Override
234 public ChannelFuture shutdown(ChannelPromise channelPromise) {
235 if (eventLoop().inEventLoop()) {
236 shutdown0(channelPromise);
237 } else {
238 eventLoop().execute(() -> shutdown0(channelPromise));
239 }
240 return channelPromise;
241 }
242
243 private void shutdown0(ChannelPromise promise) {
244 assert eventLoop().inEventLoop();
245 if (!promise.setUncancellable()) {
246 return;
247 }
248 inputShutdown = true;
249 outputShutdown = true;
250 unsafe.writeWithoutCheckChannelState(QuicStreamFrame.EMPTY_FIN, unsafe.voidPromise());
251 unsafe.flush();
252 parent().streamShutdown(streamId(), true, false, 0, promise);
253 closeIfDone();
254 }
255
256 @Override
257 public ChannelFuture shutdown(int error, ChannelPromise promise) {
258 if (eventLoop().inEventLoop()) {
259 shutdown0(error, promise);
260 } else {
261 eventLoop().execute(() -> shutdown0(error, promise));
262 }
263 return promise;
264 }
265
266 private void shutdown0(int error, ChannelPromise channelPromise) {
267 assert eventLoop().inEventLoop();
268 if (!channelPromise.setUncancellable()) {
269 return;
270 }
271 inputShutdown = true;
272 outputShutdown = true;
273 parent().streamShutdown(streamId(), true, true, error, channelPromise);
274 closeIfDone();
275 }
276
277 private void sendFinIfNeeded() throws Exception {
278 if (!finSent) {
279 finSent = true;
280 parent().streamSendFin(streamId());
281 }
282 }
283
284 private void closeIfDone() {
285 if (finSent && (finReceived || type() == QuicStreamType.UNIDIRECTIONAL && isLocalCreated())) {
286 unsafe().close(unsafe().voidPromise());
287 }
288 }
289
290 private void removeStreamFromParent() {
291 if (!active && finReceived) {
292 parent().streamClosed(streamId());
293 inputShutdown = true;
294 outputShutdown = true;
295 }
296 }
297
298 @Override
299 public QuicStreamChannel flush() {
300 pipeline.flush();
301 return this;
302 }
303
304 @Override
305 public QuicStreamChannel read() {
306 pipeline.read();
307 return this;
308 }
309
310 @Override
311 public QuicStreamChannelConfig config() {
312 return config;
313 }
314
315 @Override
316 public boolean isOpen() {
317 return active;
318 }
319
320 @Override
321 public boolean isActive() {
322 return isOpen();
323 }
324
325 @Override
326 public ChannelMetadata metadata() {
327 return METADATA;
328 }
329
330 @Override
331 public ChannelId id() {
332 return id;
333 }
334
335 @Override
336 public EventLoop eventLoop() {
337 return parent.eventLoop();
338 }
339
340 @Override
341 public boolean isRegistered() {
342 return registered;
343 }
344
345 @Override
346 public ChannelFuture closeFuture() {
347 return closePromise;
348 }
349
350 @Override
351 public boolean isWritable() {
352 return writable;
353 }
354
355 @Override
356 public long bytesBeforeUnwritable() {
357
358 return Math.max(capacity, 0);
359 }
360
361 @Override
362 public long bytesBeforeWritable() {
363 if (writable) {
364 return 0;
365 }
366
367 return 8;
368 }
369
370 @Override
371 public QuicStreamChannelUnsafe unsafe() {
372 return unsafe;
373 }
374
375 @Override
376 public ChannelPipeline pipeline() {
377 return pipeline;
378 }
379
380 @Override
381 public ByteBufAllocator alloc() {
382 return config.getAllocator();
383 }
384
385 @Override
386 public int compareTo(Channel o) {
387 return id.compareTo(o.id());
388 }
389
390
391
392
393 @Override
394 public int hashCode() {
395 return id.hashCode();
396 }
397
398
399
400
401
402 @Override
403 public boolean equals(Object o) {
404 return this == o;
405 }
406
407 @Override
408 public String toString() {
409 return "[id: 0x" + id.asShortText() + ", " + address + "]";
410 }
411
412
413
414
415 boolean writable(long capacity) {
416 assert eventLoop().inEventLoop();
417 if (capacity < 0) {
418
419 if (capacity != Quiche.QUICHE_ERR_DONE) {
420 if (!queue.isEmpty()) {
421 if (capacity == Quiche.QUICHE_ERR_STREAM_STOPPED) {
422 queue.removeAndFailAll(new ChannelOutputShutdownException("STOP_SENDING frame received"));
423
424 return false;
425 } else {
426 queue.removeAndFailAll(Quiche.convertToException((int) capacity));
427 }
428 } else if (capacity == Quiche.QUICHE_ERR_STREAM_STOPPED) {
429
430 return false;
431 }
432
433 finSent = true;
434 unsafe().close(unsafe().voidPromise());
435 }
436 return false;
437 }
438 this.capacity = capacity;
439 boolean mayNeedWrite = unsafe().writeQueued();
440
441 updateWritabilityIfNeeded(this.capacity > 0);
442 return mayNeedWrite;
443 }
444
445 private void updateWritabilityIfNeeded(boolean newWritable) {
446 if (writable != newWritable) {
447 writable = newWritable;
448 pipeline.fireChannelWritabilityChanged();
449 }
450 }
451
452
453
454
455 void readable() {
456 assert eventLoop().inEventLoop();
457
458
459 readable = true;
460 if (readPending || !active) {
461 unsafe().recv();
462 }
463 }
464
465 final class QuicStreamChannelUnsafe implements Unsafe {
466
467 @SuppressWarnings("deprecation")
468 private RecvByteBufAllocator.Handle recvHandle;
469
470 private final ChannelPromise voidPromise = new VoidChannelPromise(
471 QuicheQuicStreamChannel.this, false);
472 @Override
473 public void connect(SocketAddress remote, SocketAddress local, ChannelPromise promise) {
474 assert eventLoop().inEventLoop();
475 promise.setFailure(new UnsupportedOperationException());
476 }
477
478 @SuppressWarnings("deprecation")
479 @Override
480 public RecvByteBufAllocator.Handle recvBufAllocHandle() {
481 if (recvHandle == null) {
482 recvHandle = config.getRecvByteBufAllocator().newHandle();
483 }
484 return recvHandle;
485 }
486
487 @Override
488 public SocketAddress localAddress() {
489 return address;
490 }
491
492 @Override
493 public SocketAddress remoteAddress() {
494 return address;
495 }
496
497 @Override
498 public void register(EventLoop eventLoop, ChannelPromise promise) {
499 assert eventLoop.inEventLoop();
500 if (!promise.setUncancellable()) {
501 return;
502 }
503 if (registered) {
504 promise.setFailure(new IllegalStateException());
505 return;
506 }
507 if (eventLoop != parent.eventLoop()) {
508 promise.setFailure(new IllegalArgumentException());
509 return;
510 }
511 registered = true;
512 promise.setSuccess();
513 pipeline.fireChannelRegistered();
514 pipeline.fireChannelActive();
515 }
516
517 @Override
518 public void bind(SocketAddress localAddress, ChannelPromise promise) {
519 assert eventLoop().inEventLoop();
520 if (!promise.setUncancellable()) {
521 return;
522 }
523 promise.setFailure(new UnsupportedOperationException());
524 }
525
526 @Override
527 public void disconnect(ChannelPromise promise) {
528 assert eventLoop().inEventLoop();
529 close(promise);
530 }
531
532 @Override
533 public void close(ChannelPromise promise) {
534 close(null, promise);
535 }
536
537 void close(@Nullable ClosedChannelException writeFailCause, ChannelPromise promise) {
538 assert eventLoop().inEventLoop();
539 if (!promise.setUncancellable()) {
540 return;
541 }
542 if (!active || closePromise.isDone()) {
543 if (promise.isVoid()) {
544 return;
545 }
546 closePromise.addListener(new PromiseNotifier<>(promise));
547 return;
548 }
549 active = false;
550 try {
551
552 sendFinIfNeeded();
553 } catch (Exception ignore) {
554
555 } finally {
556 if (!queue.isEmpty()) {
557
558 if (writeFailCause == null) {
559 writeFailCause = new ClosedChannelException();
560 }
561 queue.removeAndFailAll(writeFailCause);
562 }
563
564 promise.trySuccess();
565 closePromise.trySuccess();
566 if (type() == QuicStreamType.UNIDIRECTIONAL && isLocalCreated()) {
567 inputShutdown = true;
568 outputShutdown = true;
569
570
571 parent().streamClosed(streamId());
572 } else {
573 removeStreamFromParent();
574 }
575 }
576 if (inWriteQueued) {
577 invokeLater(() -> deregister(voidPromise(), true));
578 } else {
579 deregister(voidPromise(), true);
580 }
581
582
583 if (readable && !inRecv) {
584
585 recv();
586
587
588
589
590
591
592
593
594 parent().connectionSendAndFlush();
595 }
596 }
597
598 private void deregister(final ChannelPromise promise, final boolean fireChannelInactive) {
599 assert eventLoop().inEventLoop();
600 if (!promise.setUncancellable()) {
601 return;
602 }
603
604 if (!registered) {
605 promise.trySuccess();
606 return;
607 }
608
609
610
611
612
613
614
615
616
617
618 invokeLater(() -> {
619 if (fireChannelInactive) {
620 pipeline.fireChannelInactive();
621 }
622
623
624
625
626 if (registered) {
627 registered = false;
628 pipeline.fireChannelUnregistered();
629 }
630 promise.setSuccess();
631 });
632 }
633
634 private void invokeLater(Runnable task) {
635 try {
636
637
638
639
640
641
642
643
644
645
646
647 eventLoop().execute(task);
648 } catch (RejectedExecutionException e) {
649 LOGGER.warn("Can't invoke task later as EventLoop rejected it", e);
650 }
651 }
652
653 @Override
654 public void closeForcibly() {
655 assert eventLoop().inEventLoop();
656 close(unsafe().voidPromise());
657 }
658
659 @Override
660 public void deregister(ChannelPromise promise) {
661 assert eventLoop().inEventLoop();
662 deregister(promise, false);
663 }
664
665 @Override
666 public void beginRead() {
667 assert eventLoop().inEventLoop();
668 readPending = true;
669 if (readable) {
670 unsafe().recv();
671
672
673
674
675
676
677 parent().connectionSendAndFlush();
678 }
679 }
680
681 private void closeIfNeeded(boolean wasFinSent) {
682
683
684
685
686 if (!wasFinSent && QuicheQuicStreamChannel.this.finSent
687 && (type() == QuicStreamType.UNIDIRECTIONAL || finReceived)) {
688
689 close(voidPromise());
690 }
691 }
692
693 boolean writeQueued() {
694 assert eventLoop().inEventLoop();
695 boolean wasFinSent = QuicheQuicStreamChannel.this.finSent;
696 inWriteQueued = true;
697 try {
698 if (queue.isEmpty()) {
699 return false;
700 }
701 boolean written = false;
702 for (;;) {
703 Object msg = queue.current();
704 if (msg == null) {
705 break;
706 }
707 try {
708 int res = write0(msg);
709 if (res == 1) {
710 queue.remove().setSuccess();
711 written = true;
712 } else if (res == 0 || res == Quiche.QUICHE_ERR_DONE) {
713 break;
714 } else if (res == Quiche.QUICHE_ERR_STREAM_STOPPED) {
715
716
717
718 queue.removeAndFailAll(
719 new ChannelOutputShutdownException("STOP_SENDING frame received"));
720 break;
721 } else {
722 queue.remove().setFailure(Quiche.convertToException(res));
723 }
724 } catch (Exception e) {
725 queue.remove().setFailure(e);
726 }
727 }
728 if (written) {
729 updateWritabilityIfNeeded(capacity > 0);
730 }
731 return written;
732 } finally {
733 closeIfNeeded(wasFinSent);
734 inWriteQueued = false;
735 }
736 }
737
738 @Override
739 public void write(Object msg, ChannelPromise promise) {
740 assert eventLoop().inEventLoop();
741 if (!promise.setUncancellable()) {
742 ReferenceCountUtil.release(msg);
743 return;
744 }
745
746
747 if (!isOpen()) {
748 queueAndFailAll(msg, promise, new ClosedChannelException());
749 } else if (finSent) {
750 queueAndFailAll(msg, promise, new ChannelOutputShutdownException("Fin was sent already"));
751 } else if (!queue.isEmpty()) {
752
753
754 try {
755 msg = filterMsg(msg);
756 } catch (UnsupportedOperationException e) {
757 ReferenceCountUtil.release(msg);
758 promise.setFailure(e);
759 return;
760 }
761
762
763 ReferenceCountUtil.touch(msg);
764 queue.add(msg, promise);
765
766
767 writeQueued();
768 } else {
769 assert queue.isEmpty();
770 writeWithoutCheckChannelState(msg, promise);
771 }
772 }
773
774 private void queueAndFailAll(Object msg, ChannelPromise promise, Throwable cause) {
775
776 ReferenceCountUtil.touch(msg);
777
778 queue.add(msg, promise);
779 queue.removeAndFailAll(cause);
780 }
781
782 private Object filterMsg(Object msg) {
783 if (msg instanceof ByteBuf) {
784 ByteBuf buffer = (ByteBuf) msg;
785 if (!buffer.isDirect()) {
786 ByteBuf tmpBuffer = alloc().directBuffer(buffer.readableBytes());
787 tmpBuffer.writeBytes(buffer, buffer.readerIndex(), buffer.readableBytes());
788 buffer.release();
789 return tmpBuffer;
790 }
791 } else if (msg instanceof QuicStreamFrame) {
792 QuicStreamFrame frame = (QuicStreamFrame) msg;
793 ByteBuf buffer = frame.content();
794 if (!buffer.isDirect()) {
795 ByteBuf tmpBuffer = alloc().directBuffer(buffer.readableBytes());
796 tmpBuffer.writeBytes(buffer, buffer.readerIndex(), buffer.readableBytes());
797 QuicStreamFrame tmpFrame = frame.replace(tmpBuffer);
798 frame.release();
799 return tmpFrame;
800 }
801 } else {
802 throw new UnsupportedOperationException(
803 "unsupported message type: " + StringUtil.simpleClassName(msg));
804 }
805 return msg;
806 }
807
808 void writeWithoutCheckChannelState(Object msg, ChannelPromise promise) {
809 try {
810 msg = filterMsg(msg);
811 } catch (UnsupportedOperationException e) {
812 ReferenceCountUtil.release(msg);
813 promise.setFailure(e);
814 return;
815 }
816
817 boolean wasFinSent = QuicheQuicStreamChannel.this.finSent;
818 boolean mayNeedWritabilityUpdate = false;
819 try {
820 int res = write0(msg);
821 if (res > 0) {
822 ReferenceCountUtil.release(msg);
823 promise.setSuccess();
824 mayNeedWritabilityUpdate = capacity == 0;
825 } else if (res == 0 || res == Quiche.QUICHE_ERR_DONE) {
826
827 ReferenceCountUtil.touch(msg);
828 queue.add(msg, promise);
829 mayNeedWritabilityUpdate = true;
830 } else if (res == Quiche.QUICHE_ERR_STREAM_STOPPED) {
831 throw new ChannelOutputShutdownException("STOP_SENDING frame received");
832 } else {
833 throw Quiche.convertToException(res);
834 }
835 } catch (Exception e) {
836 ReferenceCountUtil.release(msg);
837 promise.setFailure(e);
838 mayNeedWritabilityUpdate = capacity == 0;
839 } finally {
840 if (mayNeedWritabilityUpdate) {
841 updateWritabilityIfNeeded(false);
842 }
843 closeIfNeeded(wasFinSent);
844 }
845 }
846
847 private int write0(Object msg) throws Exception {
848 if (type() == QuicStreamType.UNIDIRECTIONAL && !isLocalCreated()) {
849 throw new UnsupportedOperationException(
850 "Writes on non-local created streams that are unidirectional are not supported");
851 }
852 if (finSent) {
853 throw new ChannelOutputShutdownException("Fin was sent already");
854 }
855
856 final boolean fin;
857 ByteBuf buffer;
858 if (msg instanceof ByteBuf) {
859 fin = false;
860 buffer = (ByteBuf) msg;
861 } else {
862 QuicStreamFrame frame = (QuicStreamFrame) msg;
863 fin = frame.hasFin();
864 buffer = frame.content();
865 }
866
867 boolean readable = buffer.isReadable();
868 if (!fin && !readable) {
869 return 1;
870 }
871
872 boolean sendSomething = false;
873 try {
874 do {
875 int res = parent().streamSend(streamId(), buffer, fin);
876
877
878 long cap = parent.streamCapacity(streamId());
879 if (cap >= 0) {
880 capacity = cap;
881 }
882 if (res < 0) {
883 return res;
884 }
885 if (readable && res == 0) {
886 return 0;
887 }
888 sendSomething = true;
889 buffer.skipBytes(res);
890 } while (buffer.isReadable());
891
892 if (fin) {
893 finSent = true;
894 outputShutdown = true;
895 }
896 return 1;
897 } finally {
898
899
900
901
902 if (sendSomething) {
903 parent.connectionSendAndFlush();
904 }
905 }
906 }
907
908 @Override
909 public void flush() {
910 assert eventLoop().inEventLoop();
911
912 }
913
914 @Override
915 public ChannelPromise voidPromise() {
916 assert eventLoop().inEventLoop();
917 return voidPromise;
918 }
919
920 @Override
921 @Nullable
922 public ChannelOutboundBuffer outboundBuffer() {
923 return null;
924 }
925
926 private void closeOnRead(ChannelPipeline pipeline, boolean readFrames) {
927 if (readFrames && finReceived && finSent) {
928 close(voidPromise());
929 } else if (config.isAllowHalfClosure()) {
930 if (finReceived) {
931
932
933 pipeline.fireUserEventTriggered(ChannelInputShutdownEvent.INSTANCE);
934 pipeline.fireUserEventTriggered(ChannelInputShutdownReadComplete.INSTANCE);
935 if (finSent) {
936
937
938 close(voidPromise());
939 }
940 }
941 } else {
942
943
944 close(voidPromise());
945 }
946 }
947
948 private void handleReadException(ChannelPipeline pipeline, @Nullable ByteBuf byteBuf, Throwable cause,
949 @SuppressWarnings("deprecation") RecvByteBufAllocator.Handle allocHandle,
950 boolean readFrames) {
951 if (byteBuf != null) {
952 if (byteBuf.isReadable()) {
953 pipeline.fireChannelRead(byteBuf);
954 } else {
955 byteBuf.release();
956 }
957 }
958
959 readComplete(allocHandle, pipeline);
960 pipeline.fireExceptionCaught(cause);
961 if (finReceived) {
962 closeOnRead(pipeline, readFrames);
963 }
964 }
965
966 void recv() {
967 assert eventLoop().inEventLoop();
968 if (inRecv) {
969
970
971 return;
972 }
973
974 inRecv = true;
975 try {
976 ChannelPipeline pipeline = pipeline();
977 QuicheQuicStreamChannelConfig config = (QuicheQuicStreamChannelConfig) config();
978
979
980 DirectIoByteBufAllocator allocator = config.allocator;
981 @SuppressWarnings("deprecation")
982 RecvByteBufAllocator.Handle allocHandle = this.recvBufAllocHandle();
983 boolean readFrames = config.isReadFrames();
984
985
986
987 while (active && readPending && readable) {
988 allocHandle.reset(config);
989 ByteBuf byteBuf = null;
990 QuicheQuicChannel parent = parent();
991
992
993
994 boolean readCompleteNeeded = false;
995 boolean continueReading = true;
996 try {
997 while (!finReceived && continueReading) {
998 byteBuf = allocHandle.allocate(allocator);
999 allocHandle.attemptedBytesRead(byteBuf.writableBytes());
1000 handleRecvResult(parent.streamRecv(streamId(), byteBuf));
1001 allocHandle.lastBytesRead(byteBuf.readableBytes());
1002 if (allocHandle.lastBytesRead() <= 0) {
1003 byteBuf.release();
1004 if (finReceived && readFrames) {
1005
1006
1007 byteBuf = Unpooled.EMPTY_BUFFER;
1008 } else {
1009 byteBuf = null;
1010 break;
1011 }
1012 }
1013
1014 allocHandle.incMessagesRead(1);
1015 readCompleteNeeded = true;
1016
1017
1018
1019 readPending = false;
1020
1021 if (readFrames) {
1022 pipeline.fireChannelRead(new DefaultQuicStreamFrame(byteBuf, finReceived));
1023 } else {
1024 pipeline.fireChannelRead(byteBuf);
1025 }
1026 byteBuf = null;
1027 continueReading = allocHandle.continueReading();
1028 }
1029
1030 if (readCompleteNeeded) {
1031 readComplete(allocHandle, pipeline);
1032 }
1033 if (finReceived) {
1034 readable = false;
1035 closeOnRead(pipeline, readFrames);
1036 }
1037 } catch (Throwable cause) {
1038 readable = false;
1039 handleReadException(pipeline, byteBuf, cause, allocHandle, readFrames);
1040 }
1041 }
1042 if (!active) {
1043 discardInput(allocator, allocHandle);
1044 }
1045 } finally {
1046
1047 inRecv = false;
1048 removeStreamFromParent();
1049 }
1050 }
1051
1052 private void handleRecvResult(QuicheQuicChannel.StreamRecvResult result) {
1053 switch (result) {
1054 case DONE:
1055
1056 readable = false;
1057 break;
1058 case FIN:
1059
1060
1061 readable = false;
1062 finReceived = true;
1063 inputShutdown = true;
1064 break;
1065 case OK:
1066 break;
1067 default:
1068 throw new Error("Unexpected StreamRecvResult: " + result);
1069 }
1070 }
1071
1072
1073
1074
1075
1076
1077 private void discardInput(DirectIoByteBufAllocator allocator,
1078 @SuppressWarnings("deprecation") RecvByteBufAllocator.Handle allocHandle) {
1079 QuicheQuicChannel parent = parent();
1080 while (readable && !finReceived) {
1081 allocHandle.reset(config());
1082 ByteBuf byteBuf = allocHandle.allocate(allocator);
1083 try {
1084 handleRecvResult(parent.streamRecv(streamId(), byteBuf));
1085 } catch (Throwable cause) {
1086
1087
1088 readable = false;
1089 finReceived = true;
1090 inputShutdown = true;
1091
1092
1093
1094
1095 if (!(cause instanceof ClosedChannelException)) {
1096 pipeline().fireExceptionCaught(cause);
1097 }
1098 } finally {
1099 byteBuf.release();
1100 }
1101 }
1102 }
1103
1104
1105
1106 private void readComplete(@SuppressWarnings("deprecation") RecvByteBufAllocator.Handle allocHandle,
1107 ChannelPipeline pipeline) {
1108 allocHandle.readComplete();
1109 pipeline.fireChannelReadComplete();
1110 }
1111 }
1112 }