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