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