View Javadoc
1   /*
2    * Copyright 2014 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.epoll;
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.socket.SocketChannelConfig;
24  import io.netty.util.internal.PlatformDependent;
25  
26  import java.io.IOException;
27  import java.net.InetAddress;
28  import java.util.Map;
29  
30  import static io.netty.channel.ChannelOption.*;
31  
32  public final class EpollSocketChannelConfig extends EpollChannelConfig implements SocketChannelConfig {
33      private static final long MAX_UINT32_T = 0xFFFFFFFFL;
34      private final EpollSocketChannel channel;
35      private volatile boolean allowHalfClosure;
36  
37      /**
38       * Creates a new instance.
39       */
40      EpollSocketChannelConfig(EpollSocketChannel channel) {
41          super(channel);
42  
43          this.channel = channel;
44          if (PlatformDependent.canEnableTcpNoDelayByDefault()) {
45              setTcpNoDelay(true);
46          }
47          // Make it consistent with NIO.
48          setMaxMessagesPerRead(16);
49      }
50  
51      @Override
52      public Map<ChannelOption<?>, Object> getOptions() {
53          return getOptions(
54                  super.getOptions(),
55                  SO_RCVBUF, SO_SNDBUF, TCP_NODELAY, SO_KEEPALIVE, SO_REUSEADDR, SO_LINGER, IP_TOS,
56                  ALLOW_HALF_CLOSURE, EpollChannelOption.TCP_CORK, EpollChannelOption.TCP_NOTSENT_LOWAT,
57                  EpollChannelOption.TCP_KEEPCNT, EpollChannelOption.TCP_KEEPIDLE, EpollChannelOption.TCP_KEEPINTVL,
58                  EpollChannelOption.TCP_MD5SIG, EpollChannelOption.TCP_QUICKACK);
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 == EpollChannelOption.TCP_CORK) {
89              return (T) Boolean.valueOf(isTcpCork());
90          }
91          if (option == EpollChannelOption.TCP_NOTSENT_LOWAT) {
92              return (T) Long.valueOf(getTcpNotSentLowAt());
93          }
94          if (option == EpollChannelOption.TCP_KEEPIDLE) {
95              return (T) Integer.valueOf(getTcpKeepIdle());
96          }
97          if (option == EpollChannelOption.TCP_KEEPINTVL) {
98              return (T) Integer.valueOf(getTcpKeepIntvl());
99          }
100         if (option == EpollChannelOption.TCP_KEEPCNT) {
101             return (T) Integer.valueOf(getTcpKeepCnt());
102         }
103         if (option == EpollChannelOption.TCP_USER_TIMEOUT) {
104             return (T) Integer.valueOf(getTcpUserTimeout());
105         }
106         if (option == EpollChannelOption.TCP_QUICKACK) {
107             return (T) Boolean.valueOf(isTcpQuickAck());
108         }
109         return super.getOption(option);
110     }
111 
112     @Override
113     public <T> boolean setOption(ChannelOption<T> option, T value) {
114         validate(option, value);
115 
116         if (option == SO_RCVBUF) {
117             setReceiveBufferSize((Integer) value);
118         } else if (option == SO_SNDBUF) {
119             setSendBufferSize((Integer) value);
120         } else if (option == TCP_NODELAY) {
121             setTcpNoDelay((Boolean) value);
122         } else if (option == SO_KEEPALIVE) {
123             setKeepAlive((Boolean) value);
124         } else if (option == SO_REUSEADDR) {
125             setReuseAddress((Boolean) value);
126         } else if (option == SO_LINGER) {
127             setSoLinger((Integer) value);
128         } else if (option == IP_TOS) {
129             setTrafficClass((Integer) value);
130         } else if (option == ALLOW_HALF_CLOSURE) {
131             setAllowHalfClosure((Boolean) value);
132         } else if (option == EpollChannelOption.TCP_CORK) {
133             setTcpCork((Boolean) value);
134         } else if (option == EpollChannelOption.TCP_NOTSENT_LOWAT) {
135             setTcpNotSentLowAt((Long) value);
136         } else if (option == EpollChannelOption.TCP_KEEPIDLE) {
137             setTcpKeepIdle((Integer) value);
138         } else if (option == EpollChannelOption.TCP_KEEPCNT) {
139             setTcpKeepCnt((Integer) value);
140         } else if (option == EpollChannelOption.TCP_KEEPINTVL) {
141             setTcpKeepIntvl((Integer) value);
142         } else if (option == EpollChannelOption.TCP_USER_TIMEOUT) {
143             setTcpUserTimeout((Integer) value);
144         } else if (option == EpollChannelOption.TCP_MD5SIG) {
145             @SuppressWarnings("unchecked")
146             final Map<InetAddress, byte[]> m = (Map<InetAddress, byte[]>) value;
147             setTcpMd5Sig(m);
148         } else if (option == EpollChannelOption.TCP_QUICKACK) {
149             setTcpQuickAck((Boolean) value);
150         } else {
151             return super.setOption(option, value);
152         }
153 
154         return true;
155     }
156 
157     @Override
158     public int getReceiveBufferSize() {
159         try {
160             return channel.fd().getReceiveBufferSize();
161         } catch (IOException e) {
162             throw new ChannelException(e);
163         }
164     }
165 
166     @Override
167     public int getSendBufferSize() {
168         try {
169             return channel.fd().getSendBufferSize();
170         } catch (IOException e) {
171             throw new ChannelException(e);
172         }
173     }
174 
175     @Override
176     public int getSoLinger() {
177         try {
178             return channel.fd().getSoLinger();
179         } catch (IOException e) {
180             throw new ChannelException(e);
181         }
182     }
183 
184     @Override
185     public int getTrafficClass() {
186         try {
187             return Native.getTrafficClass(channel.fd().intValue());
188         } catch (IOException e) {
189             throw new ChannelException(e);
190         }
191     }
192 
193     @Override
194     public boolean isKeepAlive() {
195         try {
196             return channel.fd().isKeepAlive();
197         } catch (IOException e) {
198             throw new ChannelException(e);
199         }
200     }
201 
202     @Override
203     public boolean isReuseAddress() {
204         try {
205             return Native.isReuseAddress(channel.fd().intValue()) == 1;
206         } catch (IOException e) {
207             throw new ChannelException(e);
208         }
209     }
210 
211     @Override
212     public boolean isTcpNoDelay() {
213         try {
214             return channel.fd().isTcpNoDelay();
215         } catch (IOException e) {
216             throw new ChannelException(e);
217         }
218     }
219 
220     /**
221      * Get the {@code TCP_CORK} option on the socket. See {@code man 7 tcp} for more details.
222      */
223     public boolean isTcpCork() {
224         try {
225             return channel.fd().isTcpCork();
226         } catch (IOException e) {
227             throw new ChannelException(e);
228         }
229     }
230 
231     /**
232      * Get the {@code TCP_NOTSENT_LOWAT} option on the socket. See {@code man 7 tcp} for more details.
233      * @return value is a uint32_t
234      */
235     public long getTcpNotSentLowAt() {
236         try {
237             return Native.getTcpNotSentLowAt(channel.fd().intValue()) & MAX_UINT32_T;
238         } catch (IOException e) {
239             throw new ChannelException(e);
240         }
241     }
242 
243     /**
244      * Get the {@code TCP_KEEPIDLE} option on the socket. See {@code man 7 tcp} for more details.
245      */
246     public int getTcpKeepIdle() {
247         try {
248             return Native.getTcpKeepIdle(channel.fd().intValue());
249         } catch (IOException e) {
250             throw new ChannelException(e);
251         }
252     }
253 
254     /**
255      * Get the {@code TCP_KEEPINTVL} option on the socket. See {@code man 7 tcp} for more details.
256      */
257     public int getTcpKeepIntvl() {
258         try {
259             return Native.getTcpKeepIntvl(channel.fd().intValue());
260         } catch (IOException e) {
261             throw new ChannelException(e);
262         }
263     }
264 
265     /**
266      * Get the {@code TCP_KEEPCNT} option on the socket. See {@code man 7 tcp} for more details.
267      */
268     public int getTcpKeepCnt() {
269         try {
270             return Native.getTcpKeepCnt(channel.fd().intValue());
271         } catch (IOException e) {
272             throw new ChannelException(e);
273         }
274     }
275 
276     /**
277      * Get the {@code TCP_USER_TIMEOUT} option on the socket. See {@code man 7 tcp} for more details.
278      */
279     public int getTcpUserTimeout() {
280         try {
281         return Native.getTcpUserTimeout(channel.fd().intValue());
282         } catch (IOException e) {
283             throw new ChannelException(e);
284         }
285     }
286 
287     @Override
288     public EpollSocketChannelConfig setKeepAlive(boolean keepAlive) {
289         try {
290             channel.fd().setKeepAlive(keepAlive);
291             return this;
292         } catch (IOException e) {
293             throw new ChannelException(e);
294         }
295     }
296 
297     @Override
298     public EpollSocketChannelConfig setPerformancePreferences(
299             int connectionTime, int latency, int bandwidth) {
300         return this;
301     }
302 
303     @Override
304     public EpollSocketChannelConfig setReceiveBufferSize(int receiveBufferSize) {
305         try {
306             channel.fd().setReceiveBufferSize(receiveBufferSize);
307             return this;
308         } catch (IOException e) {
309             throw new ChannelException(e);
310         }
311     }
312 
313     @Override
314     public EpollSocketChannelConfig setReuseAddress(boolean reuseAddress) {
315         try {
316             Native.setReuseAddress(channel.fd().intValue(), reuseAddress ? 1 : 0);
317             return this;
318         } catch (IOException e) {
319             throw new ChannelException(e);
320         }
321     }
322 
323     @Override
324     public EpollSocketChannelConfig setSendBufferSize(int sendBufferSize) {
325         try {
326             channel.fd().setSendBufferSize(sendBufferSize);
327             return this;
328         } catch (IOException e) {
329             throw new ChannelException(e);
330         }
331     }
332 
333     @Override
334     public EpollSocketChannelConfig setSoLinger(int soLinger) {
335         try {
336             channel.fd().setSoLinger(soLinger);
337             return this;
338         } catch (IOException e) {
339             throw new ChannelException(e);
340         }
341     }
342 
343     @Override
344     public EpollSocketChannelConfig setTcpNoDelay(boolean tcpNoDelay) {
345         try {
346             channel.fd().setTcpNoDelay(tcpNoDelay);
347             return this;
348         } catch (IOException e) {
349             throw new ChannelException(e);
350         }
351     }
352 
353     /**
354      * Set the {@code TCP_CORK} option on the socket. See {@code man 7 tcp} for more details.
355      */
356     public EpollSocketChannelConfig setTcpCork(boolean tcpCork) {
357         try {
358             channel.fd().setTcpCork(tcpCork);
359             return this;
360         } catch (IOException e) {
361             throw new ChannelException(e);
362         }
363     }
364 
365     /**
366      * Set the {@code TCP_NOTSENT_LOWAT} option on the socket. See {@code man 7 tcp} for more details.
367      * @param tcpNotSentLowAt is a uint32_t
368      */
369     public EpollSocketChannelConfig setTcpNotSentLowAt(long tcpNotSentLowAt) {
370         if (tcpNotSentLowAt < 0 || tcpNotSentLowAt > MAX_UINT32_T) {
371             throw new IllegalArgumentException("tcpNotSentLowAt must be a uint32_t");
372         }
373         try {
374             Native.setTcpNotSentLowAt(channel.fd().intValue(), (int) tcpNotSentLowAt);
375             return this;
376         } catch (IOException e) {
377             throw new ChannelException(e);
378         }
379     }
380 
381     @Override
382     public EpollSocketChannelConfig setTrafficClass(int trafficClass) {
383         try {
384             Native.setTrafficClass(channel.fd().intValue(), trafficClass);
385             return this;
386         } catch (IOException e) {
387             throw new ChannelException(e);
388         }
389     }
390 
391     /**
392      * Set the {@code TCP_KEEPIDLE} option on the socket. See {@code man 7 tcp} for more details.
393      */
394     public EpollSocketChannelConfig setTcpKeepIdle(int seconds) {
395         try {
396             Native.setTcpKeepIdle(channel.fd().intValue(), seconds);
397             return this;
398         } catch (IOException e) {
399             throw new ChannelException(e);
400         }
401     }
402 
403     /**
404      * Set the {@code TCP_KEEPINTVL} option on the socket. See {@code man 7 tcp} for more details.
405      */
406     public EpollSocketChannelConfig setTcpKeepIntvl(int seconds) {
407         try {
408             Native.setTcpKeepIntvl(channel.fd().intValue(), seconds);
409             return this;
410         } catch (IOException e) {
411             throw new ChannelException(e);
412         }
413     }
414 
415     /**
416      * @deprecated use {@link #setTcpKeepCnt(int)}
417      */
418     @Deprecated
419     public EpollSocketChannelConfig setTcpKeepCntl(int probes) {
420         return setTcpKeepCnt(probes);
421     }
422 
423     /**
424      * Set the {@code TCP_KEEPCNT} option on the socket. See {@code man 7 tcp} for more details.
425      */
426     public EpollSocketChannelConfig setTcpKeepCnt(int probes) {
427         try {
428             Native.setTcpKeepCnt(channel.fd().intValue(), probes);
429             return this;
430         } catch (IOException e) {
431             throw new ChannelException(e);
432         }
433     }
434 
435     /**
436      * Set the {@code TCP_USER_TIMEOUT} option on the socket. See {@code man 7 tcp} for more details.
437      */
438     public EpollSocketChannelConfig setTcpUserTimeout(int milliseconds) {
439         try {
440             Native.setTcpUserTimeout(channel.fd().intValue(), milliseconds);
441             return this;
442         } catch (IOException e) {
443             throw new ChannelException(e);
444         }
445     }
446 
447     /**
448      * Set the {@code TCP_MD5SIG} option on the socket. See {@code linux/tcp.h} for more details.
449      * Keys can only be set on, not read to prevent a potential leak, as they are confidential.
450      * Allowing them being read would mean anyone with access to the channel could get them.
451      */
452     public EpollSocketChannelConfig setTcpMd5Sig(Map<InetAddress, byte[]> keys) {
453         try {
454             channel.setTcpMd5Sig(keys);
455             return this;
456         } catch (IOException e) {
457             throw new ChannelException(e);
458         }
459     }
460 
461     /**
462      * Set the {@code TCP_QUICKACK} option on the socket. See <a href="http://linux.die.net/man/7/tcp">TCP_QUICKACK</a>
463      * for more details.
464      */
465     public EpollSocketChannelConfig setTcpQuickAck(boolean quickAck) {
466         try {
467             channel.fd().setTcpQuickAck(quickAck);
468             return this;
469         } catch (IOException e) {
470             throw new ChannelException(e);
471         }
472     }
473 
474     /**
475      * Returns {@code true} if <a href="http://linux.die.net/man/7/tcp">TCP_QUICKACK</a> is enabled,
476      * {@code false} otherwise.
477      */
478     public boolean isTcpQuickAck() {
479         try {
480             return channel.fd().isTcpQuickAck();
481         } catch (IOException e) {
482             throw new ChannelException(e);
483         }
484     }
485 
486     @Override
487     public boolean isAllowHalfClosure() {
488         return allowHalfClosure;
489     }
490 
491     @Override
492     public EpollSocketChannelConfig setAllowHalfClosure(boolean allowHalfClosure) {
493         this.allowHalfClosure = allowHalfClosure;
494         return this;
495     }
496 
497     @Override
498     public EpollSocketChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis) {
499         super.setConnectTimeoutMillis(connectTimeoutMillis);
500         return this;
501     }
502 
503     @Override
504     public EpollSocketChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead) {
505         super.setMaxMessagesPerRead(maxMessagesPerRead);
506         return this;
507     }
508 
509     @Override
510     public EpollSocketChannelConfig setWriteSpinCount(int writeSpinCount) {
511         super.setWriteSpinCount(writeSpinCount);
512         return this;
513     }
514 
515     @Override
516     public EpollSocketChannelConfig setAllocator(ByteBufAllocator allocator) {
517         super.setAllocator(allocator);
518         return this;
519     }
520 
521     @Override
522     public EpollSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) {
523         super.setRecvByteBufAllocator(allocator);
524         return this;
525     }
526 
527     @Override
528     public EpollSocketChannelConfig setAutoRead(boolean autoRead) {
529         super.setAutoRead(autoRead);
530         return this;
531     }
532 
533     @Override
534     public EpollSocketChannelConfig setAutoClose(boolean autoClose) {
535         super.setAutoClose(autoClose);
536         return this;
537     }
538 
539     @Override
540     public EpollSocketChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) {
541         super.setWriteBufferHighWaterMark(writeBufferHighWaterMark);
542         return this;
543     }
544 
545     @Override
546     public EpollSocketChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) {
547         super.setWriteBufferLowWaterMark(writeBufferLowWaterMark);
548         return this;
549     }
550 
551     @Override
552     public EpollSocketChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) {
553         super.setMessageSizeEstimator(estimator);
554         return this;
555     }
556 
557     @Override
558     public EpollSocketChannelConfig setEpollMode(EpollMode mode) {
559         super.setEpollMode(mode);
560         return this;
561     }
562 }