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