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