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.WriteBufferWaterMark;
24  import io.netty.channel.socket.SocketChannelConfig;
25  import io.netty.util.internal.PlatformDependent;
26  
27  import java.io.IOException;
28  import java.net.InetAddress;
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  
40  public final class EpollSocketChannelConfig extends EpollChannelConfig implements SocketChannelConfig {
41      private volatile boolean allowHalfClosure;
42  
43      /**
44       * Creates a new instance.
45       */
46      EpollSocketChannelConfig(EpollSocketChannel channel) {
47          super(channel);
48  
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, EpollChannelOption.TCP_CORK, EpollChannelOption.TCP_NOTSENT_LOWAT,
61                  EpollChannelOption.TCP_KEEPCNT, EpollChannelOption.TCP_KEEPIDLE, EpollChannelOption.TCP_KEEPINTVL,
62                  EpollChannelOption.TCP_MD5SIG, EpollChannelOption.TCP_QUICKACK, EpollChannelOption.IP_TRANSPARENT,
63                  EpollChannelOption.TCP_FASTOPEN_CONNECT, EpollChannelOption.SO_BUSY_POLL);
64      }
65  
66      @SuppressWarnings("unchecked")
67      @Override
68      public <T> T getOption(ChannelOption<T> option) {
69          if (option == SO_RCVBUF) {
70              return (T) Integer.valueOf(getReceiveBufferSize());
71          }
72          if (option == SO_SNDBUF) {
73              return (T) Integer.valueOf(getSendBufferSize());
74          }
75          if (option == TCP_NODELAY) {
76              return (T) Boolean.valueOf(isTcpNoDelay());
77          }
78          if (option == SO_KEEPALIVE) {
79              return (T) Boolean.valueOf(isKeepAlive());
80          }
81          if (option == SO_REUSEADDR) {
82              return (T) Boolean.valueOf(isReuseAddress());
83          }
84          if (option == SO_LINGER) {
85              return (T) Integer.valueOf(getSoLinger());
86          }
87          if (option == IP_TOS) {
88              return (T) Integer.valueOf(getTrafficClass());
89          }
90          if (option == ALLOW_HALF_CLOSURE) {
91              return (T) Boolean.valueOf(isAllowHalfClosure());
92          }
93          if (option == EpollChannelOption.TCP_CORK) {
94              return (T) Boolean.valueOf(isTcpCork());
95          }
96          if (option == EpollChannelOption.TCP_NOTSENT_LOWAT) {
97              return (T) Long.valueOf(getTcpNotSentLowAt());
98          }
99          if (option == EpollChannelOption.TCP_KEEPIDLE) {
100             return (T) Integer.valueOf(getTcpKeepIdle());
101         }
102         if (option == EpollChannelOption.TCP_KEEPINTVL) {
103             return (T) Integer.valueOf(getTcpKeepIntvl());
104         }
105         if (option == EpollChannelOption.TCP_KEEPCNT) {
106             return (T) Integer.valueOf(getTcpKeepCnt());
107         }
108         if (option == EpollChannelOption.TCP_USER_TIMEOUT) {
109             return (T) Integer.valueOf(getTcpUserTimeout());
110         }
111         if (option == EpollChannelOption.TCP_QUICKACK) {
112             return (T) Boolean.valueOf(isTcpQuickAck());
113         }
114         if (option == EpollChannelOption.IP_TRANSPARENT) {
115             return (T) Boolean.valueOf(isIpTransparent());
116         }
117         if (option == EpollChannelOption.TCP_FASTOPEN_CONNECT) {
118             return (T) Boolean.valueOf(isTcpFastOpenConnect());
119         }
120         if (option == EpollChannelOption.SO_BUSY_POLL) {
121             return (T) Integer.valueOf(getSoBusyPoll());
122         }
123         return super.getOption(option);
124     }
125 
126     @Override
127     public <T> boolean setOption(ChannelOption<T> option, T value) {
128         validate(option, value);
129 
130         if (option == SO_RCVBUF) {
131             setReceiveBufferSize((Integer) value);
132         } else if (option == SO_SNDBUF) {
133             setSendBufferSize((Integer) value);
134         } else if (option == TCP_NODELAY) {
135             setTcpNoDelay((Boolean) value);
136         } else if (option == SO_KEEPALIVE) {
137             setKeepAlive((Boolean) value);
138         } else if (option == SO_REUSEADDR) {
139             setReuseAddress((Boolean) value);
140         } else if (option == SO_LINGER) {
141             setSoLinger((Integer) value);
142         } else if (option == IP_TOS) {
143             setTrafficClass((Integer) value);
144         } else if (option == ALLOW_HALF_CLOSURE) {
145             setAllowHalfClosure((Boolean) value);
146         } else if (option == EpollChannelOption.TCP_CORK) {
147             setTcpCork((Boolean) value);
148         } else if (option == EpollChannelOption.TCP_NOTSENT_LOWAT) {
149             setTcpNotSentLowAt((Long) value);
150         } else if (option == EpollChannelOption.TCP_KEEPIDLE) {
151             setTcpKeepIdle((Integer) value);
152         } else if (option == EpollChannelOption.TCP_KEEPCNT) {
153             setTcpKeepCnt((Integer) value);
154         } else if (option == EpollChannelOption.TCP_KEEPINTVL) {
155             setTcpKeepIntvl((Integer) value);
156         } else if (option == EpollChannelOption.TCP_USER_TIMEOUT) {
157             setTcpUserTimeout((Integer) value);
158         } else if (option == EpollChannelOption.IP_TRANSPARENT) {
159             setIpTransparent((Boolean) value);
160         } else if (option == EpollChannelOption.TCP_MD5SIG) {
161             @SuppressWarnings("unchecked")
162             final Map<InetAddress, byte[]> m = (Map<InetAddress, byte[]>) value;
163             setTcpMd5Sig(m);
164         } else if (option == EpollChannelOption.TCP_QUICKACK) {
165             setTcpQuickAck((Boolean) value);
166         } else if (option == EpollChannelOption.TCP_FASTOPEN_CONNECT) {
167             setTcpFastOpenConnect((Boolean) value);
168         } else if (option == EpollChannelOption.SO_BUSY_POLL) {
169             setSoBusyPoll((Integer) value);
170         } else {
171             return super.setOption(option, value);
172         }
173 
174         return true;
175     }
176 
177     @Override
178     public int getReceiveBufferSize() {
179         try {
180             return ((EpollSocketChannel) channel).socket.getReceiveBufferSize();
181         } catch (IOException e) {
182             throw new ChannelException(e);
183         }
184     }
185 
186     @Override
187     public int getSendBufferSize() {
188         try {
189             return ((EpollSocketChannel) channel).socket.getSendBufferSize();
190         } catch (IOException e) {
191             throw new ChannelException(e);
192         }
193     }
194 
195     @Override
196     public int getSoLinger() {
197         try {
198             return ((EpollSocketChannel) channel).socket.getSoLinger();
199         } catch (IOException e) {
200             throw new ChannelException(e);
201         }
202     }
203 
204     @Override
205     public int getTrafficClass() {
206         try {
207             return ((EpollSocketChannel) channel).socket.getTrafficClass();
208         } catch (IOException e) {
209             throw new ChannelException(e);
210         }
211     }
212 
213     @Override
214     public boolean isKeepAlive() {
215         try {
216             return ((EpollSocketChannel) channel).socket.isKeepAlive();
217         } catch (IOException e) {
218             throw new ChannelException(e);
219         }
220     }
221 
222     @Override
223     public boolean isReuseAddress() {
224         try {
225             return ((EpollSocketChannel) channel).socket.isReuseAddress();
226         } catch (IOException e) {
227             throw new ChannelException(e);
228         }
229     }
230 
231     @Override
232     public boolean isTcpNoDelay() {
233         try {
234             return ((EpollSocketChannel) channel).socket.isTcpNoDelay();
235         } catch (IOException e) {
236             throw new ChannelException(e);
237         }
238     }
239 
240     /**
241      * Get the {@code TCP_CORK} option on the socket. See {@code man 7 tcp} for more details.
242      */
243     public boolean isTcpCork() {
244         try {
245             return ((EpollSocketChannel) channel).socket.isTcpCork();
246         } catch (IOException e) {
247             throw new ChannelException(e);
248         }
249     }
250 
251     /**
252      * Get the {@code SO_BUSY_POLL} option on the socket. See {@code man 7 tcp} for more details.
253      */
254     public int getSoBusyPoll() {
255         try {
256             return ((EpollSocketChannel) channel).socket.getSoBusyPoll();
257         } catch (IOException e) {
258             throw new ChannelException(e);
259         }
260     }
261 
262     /**
263      * Get the {@code TCP_NOTSENT_LOWAT} option on the socket. See {@code man 7 tcp} for more details.
264      * @return value is a uint32_t
265      */
266     public long getTcpNotSentLowAt() {
267         try {
268             return ((EpollSocketChannel) channel).socket.getTcpNotSentLowAt();
269         } catch (IOException e) {
270             throw new ChannelException(e);
271         }
272     }
273 
274     /**
275      * Get the {@code TCP_KEEPIDLE} option on the socket. See {@code man 7 tcp} for more details.
276      */
277     public int getTcpKeepIdle() {
278         try {
279             return ((EpollSocketChannel) channel).socket.getTcpKeepIdle();
280         } catch (IOException e) {
281             throw new ChannelException(e);
282         }
283     }
284 
285     /**
286      * Get the {@code TCP_KEEPINTVL} option on the socket. See {@code man 7 tcp} for more details.
287      */
288     public int getTcpKeepIntvl() {
289         try {
290             return ((EpollSocketChannel) channel).socket.getTcpKeepIntvl();
291         } catch (IOException e) {
292             throw new ChannelException(e);
293         }
294     }
295 
296     /**
297      * Get the {@code TCP_KEEPCNT} option on the socket. See {@code man 7 tcp} for more details.
298      */
299     public int getTcpKeepCnt() {
300         try {
301             return ((EpollSocketChannel) channel).socket.getTcpKeepCnt();
302         } catch (IOException e) {
303             throw new ChannelException(e);
304         }
305     }
306 
307     /**
308      * Get the {@code TCP_USER_TIMEOUT} option on the socket. See {@code man 7 tcp} for more details.
309      */
310     public int getTcpUserTimeout() {
311         try {
312             return ((EpollSocketChannel) channel).socket.getTcpUserTimeout();
313         } catch (IOException e) {
314             throw new ChannelException(e);
315         }
316     }
317 
318     @Override
319     public EpollSocketChannelConfig setKeepAlive(boolean keepAlive) {
320         try {
321             ((EpollSocketChannel) channel).socket.setKeepAlive(keepAlive);
322             return this;
323         } catch (IOException e) {
324             throw new ChannelException(e);
325         }
326     }
327 
328     @Override
329     public EpollSocketChannelConfig setPerformancePreferences(
330             int connectionTime, int latency, int bandwidth) {
331         return this;
332     }
333 
334     @Override
335     public EpollSocketChannelConfig setReceiveBufferSize(int receiveBufferSize) {
336         try {
337             ((EpollSocketChannel) channel).socket.setReceiveBufferSize(receiveBufferSize);
338             return this;
339         } catch (IOException e) {
340             throw new ChannelException(e);
341         }
342     }
343 
344     @Override
345     public EpollSocketChannelConfig setReuseAddress(boolean reuseAddress) {
346         try {
347             ((EpollSocketChannel) channel).socket.setReuseAddress(reuseAddress);
348             return this;
349         } catch (IOException e) {
350             throw new ChannelException(e);
351         }
352     }
353 
354     @Override
355     public EpollSocketChannelConfig setSendBufferSize(int sendBufferSize) {
356         try {
357             ((EpollSocketChannel) channel).socket.setSendBufferSize(sendBufferSize);
358             calculateMaxBytesPerGatheringWrite();
359             return this;
360         } catch (IOException e) {
361             throw new ChannelException(e);
362         }
363     }
364 
365     @Override
366     public EpollSocketChannelConfig setSoLinger(int soLinger) {
367         try {
368             ((EpollSocketChannel) channel).socket.setSoLinger(soLinger);
369             return this;
370         } catch (IOException e) {
371             throw new ChannelException(e);
372         }
373     }
374 
375     @Override
376     public EpollSocketChannelConfig setTcpNoDelay(boolean tcpNoDelay) {
377         try {
378             ((EpollSocketChannel) channel).socket.setTcpNoDelay(tcpNoDelay);
379             return this;
380         } catch (IOException e) {
381             throw new ChannelException(e);
382         }
383     }
384 
385     /**
386      * Set the {@code TCP_CORK} option on the socket. See {@code man 7 tcp} for more details.
387      */
388     public EpollSocketChannelConfig setTcpCork(boolean tcpCork) {
389         try {
390             ((EpollSocketChannel) channel).socket.setTcpCork(tcpCork);
391             return this;
392         } catch (IOException e) {
393             throw new ChannelException(e);
394         }
395     }
396 
397     /**
398      * Set the {@code SO_BUSY_POLL} option on the socket. See {@code man 7 tcp} for more details.
399      */
400     public EpollSocketChannelConfig setSoBusyPoll(int loopMicros) {
401         try {
402             ((EpollSocketChannel) channel).socket.setSoBusyPoll(loopMicros);
403             return this;
404         } catch (IOException e) {
405             throw new ChannelException(e);
406         }
407     }
408 
409     /**
410      * Set the {@code TCP_NOTSENT_LOWAT} option on the socket. See {@code man 7 tcp} for more details.
411      * @param tcpNotSentLowAt is a uint32_t
412      */
413     public EpollSocketChannelConfig setTcpNotSentLowAt(long tcpNotSentLowAt) {
414         try {
415             ((EpollSocketChannel) channel).socket.setTcpNotSentLowAt(tcpNotSentLowAt);
416             return this;
417         } catch (IOException e) {
418             throw new ChannelException(e);
419         }
420     }
421 
422     @Override
423     public EpollSocketChannelConfig setTrafficClass(int trafficClass) {
424         try {
425             ((EpollSocketChannel) channel).socket.setTrafficClass(trafficClass);
426             return this;
427         } catch (IOException e) {
428             throw new ChannelException(e);
429         }
430     }
431 
432     /**
433      * Set the {@code TCP_KEEPIDLE} option on the socket. See {@code man 7 tcp} for more details.
434      */
435     public EpollSocketChannelConfig setTcpKeepIdle(int seconds) {
436         try {
437             ((EpollSocketChannel) channel).socket.setTcpKeepIdle(seconds);
438             return this;
439         } catch (IOException e) {
440             throw new ChannelException(e);
441         }
442     }
443 
444     /**
445      * Set the {@code TCP_KEEPINTVL} option on the socket. See {@code man 7 tcp} for more details.
446      */
447     public EpollSocketChannelConfig setTcpKeepIntvl(int seconds) {
448         try {
449             ((EpollSocketChannel) channel).socket.setTcpKeepIntvl(seconds);
450             return this;
451         } catch (IOException e) {
452             throw new ChannelException(e);
453         }
454     }
455 
456     /**
457      * @deprecated use {@link #setTcpKeepCnt(int)}
458      */
459     @Deprecated
460     public EpollSocketChannelConfig setTcpKeepCntl(int probes) {
461         return setTcpKeepCnt(probes);
462     }
463 
464     /**
465      * Set the {@code TCP_KEEPCNT} option on the socket. See {@code man 7 tcp} for more details.
466      */
467     public EpollSocketChannelConfig setTcpKeepCnt(int probes) {
468         try {
469             ((EpollSocketChannel) channel).socket.setTcpKeepCnt(probes);
470             return this;
471         } catch (IOException e) {
472             throw new ChannelException(e);
473         }
474     }
475 
476     /**
477      * Set the {@code TCP_USER_TIMEOUT} option on the socket. See {@code man 7 tcp} for more details.
478      */
479     public EpollSocketChannelConfig setTcpUserTimeout(int milliseconds) {
480         try {
481             ((EpollSocketChannel) channel).socket.setTcpUserTimeout(milliseconds);
482             return this;
483         } catch (IOException e) {
484             throw new ChannelException(e);
485         }
486     }
487 
488      /**
489      * Returns {@code true} if <a href="http://man7.org/linux/man-pages/man7/ip.7.html">IP_TRANSPARENT</a> is enabled,
490      * {@code false} otherwise.
491      */
492     public boolean isIpTransparent() {
493         try {
494             return ((EpollSocketChannel) channel).socket.isIpTransparent();
495         } catch (IOException e) {
496             throw new ChannelException(e);
497         }
498     }
499 
500     /**
501      * If {@code true} is used <a href="http://man7.org/linux/man-pages/man7/ip.7.html">IP_TRANSPARENT</a> is enabled,
502      * {@code false} for disable it. Default is disabled.
503      */
504     public EpollSocketChannelConfig setIpTransparent(boolean transparent) {
505         try {
506             ((EpollSocketChannel) channel).socket.setIpTransparent(transparent);
507             return this;
508         } catch (IOException e) {
509             throw new ChannelException(e);
510         }
511     }
512 
513     /**
514      * Set the {@code TCP_MD5SIG} option on the socket. See {@code linux/tcp.h} for more details.
515      * Keys can only be set on, not read to prevent a potential leak, as they are confidential.
516      * Allowing them being read would mean anyone with access to the channel could get them.
517      */
518     public EpollSocketChannelConfig setTcpMd5Sig(Map<InetAddress, byte[]> keys) {
519         try {
520             ((EpollSocketChannel) channel).setTcpMd5Sig(keys);
521             return this;
522         } catch (IOException e) {
523             throw new ChannelException(e);
524         }
525     }
526 
527     /**
528      * Set the {@code TCP_QUICKACK} option on the socket. See <a href="http://linux.die.net/man/7/tcp">TCP_QUICKACK</a>
529      * for more details.
530      */
531     public EpollSocketChannelConfig setTcpQuickAck(boolean quickAck) {
532         try {
533             ((EpollSocketChannel) channel).socket.setTcpQuickAck(quickAck);
534             return this;
535         } catch (IOException e) {
536             throw new ChannelException(e);
537         }
538     }
539 
540     /**
541      * Returns {@code true} if <a href="http://linux.die.net/man/7/tcp">TCP_QUICKACK</a> is enabled,
542      * {@code false} otherwise.
543      */
544     public boolean isTcpQuickAck() {
545         try {
546             return ((EpollSocketChannel) channel).socket.isTcpQuickAck();
547         } catch (IOException e) {
548             throw new ChannelException(e);
549         }
550     }
551 
552     /**
553      * Set the {@code TCP_FASTOPEN_CONNECT} option on the socket. Requires Linux kernel 4.11 or later.
554      * See
555      * <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=19f6d3f3">this commit</a>
556      * for more details.
557      */
558     public EpollSocketChannelConfig setTcpFastOpenConnect(boolean fastOpenConnect) {
559         try {
560             ((EpollSocketChannel) channel).socket.setTcpFastOpenConnect(fastOpenConnect);
561             return this;
562         } catch (IOException e) {
563             throw new ChannelException(e);
564         }
565     }
566 
567     /**
568      * Returns {@code true} if {@code TCP_FASTOPEN_CONNECT} is enabled, {@code false} otherwise.
569      */
570     public boolean isTcpFastOpenConnect() {
571         try {
572             return ((EpollSocketChannel) channel).socket.isTcpFastOpenConnect();
573         } catch (IOException e) {
574             throw new ChannelException(e);
575         }
576     }
577 
578     @Override
579     public boolean isAllowHalfClosure() {
580         return allowHalfClosure;
581     }
582 
583     @Override
584     public EpollSocketChannelConfig setAllowHalfClosure(boolean allowHalfClosure) {
585         this.allowHalfClosure = allowHalfClosure;
586         return this;
587     }
588 
589     @Override
590     public EpollSocketChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis) {
591         super.setConnectTimeoutMillis(connectTimeoutMillis);
592         return this;
593     }
594 
595     @Override
596     @Deprecated
597     public EpollSocketChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead) {
598         super.setMaxMessagesPerRead(maxMessagesPerRead);
599         return this;
600     }
601 
602     @Override
603     public EpollSocketChannelConfig setWriteSpinCount(int writeSpinCount) {
604         super.setWriteSpinCount(writeSpinCount);
605         return this;
606     }
607 
608     @Override
609     public EpollSocketChannelConfig setAllocator(ByteBufAllocator allocator) {
610         super.setAllocator(allocator);
611         return this;
612     }
613 
614     @Override
615     public EpollSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) {
616         super.setRecvByteBufAllocator(allocator);
617         return this;
618     }
619 
620     @Override
621     public EpollSocketChannelConfig setAutoRead(boolean autoRead) {
622         super.setAutoRead(autoRead);
623         return this;
624     }
625 
626     @Override
627     public EpollSocketChannelConfig setAutoClose(boolean autoClose) {
628         super.setAutoClose(autoClose);
629         return this;
630     }
631 
632     @Override
633     @Deprecated
634     public EpollSocketChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) {
635         super.setWriteBufferHighWaterMark(writeBufferHighWaterMark);
636         return this;
637     }
638 
639     @Override
640     @Deprecated
641     public EpollSocketChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) {
642         super.setWriteBufferLowWaterMark(writeBufferLowWaterMark);
643         return this;
644     }
645 
646     @Override
647     public EpollSocketChannelConfig setWriteBufferWaterMark(WriteBufferWaterMark writeBufferWaterMark) {
648         super.setWriteBufferWaterMark(writeBufferWaterMark);
649         return this;
650     }
651 
652     @Override
653     public EpollSocketChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) {
654         super.setMessageSizeEstimator(estimator);
655         return this;
656     }
657 
658     @Override
659     public EpollSocketChannelConfig setEpollMode(EpollMode mode) {
660         super.setEpollMode(mode);
661         return this;
662     }
663 
664     private void calculateMaxBytesPerGatheringWrite() {
665         // Multiply by 2 to give some extra space in case the OS can process write data faster than we can provide.
666         int newSendBufferSize = getSendBufferSize() << 1;
667         if (newSendBufferSize > 0) {
668             setMaxBytesPerGatheringWrite(getSendBufferSize() << 1);
669         }
670     }
671 }