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.ByteBufAllocator;
19  import io.netty.channel.ChannelException;
20  import io.netty.channel.ChannelOption;
21  import io.netty.channel.MessageSizeEstimator;
22  import io.netty.channel.RecvByteBufAllocator;
23  import io.netty.channel.WriteBufferWaterMark;
24  import io.netty.channel.socket.SocketChannelConfig;
25  import io.netty.util.internal.PlatformDependent;
26  import io.netty.util.internal.UnstableApi;
27  
28  import java.io.IOException;
29  import java.util.Map;
30  
31  import static io.netty.channel.ChannelOption.ALLOW_HALF_CLOSURE;
32  import static io.netty.channel.ChannelOption.IP_TOS;
33  import static io.netty.channel.ChannelOption.SO_KEEPALIVE;
34  import static io.netty.channel.ChannelOption.SO_LINGER;
35  import static io.netty.channel.ChannelOption.SO_RCVBUF;
36  import static io.netty.channel.ChannelOption.SO_REUSEADDR;
37  import static io.netty.channel.ChannelOption.SO_SNDBUF;
38  import static io.netty.channel.ChannelOption.TCP_NODELAY;
39  import static io.netty.channel.kqueue.KQueueChannelOption.SO_SNDLOWAT;
40  import static io.netty.channel.kqueue.KQueueChannelOption.TCP_NOPUSH;
41  
42  @UnstableApi
43  public final class KQueueSocketChannelConfig extends KQueueChannelConfig implements SocketChannelConfig {
44      private volatile boolean allowHalfClosure;
45      private volatile boolean tcpFastopen;
46  
47      KQueueSocketChannelConfig(KQueueSocketChannel channel) {
48          super(channel);
49          if (PlatformDependent.canEnableTcpNoDelayByDefault()) {
50              setTcpNoDelay(true);
51          }
52          calculateMaxBytesPerGatheringWrite();
53      }
54  
55      @Override
56      public Map<ChannelOption<?>, Object> getOptions() {
57          return getOptions(
58                  super.getOptions(),
59                  SO_RCVBUF, SO_SNDBUF, TCP_NODELAY, SO_KEEPALIVE, SO_REUSEADDR, SO_LINGER, IP_TOS,
60                  ALLOW_HALF_CLOSURE, SO_SNDLOWAT, TCP_NOPUSH);
61      }
62  
63      @SuppressWarnings("unchecked")
64      @Override
65      public <T> T getOption(ChannelOption<T> option) {
66          if (option == SO_RCVBUF) {
67              return (T) Integer.valueOf(getReceiveBufferSize());
68          }
69          if (option == SO_SNDBUF) {
70              return (T) Integer.valueOf(getSendBufferSize());
71          }
72          if (option == TCP_NODELAY) {
73              return (T) Boolean.valueOf(isTcpNoDelay());
74          }
75          if (option == SO_KEEPALIVE) {
76              return (T) Boolean.valueOf(isKeepAlive());
77          }
78          if (option == SO_REUSEADDR) {
79              return (T) Boolean.valueOf(isReuseAddress());
80          }
81          if (option == SO_LINGER) {
82              return (T) Integer.valueOf(getSoLinger());
83          }
84          if (option == IP_TOS) {
85              return (T) Integer.valueOf(getTrafficClass());
86          }
87          if (option == ALLOW_HALF_CLOSURE) {
88              return (T) Boolean.valueOf(isAllowHalfClosure());
89          }
90          if (option == SO_SNDLOWAT) {
91              return (T) Integer.valueOf(getSndLowAt());
92          }
93          if (option == TCP_NOPUSH) {
94              return (T) Boolean.valueOf(isTcpNoPush());
95          }
96          if (option == ChannelOption.TCP_FASTOPEN_CONNECT) {
97              return (T) Boolean.valueOf(isTcpFastOpenConnect());
98          }
99          return super.getOption(option);
100     }
101 
102     @Override
103     public <T> boolean setOption(ChannelOption<T> option, T value) {
104         validate(option, value);
105 
106         if (option == SO_RCVBUF) {
107             setReceiveBufferSize((Integer) value);
108         } else if (option == SO_SNDBUF) {
109             setSendBufferSize((Integer) value);
110         } else if (option == TCP_NODELAY) {
111             setTcpNoDelay((Boolean) value);
112         } else if (option == SO_KEEPALIVE) {
113             setKeepAlive((Boolean) value);
114         } else if (option == SO_REUSEADDR) {
115             setReuseAddress((Boolean) value);
116         } else if (option == SO_LINGER) {
117             setSoLinger((Integer) value);
118         } else if (option == IP_TOS) {
119             setTrafficClass((Integer) value);
120         } else if (option == ALLOW_HALF_CLOSURE) {
121             setAllowHalfClosure((Boolean) value);
122         } else if (option == SO_SNDLOWAT) {
123             setSndLowAt((Integer) value);
124         } else if (option == TCP_NOPUSH) {
125             setTcpNoPush((Boolean) value);
126         } else if (option == ChannelOption.TCP_FASTOPEN_CONNECT) {
127             setTcpFastOpenConnect((Boolean) value);
128         } else {
129             return super.setOption(option, value);
130         }
131 
132         return true;
133     }
134 
135     @Override
136     public int getReceiveBufferSize() {
137         try {
138             return ((KQueueSocketChannel) channel).socket.getReceiveBufferSize();
139         } catch (IOException e) {
140             throw new ChannelException(e);
141         }
142     }
143 
144     @Override
145     public int getSendBufferSize() {
146         try {
147             return ((KQueueSocketChannel) channel).socket.getSendBufferSize();
148         } catch (IOException e) {
149             throw new ChannelException(e);
150         }
151     }
152 
153     @Override
154     public int getSoLinger() {
155         try {
156             return ((KQueueSocketChannel) channel).socket.getSoLinger();
157         } catch (IOException e) {
158             throw new ChannelException(e);
159         }
160     }
161 
162     @Override
163     public int getTrafficClass() {
164         try {
165             return ((KQueueSocketChannel) channel).socket.getTrafficClass();
166         } catch (IOException e) {
167             throw new ChannelException(e);
168         }
169     }
170 
171     @Override
172     public boolean isKeepAlive() {
173         try {
174             return ((KQueueSocketChannel) channel).socket.isKeepAlive();
175         } catch (IOException e) {
176             throw new ChannelException(e);
177         }
178     }
179 
180     @Override
181     public boolean isReuseAddress() {
182         try {
183             return ((KQueueSocketChannel) channel).socket.isReuseAddress();
184         } catch (IOException e) {
185             throw new ChannelException(e);
186         }
187     }
188 
189     @Override
190     public boolean isTcpNoDelay() {
191         try {
192             return ((KQueueSocketChannel) channel).socket.isTcpNoDelay();
193         } catch (IOException e) {
194             throw new ChannelException(e);
195         }
196     }
197 
198     public int getSndLowAt() {
199         try {
200             return ((KQueueSocketChannel) channel).socket.getSndLowAt();
201         } catch (IOException e) {
202             throw new ChannelException(e);
203         }
204     }
205 
206     public void setSndLowAt(int sndLowAt)  {
207         try {
208             ((KQueueSocketChannel) channel).socket.setSndLowAt(sndLowAt);
209         } catch (IOException e) {
210             throw new ChannelException(e);
211         }
212     }
213 
214     public boolean isTcpNoPush() {
215         try {
216             return ((KQueueSocketChannel) channel).socket.isTcpNoPush();
217         } catch (IOException e) {
218             throw new ChannelException(e);
219         }
220     }
221 
222     public void setTcpNoPush(boolean tcpNoPush)  {
223         try {
224             ((KQueueSocketChannel) channel).socket.setTcpNoPush(tcpNoPush);
225         } catch (IOException e) {
226             throw new ChannelException(e);
227         }
228     }
229 
230     @Override
231     public KQueueSocketChannelConfig setKeepAlive(boolean keepAlive) {
232         try {
233             ((KQueueSocketChannel) channel).socket.setKeepAlive(keepAlive);
234             return this;
235         } catch (IOException e) {
236             throw new ChannelException(e);
237         }
238     }
239 
240     @Override
241     public KQueueSocketChannelConfig setReceiveBufferSize(int receiveBufferSize) {
242         try {
243             ((KQueueSocketChannel) channel).socket.setReceiveBufferSize(receiveBufferSize);
244             return this;
245         } catch (IOException e) {
246             throw new ChannelException(e);
247         }
248     }
249 
250     @Override
251     public KQueueSocketChannelConfig setReuseAddress(boolean reuseAddress) {
252         try {
253             ((KQueueSocketChannel) channel).socket.setReuseAddress(reuseAddress);
254             return this;
255         } catch (IOException e) {
256             throw new ChannelException(e);
257         }
258     }
259 
260     @Override
261     public KQueueSocketChannelConfig setSendBufferSize(int sendBufferSize) {
262         try {
263             ((KQueueSocketChannel) channel).socket.setSendBufferSize(sendBufferSize);
264             calculateMaxBytesPerGatheringWrite();
265             return this;
266         } catch (IOException e) {
267             throw new ChannelException(e);
268         }
269     }
270 
271     @Override
272     public KQueueSocketChannelConfig setSoLinger(int soLinger) {
273         try {
274             ((KQueueSocketChannel) channel).socket.setSoLinger(soLinger);
275             return this;
276         } catch (IOException e) {
277             throw new ChannelException(e);
278         }
279     }
280 
281     @Override
282     public KQueueSocketChannelConfig setTcpNoDelay(boolean tcpNoDelay) {
283         try {
284             ((KQueueSocketChannel) channel).socket.setTcpNoDelay(tcpNoDelay);
285             return this;
286         } catch (IOException e) {
287             throw new ChannelException(e);
288         }
289     }
290 
291     @Override
292     public KQueueSocketChannelConfig setTrafficClass(int trafficClass) {
293         try {
294             ((KQueueSocketChannel) channel).socket.setTrafficClass(trafficClass);
295             return this;
296         } catch (IOException e) {
297             throw new ChannelException(e);
298         }
299     }
300 
301     @Override
302     public boolean isAllowHalfClosure() {
303         return allowHalfClosure;
304     }
305 
306     /**
307      * Enables client TCP fast open, if available.
308      */
309     public KQueueSocketChannelConfig setTcpFastOpenConnect(boolean fastOpenConnect) {
310         tcpFastopen = fastOpenConnect;
311         return this;
312     }
313 
314     /**
315      * Returns {@code true} if TCP fast open is enabled, {@code false} otherwise.
316      */
317     public boolean isTcpFastOpenConnect() {
318         return tcpFastopen;
319     }
320 
321     @Override
322     public KQueueSocketChannelConfig setRcvAllocTransportProvidesGuess(boolean transportProvidesGuess) {
323         super.setRcvAllocTransportProvidesGuess(transportProvidesGuess);
324         return this;
325     }
326 
327     @Override
328     public KQueueSocketChannelConfig setPerformancePreferences(
329             int connectionTime, int latency, int bandwidth) {
330         return this;
331     }
332 
333     @Override
334     public KQueueSocketChannelConfig setAllowHalfClosure(boolean allowHalfClosure) {
335         this.allowHalfClosure = allowHalfClosure;
336         return this;
337     }
338 
339     @Override
340     public KQueueSocketChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis) {
341         super.setConnectTimeoutMillis(connectTimeoutMillis);
342         return this;
343     }
344 
345     @Override
346     @Deprecated
347     public KQueueSocketChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead) {
348         super.setMaxMessagesPerRead(maxMessagesPerRead);
349         return this;
350     }
351 
352     @Override
353     public KQueueSocketChannelConfig setWriteSpinCount(int writeSpinCount) {
354         super.setWriteSpinCount(writeSpinCount);
355         return this;
356     }
357 
358     @Override
359     public KQueueSocketChannelConfig setAllocator(ByteBufAllocator allocator) {
360         super.setAllocator(allocator);
361         return this;
362     }
363 
364     @Override
365     public KQueueSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) {
366         super.setRecvByteBufAllocator(allocator);
367         return this;
368     }
369 
370     @Override
371     public KQueueSocketChannelConfig setAutoRead(boolean autoRead) {
372         super.setAutoRead(autoRead);
373         return this;
374     }
375 
376     @Override
377     public KQueueSocketChannelConfig setAutoClose(boolean autoClose) {
378         super.setAutoClose(autoClose);
379         return this;
380     }
381 
382     @Override
383     @Deprecated
384     public KQueueSocketChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) {
385         super.setWriteBufferHighWaterMark(writeBufferHighWaterMark);
386         return this;
387     }
388 
389     @Override
390     @Deprecated
391     public KQueueSocketChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) {
392         super.setWriteBufferLowWaterMark(writeBufferLowWaterMark);
393         return this;
394     }
395 
396     @Override
397     public KQueueSocketChannelConfig setWriteBufferWaterMark(WriteBufferWaterMark writeBufferWaterMark) {
398         super.setWriteBufferWaterMark(writeBufferWaterMark);
399         return this;
400     }
401 
402     @Override
403     public KQueueSocketChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) {
404         super.setMessageSizeEstimator(estimator);
405         return this;
406     }
407 
408     private void calculateMaxBytesPerGatheringWrite() {
409         // Multiply by 2 to give some extra space in case the OS can process write data faster than we can provide.
410         int newSendBufferSize = getSendBufferSize() << 1;
411         if (newSendBufferSize > 0) {
412             setMaxBytesPerGatheringWrite(newSendBufferSize);
413         }
414     }
415 }