View Javadoc
1   /*
2    * Copyright 2016 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.channel.kqueue;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.buffer.ByteBufAllocator;
20  import io.netty.channel.RecvByteBufAllocator.DelegatingHandle;
21  import io.netty.channel.RecvByteBufAllocator.ExtendedHandle;
22  import io.netty.channel.unix.PreferredDirectByteBufAllocator;
23  import io.netty.util.UncheckedBooleanSupplier;
24  
25  final class KQueueRecvByteAllocatorHandle extends DelegatingHandle implements ExtendedHandle {
26      private final PreferredDirectByteBufAllocator preferredDirectByteBufAllocator =
27              new PreferredDirectByteBufAllocator();
28  
29      private final UncheckedBooleanSupplier defaultMaybeMoreDataSupplier = new UncheckedBooleanSupplier() {
30          @Override
31          public boolean get() {
32              return maybeMoreDataToRead();
33          }
34      };
35      private boolean readEOF;
36  
37      KQueueRecvByteAllocatorHandle(ExtendedHandle handle) {
38          super(handle);
39      }
40  
41      @Override
42      public ByteBuf allocate(ByteBufAllocator alloc) {
43          // We need to ensure we always allocate a direct ByteBuf as we can only use a direct buffer to read via JNI.
44          preferredDirectByteBufAllocator.updateAllocator(alloc);
45          return delegate().allocate(preferredDirectByteBufAllocator);
46      }
47  
48      @Override
49      public boolean continueReading(UncheckedBooleanSupplier maybeMoreDataSupplier) {
50          // If we received EOF we need to continue reading until there is nothing left.
51          return isReadEOF() || ((ExtendedHandle) delegate()).continueReading(maybeMoreDataSupplier);
52      }
53  
54      @Override
55      public boolean continueReading() {
56          // We must override the supplier which determines if there maybe more data to read.
57          return continueReading(defaultMaybeMoreDataSupplier);
58      }
59  
60      void readEOF() {
61          readEOF = true;
62      }
63  
64      boolean isReadEOF() {
65          return readEOF;
66      }
67  
68      private boolean maybeMoreDataToRead() {
69          /**
70           * kqueue with EV_CLEAR flag set requires that we read until we consume "data" bytes
71           * (see <a href="https://www.freebsd.org/cgi/man.cgi?kqueue">kqueue man</a>). However in order to
72           * respect auto read we supporting reading to stop if auto read is off. If auto read is on we force reading to
73           * continue to avoid a {@link StackOverflowError} between channelReadComplete and reading from the
74           * channel. It is expected that the {@link #KQueueSocketChannel} implementations will track if all data was not
75           * read, and will force a EVFILT_READ ready event.
76           *
77           * It is assumed EOF is handled externally by checking {@link #isReadEOF()}.
78           */
79          return lastBytesRead() == attemptedBytesRead();
80      }
81  }