View Javadoc
1   /*
2    * Copyright 2015 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.epoll;
17  
18  import io.netty.buffer.ByteBufAllocator;
19  import io.netty.channel.Channel;
20  import io.netty.channel.ChannelException;
21  import io.netty.channel.ChannelOption;
22  import io.netty.channel.DefaultChannelConfig;
23  import io.netty.channel.MessageSizeEstimator;
24  import io.netty.channel.RecvByteBufAllocator;
25  import io.netty.channel.WriteBufferWaterMark;
26  import io.netty.channel.unix.IntegerUnixChannelOption;
27  import io.netty.channel.unix.RawUnixChannelOption;
28  import io.netty.util.internal.ObjectUtil;
29  
30  import java.io.IOException;
31  import java.nio.ByteBuffer;
32  import java.util.Map;
33  
34  import static io.netty.channel.unix.Limits.SSIZE_MAX;
35  
36  public class EpollChannelConfig extends DefaultChannelConfig {
37      private volatile long maxBytesPerGatheringWrite = SSIZE_MAX;
38  
39      protected EpollChannelConfig(Channel channel) {
40          super(checkAbstractEpollChannel(channel));
41      }
42  
43      protected EpollChannelConfig(Channel channel, RecvByteBufAllocator recvByteBufAllocator) {
44          super(checkAbstractEpollChannel(channel), recvByteBufAllocator);
45      }
46  
47      protected LinuxSocket socket() {
48          return ((AbstractEpollChannel) channel).socket;
49      }
50  
51      private static Channel checkAbstractEpollChannel(Channel channel) {
52          if (!(channel instanceof AbstractEpollChannel)) {
53              throw new IllegalArgumentException("channel is not AbstractEpollChannel: " + channel.getClass());
54          }
55          return channel;
56      }
57  
58      @Override
59      public Map<ChannelOption<?>, Object> getOptions() {
60          return getOptions(super.getOptions(), EpollChannelOption.EPOLL_MODE);
61      }
62  
63      @SuppressWarnings("unchecked")
64      @Override
65      public <T> T getOption(ChannelOption<T> option) {
66          if (option == EpollChannelOption.EPOLL_MODE) {
67              return (T) getEpollMode();
68          }
69          try {
70              if (option instanceof IntegerUnixChannelOption) {
71                  IntegerUnixChannelOption opt = (IntegerUnixChannelOption) option;
72                  return (T) Integer.valueOf(((AbstractEpollChannel) channel).socket.getIntOpt(
73                          opt.level(), opt.optname()));
74              }
75              if (option instanceof RawUnixChannelOption) {
76                  RawUnixChannelOption opt = (RawUnixChannelOption) option;
77                  ByteBuffer out = ByteBuffer.allocate(opt.length());
78                  ((AbstractEpollChannel) channel).socket.getRawOpt(opt.level(), opt.optname(), out);
79                  return (T) out.flip();
80              }
81          } catch (IOException e) {
82              throw new ChannelException(e);
83          }
84          return super.getOption(option);
85      }
86  
87      @Override
88      public <T> boolean setOption(ChannelOption<T> option, T value) {
89          validate(option, value);
90          if (option == EpollChannelOption.EPOLL_MODE) {
91              setEpollMode((EpollMode) value);
92          } else {
93              try {
94                  if (option instanceof IntegerUnixChannelOption) {
95                      IntegerUnixChannelOption opt = (IntegerUnixChannelOption) option;
96                      ((AbstractEpollChannel) channel).socket.setIntOpt(opt.level(), opt.optname(), (Integer) value);
97                      return true;
98                  } else if (option instanceof RawUnixChannelOption) {
99                      RawUnixChannelOption opt = (RawUnixChannelOption) option;
100                     ((AbstractEpollChannel) channel).socket.setRawOpt(opt.level(), opt.optname(), (ByteBuffer) value);
101                     return true;
102                 }
103             } catch (IOException e) {
104                 throw new ChannelException(e);
105             }
106             return super.setOption(option, value);
107         }
108         return true;
109     }
110 
111     @Override
112     public EpollChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis) {
113         super.setConnectTimeoutMillis(connectTimeoutMillis);
114         return this;
115     }
116 
117     @Override
118     @Deprecated
119     public EpollChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead) {
120         super.setMaxMessagesPerRead(maxMessagesPerRead);
121         return this;
122     }
123 
124     @Override
125     public EpollChannelConfig setWriteSpinCount(int writeSpinCount) {
126         super.setWriteSpinCount(writeSpinCount);
127         return this;
128     }
129 
130     @Override
131     public EpollChannelConfig setAllocator(ByteBufAllocator allocator) {
132         super.setAllocator(allocator);
133         return this;
134     }
135 
136     @Override
137     public EpollChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) {
138         if (!(allocator.newHandle() instanceof RecvByteBufAllocator.ExtendedHandle)) {
139             throw new IllegalArgumentException("allocator.newHandle() must return an object of type: " +
140                     RecvByteBufAllocator.ExtendedHandle.class);
141         }
142         super.setRecvByteBufAllocator(allocator);
143         return this;
144     }
145 
146     @Override
147     public EpollChannelConfig setAutoRead(boolean autoRead) {
148         super.setAutoRead(autoRead);
149         return this;
150     }
151 
152     @Override
153     @Deprecated
154     public EpollChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) {
155         super.setWriteBufferHighWaterMark(writeBufferHighWaterMark);
156         return this;
157     }
158 
159     @Override
160     @Deprecated
161     public EpollChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) {
162         super.setWriteBufferLowWaterMark(writeBufferLowWaterMark);
163         return this;
164     }
165 
166     @Override
167     public EpollChannelConfig setWriteBufferWaterMark(WriteBufferWaterMark writeBufferWaterMark) {
168         super.setWriteBufferWaterMark(writeBufferWaterMark);
169         return this;
170     }
171 
172     @Override
173     public EpollChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) {
174         super.setMessageSizeEstimator(estimator);
175         return this;
176     }
177 
178     /**
179      * Return the {@link EpollMode} used. Default is
180      * {@link EpollMode#EDGE_TRIGGERED}. If you want to use {@link #isAutoRead()} {@code false} or
181      * {@link #getMaxMessagesPerRead()} and have an accurate behaviour you should use
182      * {@link EpollMode#LEVEL_TRIGGERED}.
183      */
184     public EpollMode getEpollMode() {
185         return ((AbstractEpollChannel) channel).isFlagSet(Native.EPOLLET)
186                 ? EpollMode.EDGE_TRIGGERED : EpollMode.LEVEL_TRIGGERED;
187     }
188 
189     /**
190      * Set the {@link EpollMode} used. Default is
191      * {@link EpollMode#EDGE_TRIGGERED}. If you want to use {@link #isAutoRead()} {@code false} or
192      * {@link #getMaxMessagesPerRead()} and have an accurate behaviour you should use
193      * {@link EpollMode#LEVEL_TRIGGERED}.
194      *
195      * <strong>Be aware this config setting can only be adjusted before the channel was registered.</strong>
196      */
197     public EpollChannelConfig setEpollMode(EpollMode mode) {
198         ObjectUtil.checkNotNull(mode, "mode");
199 
200         try {
201             switch (mode) {
202             case EDGE_TRIGGERED:
203                 checkChannelNotRegistered();
204                 ((AbstractEpollChannel) channel).setFlag(Native.EPOLLET);
205                 break;
206             case LEVEL_TRIGGERED:
207                 checkChannelNotRegistered();
208                 ((AbstractEpollChannel) channel).clearFlag(Native.EPOLLET);
209                 break;
210             default:
211                 throw new Error();
212             }
213         } catch (IOException e) {
214             throw new ChannelException(e);
215         }
216         return this;
217     }
218 
219     private void checkChannelNotRegistered() {
220         if (channel.isRegistered()) {
221             throw new IllegalStateException("EpollMode can only be changed before channel is registered");
222         }
223     }
224 
225     @Override
226     protected final void autoReadCleared() {
227         ((AbstractEpollChannel) channel).clearEpollIn();
228     }
229 
230     protected final void setMaxBytesPerGatheringWrite(long maxBytesPerGatheringWrite) {
231         this.maxBytesPerGatheringWrite = maxBytesPerGatheringWrite;
232     }
233 
234     protected final long getMaxBytesPerGatheringWrite() {
235         return maxBytesPerGatheringWrite;
236     }
237 }