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.ChannelException;
20  import io.netty.channel.ChannelOption;
21  import io.netty.channel.MessageSizeEstimator;
22  import io.netty.channel.RecvByteBufAllocator;
23  import io.netty.channel.ServerChannelRecvByteBufAllocator;
24  import io.netty.channel.WriteBufferWaterMark;
25  import io.netty.channel.socket.ServerSocketChannelConfig;
26  import io.netty.util.NetUtil;
27  
28  import java.io.IOException;
29  import java.util.Map;
30  
31  import static io.netty.channel.ChannelOption.TCP_FASTOPEN;
32  import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
33  
34  final class IoUringServerSocketChannelConfig extends IOUringChannelConfig implements ServerSocketChannelConfig {
35      private volatile int backlog = NetUtil.SOMAXCONN;
36      private volatile int pendingFastOpenRequestsThreshold;
37  
38      IoUringServerSocketChannelConfig(AbstractIoUringServerChannel channel) {
39          super(channel, new ServerChannelRecvByteBufAllocator());
40          setReuseAddress(true);
41      }
42  
43      @Override
44      public Map<ChannelOption<?>, Object> getOptions() {
45          return getOptions(super.getOptions(), ChannelOption.SO_RCVBUF, ChannelOption.SO_REUSEADDR,
46                  ChannelOption.SO_BACKLOG, IoUringChannelOption.SO_REUSEPORT, IoUringChannelOption.IP_FREEBIND,
47                  IoUringChannelOption.IP_TRANSPARENT, IoUringChannelOption.TCP_DEFER_ACCEPT, ChannelOption.TCP_FASTOPEN);
48      }
49  
50      @SuppressWarnings("unchecked")
51      @Override
52      public <T> T getOption(ChannelOption<T> option) {
53          if (option == ChannelOption.SO_RCVBUF) {
54              return (T) Integer.valueOf(getReceiveBufferSize());
55          }
56          if (option == ChannelOption.SO_REUSEADDR) {
57              return (T) Boolean.valueOf(isReuseAddress());
58          }
59          if (option == ChannelOption.SO_BACKLOG) {
60              return (T) Integer.valueOf(getBacklog());
61          }
62          if (option == IoUringChannelOption.SO_REUSEPORT) {
63              return (T) Boolean.valueOf(isReusePort());
64          }
65          if (option == IoUringChannelOption.IP_FREEBIND) {
66              return (T) Boolean.valueOf(isFreeBind());
67          }
68          if (option == IoUringChannelOption.IP_TRANSPARENT) {
69              return (T) Boolean.valueOf(isIpTransparent());
70          }
71          if (option == IoUringChannelOption.TCP_DEFER_ACCEPT) {
72              return (T) Integer.valueOf(getTcpDeferAccept());
73          }
74          if (option == TCP_FASTOPEN) {
75              return (T) Integer.valueOf(getTcpFastopen());
76          }
77          return super.getOption(option);
78      }
79  
80      @Override
81      public <T> boolean setOption(ChannelOption<T> option, T value) {
82          validate(option, value);
83          if (option == ChannelOption.SO_RCVBUF) {
84              setReceiveBufferSize((Integer) value);
85          } else if (option == ChannelOption.SO_REUSEADDR) {
86              setReuseAddress((Boolean) value);
87          } else if (option == ChannelOption.SO_BACKLOG) {
88              setBacklog((Integer) value);
89          } else if (option == IoUringChannelOption.SO_REUSEPORT) {
90              setReusePort((Boolean) value);
91          } else if (option == IoUringChannelOption.IP_FREEBIND) {
92              setFreeBind((Boolean) value);
93          } else if (option == IoUringChannelOption.IP_TRANSPARENT) {
94              setIpTransparent((Boolean) value);
95          } else if (option == IoUringChannelOption.TCP_DEFER_ACCEPT) {
96              setTcpDeferAccept((Integer) value);
97          } else if (option == TCP_FASTOPEN) {
98              setTcpFastopen((Integer) value);
99          } else {
100             return super.setOption(option, value);
101         }
102 
103         return true;
104     }
105 
106     @Override
107     public IoUringServerSocketChannelConfig setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
108         return this;
109     }
110 
111     @Override
112     public boolean isReuseAddress() {
113         try {
114             return ((AbstractIoUringChannel) channel).socket.isReuseAddress();
115         } catch (IOException e) {
116             throw new ChannelException(e);
117         }
118     }
119 
120     @Override
121     public IoUringServerSocketChannelConfig setReuseAddress(boolean reuseAddress) {
122         try {
123             ((AbstractIoUringChannel) channel).socket.setReuseAddress(reuseAddress);
124             return this;
125         } catch (IOException e) {
126             throw new ChannelException(e);
127         }
128     }
129 
130     @Override
131     public int getReceiveBufferSize() {
132         try {
133             return ((AbstractIoUringChannel) channel).socket.getReceiveBufferSize();
134         } catch (IOException e) {
135             throw new ChannelException(e);
136         }
137     }
138 
139     @Override
140     public IoUringServerSocketChannelConfig setReceiveBufferSize(int receiveBufferSize) {
141         try {
142             ((AbstractIoUringChannel) channel).socket.setReceiveBufferSize(receiveBufferSize);
143             return this;
144         } catch (IOException e) {
145             throw new ChannelException(e);
146         }
147     }
148 
149     @Override
150     public int getBacklog() {
151         return backlog;
152     }
153 
154     @Override
155     public IoUringServerSocketChannelConfig setBacklog(int backlog) {
156         checkPositiveOrZero(backlog, "backlog");
157         this.backlog = backlog;
158         return this;
159     }
160 
161     @Override
162     public IoUringServerSocketChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis) {
163         super.setConnectTimeoutMillis(connectTimeoutMillis);
164         return this;
165     }
166 
167     @Override
168     @Deprecated
169     public IoUringServerSocketChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead) {
170         super.setMaxMessagesPerRead(maxMessagesPerRead);
171         return this;
172     }
173 
174     @Override
175     public IoUringServerSocketChannelConfig setWriteSpinCount(int writeSpinCount) {
176         super.setWriteSpinCount(writeSpinCount);
177         return this;
178     }
179 
180     @Override
181     public IoUringServerSocketChannelConfig setAllocator(ByteBufAllocator allocator) {
182         super.setAllocator(allocator);
183         return this;
184     }
185 
186     @Override
187     public IoUringServerSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) {
188         super.setRecvByteBufAllocator(allocator);
189         return this;
190     }
191 
192     @Override
193     public IoUringServerSocketChannelConfig setAutoRead(boolean autoRead) {
194         super.setAutoRead(autoRead);
195         return this;
196     }
197 
198     @Override
199     @Deprecated
200     public IoUringServerSocketChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) {
201         super.setWriteBufferHighWaterMark(writeBufferHighWaterMark);
202         return this;
203     }
204 
205     @Override
206     @Deprecated
207     public IoUringServerSocketChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) {
208         super.setWriteBufferLowWaterMark(writeBufferLowWaterMark);
209         return this;
210     }
211 
212     @Override
213     public IoUringServerSocketChannelConfig setWriteBufferWaterMark(WriteBufferWaterMark writeBufferWaterMark) {
214         super.setWriteBufferWaterMark(writeBufferWaterMark);
215         return this;
216     }
217 
218     @Override
219     public IoUringServerSocketChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) {
220         super.setMessageSizeEstimator(estimator);
221         return this;
222     }
223 
224     /**
225      * Returns {@code true} if the SO_REUSEPORT option is set.
226      */
227     public boolean isReusePort() {
228         try {
229             return ((IoUringServerSocketChannel) channel).socket.isReusePort();
230         } catch (IOException e) {
231             throw new ChannelException(e);
232         }
233     }
234 
235     /**
236      * Set the SO_REUSEPORT option on the underlying Channel. This will allow to bind multiple
237      * {@link io.netty.channel.socket.ServerSocketChannel}s to the same port and so accept connections with multiple
238      * threads.
239      *
240      * Be aware this method needs be called before
241      * {@link io.netty.channel.socket.ServerSocketChannel#bind(java.net.SocketAddress)} to have any affect.
242      */
243     public IoUringServerSocketChannelConfig setReusePort(boolean reusePort) {
244         try {
245             ((IoUringServerSocketChannel) channel).socket.setReusePort(reusePort);
246             return this;
247         } catch (IOException e) {
248             throw new ChannelException(e);
249         }
250     }
251 
252     /**
253      * Returns {@code true} if <a href="https://man7.org/linux/man-pages/man7/ip.7.html">IP_FREEBIND</a> is enabled,
254      * {@code false} otherwise.
255      */
256     public boolean isFreeBind() {
257         try {
258             return ((IoUringServerSocketChannel) channel).socket.isIpFreeBind();
259         } catch (IOException e) {
260             throw new ChannelException(e);
261         }
262     }
263 
264     /**
265      * If {@code true} is used <a href="https://man7.org/linux/man-pages/man7/ip.7.html">IP_FREEBIND</a> is enabled,
266      * {@code false} for disable it. Default is disabled.
267      */
268     public IoUringServerSocketChannelConfig setFreeBind(boolean freeBind) {
269         try {
270             ((IoUringServerSocketChannel) channel).socket.setIpFreeBind(freeBind);
271             return this;
272         } catch (IOException e) {
273             throw new ChannelException(e);
274         }
275     }
276 
277     /**
278      * Returns {@code true} if <a href="https://man7.org/linux/man-pages/man7/ip.7.html">IP_TRANSPARENT</a> is enabled,
279      * {@code false} otherwise.
280      */
281     public boolean isIpTransparent() {
282         try {
283             return ((IoUringServerSocketChannel) channel).socket.isIpTransparent();
284         } catch (IOException e) {
285             throw new ChannelException(e);
286         }
287     }
288 
289     /**
290      * If {@code true} is used <a href="https://man7.org/linux/man-pages/man7/ip.7.html">IP_TRANSPARENT</a> is enabled,
291      * {@code false} for disable it. Default is disabled.
292      */
293     public IoUringServerSocketChannelConfig setIpTransparent(boolean transparent) {
294         try {
295             ((IoUringServerSocketChannel) channel).socket.setIpTransparent(transparent);
296             return this;
297         } catch (IOException e) {
298             throw new ChannelException(e);
299         }
300     }
301 
302     /**
303      * Set the {@code TCP_DEFER_ACCEPT} option on the socket. See {@code man 7 tcp} for more details.
304      */
305     public IoUringServerSocketChannelConfig setTcpDeferAccept(int deferAccept) {
306         try {
307             ((IoUringServerSocketChannel) channel).socket.setTcpDeferAccept(deferAccept);
308             return this;
309         } catch (IOException e) {
310             throw new ChannelException(e);
311         }
312     }
313 
314     /**
315      * Returns a positive value if <a href="https://linux.die.net/man/7/tcp">TCP_DEFER_ACCEPT</a> is enabled.
316      */
317     public int getTcpDeferAccept() {
318         try {
319             return ((IoUringServerSocketChannel) channel).socket.getTcpDeferAccept();
320         } catch (IOException e) {
321             throw new ChannelException(e);
322         }
323     }
324 
325     /**
326      * Returns threshold value of number of pending for fast open connect.
327      *
328      * @see <a href="https://tools.ietf.org/html/rfc7413#appendix-A.2">RFC 7413 Passive Open</a>
329      */
330     public int getTcpFastopen() {
331         return pendingFastOpenRequestsThreshold;
332     }
333 
334     /**
335      * Enables tcpFastOpen on the server channel. If the underlying os doesn't support TCP_FASTOPEN setting this has no
336      * effect. This has to be set before doing listen on the socket otherwise this takes no effect.
337      *
338      * @param pendingFastOpenRequestsThreshold number of requests to be pending for fastopen at a given point in time
339      * for security.
340      *
341      * @see <a href="https://tools.ietf.org/html/rfc7413#appendix-A.2">RFC 7413 Passive Open</a>
342      */
343     public IoUringServerSocketChannelConfig setTcpFastopen(int pendingFastOpenRequestsThreshold) {
344         this.pendingFastOpenRequestsThreshold = checkPositiveOrZero(pendingFastOpenRequestsThreshold,
345                 "pendingFastOpenRequestsThreshold");
346         return this;
347     }
348 }