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