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.ByteBuf;
19  import io.netty.buffer.ByteBufAllocator;
20  import io.netty.channel.ChannelException;
21  import io.netty.channel.ChannelOption;
22  import io.netty.channel.FixedRecvByteBufAllocator;
23  import io.netty.channel.MessageSizeEstimator;
24  import io.netty.channel.RecvByteBufAllocator;
25  import io.netty.channel.WriteBufferWaterMark;
26  import io.netty.channel.socket.DatagramChannelConfig;
27  import io.netty.util.internal.ObjectUtil;
28  
29  import java.io.IOException;
30  import java.net.InetAddress;
31  import java.net.NetworkInterface;
32  import java.util.Map;
33  
34  final class IoUringDatagramChannelConfig extends IoUringChannelConfig implements DatagramChannelConfig {
35      private static final RecvByteBufAllocator DEFAULT_RCVBUF_ALLOCATOR = new FixedRecvByteBufAllocator(2048);
36      private boolean activeOnOpen;
37      private volatile int maxDatagramSize;
38  
39      IoUringDatagramChannelConfig(AbstractIoUringChannel channel) {
40          super(channel);
41          setRecvByteBufAllocator(DEFAULT_RCVBUF_ALLOCATOR);
42      }
43  
44      @Override
45      @SuppressWarnings("deprecation")
46      public Map<ChannelOption<?>, Object> getOptions() {
47          return getOptions(
48                  super.getOptions(),
49                  ChannelOption.SO_BROADCAST, ChannelOption.SO_RCVBUF, ChannelOption.SO_SNDBUF,
50                  ChannelOption.SO_REUSEADDR, ChannelOption.IP_MULTICAST_LOOP_DISABLED,
51                  ChannelOption.IP_MULTICAST_ADDR, ChannelOption.IP_MULTICAST_IF, ChannelOption.IP_MULTICAST_TTL,
52                  ChannelOption.IP_TOS, ChannelOption.DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION,
53                  IoUringChannelOption.SO_REUSEPORT, IoUringChannelOption.IP_FREEBIND,
54                  IoUringChannelOption.IP_TRANSPARENT, IoUringChannelOption.MAX_DATAGRAM_PAYLOAD_SIZE,
55                  IoUringChannelOption.IP_MULTICAST_ALL);
56      }
57  
58      @SuppressWarnings({ "unchecked", "deprecation" })
59      @Override
60      public <T> T getOption(ChannelOption<T> option) {
61          if (option == ChannelOption.SO_BROADCAST) {
62              return (T) Boolean.valueOf(isBroadcast());
63          }
64          if (option == ChannelOption.SO_RCVBUF) {
65              return (T) Integer.valueOf(getReceiveBufferSize());
66          }
67          if (option == ChannelOption.SO_SNDBUF) {
68              return (T) Integer.valueOf(getSendBufferSize());
69          }
70          if (option == ChannelOption.SO_REUSEADDR) {
71              return (T) Boolean.valueOf(isReuseAddress());
72          }
73          if (option == ChannelOption.IP_MULTICAST_LOOP_DISABLED) {
74              return (T) Boolean.valueOf(isLoopbackModeDisabled());
75          }
76          if (option == ChannelOption.IP_MULTICAST_ADDR) {
77              return (T) getInterface();
78          }
79          if (option == ChannelOption.IP_MULTICAST_IF) {
80              return (T) getNetworkInterface();
81          }
82          if (option == ChannelOption.IP_MULTICAST_TTL) {
83              return (T) Integer.valueOf(getTimeToLive());
84          }
85          if (option == ChannelOption.IP_TOS) {
86              return (T) Integer.valueOf(getTrafficClass());
87          }
88          if (option == ChannelOption.DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION) {
89              return (T) Boolean.valueOf(activeOnOpen);
90          }
91          if (option == IoUringChannelOption.SO_REUSEPORT) {
92              return (T) Boolean.valueOf(isReusePort());
93          }
94          if (option == IoUringChannelOption.IP_TRANSPARENT) {
95              return (T) Boolean.valueOf(isIpTransparent());
96          }
97          if (option == IoUringChannelOption.IP_FREEBIND) {
98              return (T) Boolean.valueOf(isFreeBind());
99          }
100         if (option == IoUringChannelOption.MAX_DATAGRAM_PAYLOAD_SIZE) {
101             return (T) Integer.valueOf(getMaxDatagramPayloadSize());
102         }
103         if (option == IoUringChannelOption.IP_MULTICAST_ALL) {
104             return (T) Boolean.valueOf(isIpMulticastAll());
105         }
106         return super.getOption(option);
107     }
108 
109     @Override
110     @SuppressWarnings("deprecation")
111     public <T> boolean setOption(ChannelOption<T> option, T value) {
112         validate(option, value);
113 
114         if (option == ChannelOption.SO_BROADCAST) {
115             setBroadcast((Boolean) value);
116         } else if (option == ChannelOption.SO_RCVBUF) {
117             setReceiveBufferSize((Integer) value);
118         } else if (option == ChannelOption.SO_SNDBUF) {
119             setSendBufferSize((Integer) value);
120         } else if (option == ChannelOption.SO_REUSEADDR) {
121             setReuseAddress((Boolean) value);
122         } else if (option == ChannelOption.IP_MULTICAST_LOOP_DISABLED) {
123             setLoopbackModeDisabled((Boolean) value);
124         } else if (option == ChannelOption.IP_MULTICAST_ADDR) {
125             setInterface((InetAddress) value);
126         } else if (option == ChannelOption.IP_MULTICAST_IF) {
127             setNetworkInterface((NetworkInterface) value);
128         } else if (option == ChannelOption.IP_MULTICAST_TTL) {
129             setTimeToLive((Integer) value);
130         } else if (option == ChannelOption.IP_TOS) {
131             setTrafficClass((Integer) value);
132         } else if (option == ChannelOption.DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION) {
133             setActiveOnOpen((Boolean) value);
134         } else if (option == IoUringChannelOption.SO_REUSEPORT) {
135             setReusePort((Boolean) value);
136         } else if (option == IoUringChannelOption.IP_FREEBIND) {
137             setFreeBind((Boolean) value);
138         } else if (option == IoUringChannelOption.IP_TRANSPARENT) {
139             setIpTransparent((Boolean) value);
140         } else if (option == IoUringChannelOption.MAX_DATAGRAM_PAYLOAD_SIZE) {
141             setMaxDatagramPayloadSize((Integer) value);
142         } else if (option == IoUringChannelOption.IP_MULTICAST_ALL) {
143             setIpMulticastAll((Boolean) value);
144         } else {
145             return super.setOption(option, value);
146         }
147 
148         return true;
149     }
150 
151     private void setActiveOnOpen(boolean activeOnOpen) {
152         if (channel.isRegistered()) {
153             throw new IllegalStateException("Can only changed before channel was registered");
154         }
155         this.activeOnOpen = activeOnOpen;
156     }
157 
158     boolean getActiveOnOpen() {
159         return activeOnOpen;
160     }
161 
162     @Override
163     public IoUringDatagramChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) {
164         super.setMessageSizeEstimator(estimator);
165         return this;
166     }
167 
168     @Override
169     @Deprecated
170     public IoUringDatagramChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) {
171         super.setWriteBufferLowWaterMark(writeBufferLowWaterMark);
172         return this;
173     }
174 
175     @Override
176     @Deprecated
177     public IoUringDatagramChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) {
178         super.setWriteBufferHighWaterMark(writeBufferHighWaterMark);
179         return this;
180     }
181 
182     @Override
183     public IoUringDatagramChannelConfig setWriteBufferWaterMark(WriteBufferWaterMark writeBufferWaterMark) {
184         super.setWriteBufferWaterMark(writeBufferWaterMark);
185         return this;
186     }
187 
188     @Override
189     public IoUringDatagramChannelConfig setAutoClose(boolean autoClose) {
190         super.setAutoClose(autoClose);
191         return this;
192     }
193 
194     @Override
195     public IoUringDatagramChannelConfig setAutoRead(boolean autoRead) {
196         super.setAutoRead(autoRead);
197         return this;
198     }
199 
200     @Override
201     public IoUringDatagramChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) {
202         super.setRecvByteBufAllocator(allocator);
203         return this;
204     }
205 
206     @Override
207     public IoUringDatagramChannelConfig setWriteSpinCount(int writeSpinCount) {
208         super.setWriteSpinCount(writeSpinCount);
209         return this;
210     }
211 
212     @Override
213     public IoUringDatagramChannelConfig setAllocator(ByteBufAllocator allocator) {
214         super.setAllocator(allocator);
215         return this;
216     }
217 
218     @Override
219     public IoUringDatagramChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis) {
220         super.setConnectTimeoutMillis(connectTimeoutMillis);
221         return this;
222     }
223 
224     @Override
225     @Deprecated
226     public IoUringDatagramChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead) {
227         super.setMaxMessagesPerRead(maxMessagesPerRead);
228         return this;
229     }
230 
231     @Override
232     public int getSendBufferSize() {
233         try {
234             return ((AbstractIoUringChannel) channel).socket.getSendBufferSize();
235         } catch (IOException e) {
236             throw new ChannelException(e);
237         }
238     }
239 
240     @Override
241     public IoUringDatagramChannelConfig setSendBufferSize(int sendBufferSize) {
242         try {
243             ((AbstractIoUringChannel) channel).socket.setSendBufferSize(sendBufferSize);
244             return this;
245         } catch (IOException e) {
246             throw new ChannelException(e);
247         }
248     }
249 
250     @Override
251     public int getReceiveBufferSize() {
252         try {
253             return ((AbstractIoUringChannel) channel).socket.getReceiveBufferSize();
254         } catch (IOException e) {
255             throw new ChannelException(e);
256         }
257     }
258 
259     @Override
260     public IoUringDatagramChannelConfig setReceiveBufferSize(int receiveBufferSize) {
261         try {
262             ((AbstractIoUringChannel) channel).socket.setReceiveBufferSize(receiveBufferSize);
263             return this;
264         } catch (IOException e) {
265             throw new ChannelException(e);
266         }
267     }
268 
269     @Override
270     public int getTrafficClass() {
271         try {
272             return ((AbstractIoUringChannel) channel).socket.getTrafficClass();
273         } catch (IOException e) {
274             throw new ChannelException(e);
275         }
276     }
277 
278     @Override
279     public IoUringDatagramChannelConfig setTrafficClass(int trafficClass) {
280         try {
281             ((AbstractIoUringChannel) channel).socket.setTrafficClass(trafficClass);
282             return this;
283         } catch (IOException e) {
284             throw new ChannelException(e);
285         }
286     }
287 
288     @Override
289     public boolean isReuseAddress() {
290         try {
291             return ((AbstractIoUringChannel) channel).socket.isReuseAddress();
292         } catch (IOException e) {
293             throw new ChannelException(e);
294         }
295     }
296 
297     @Override
298     public IoUringDatagramChannelConfig setReuseAddress(boolean reuseAddress) {
299         try {
300             ((AbstractIoUringChannel) channel).socket.setReuseAddress(reuseAddress);
301             return this;
302         } catch (IOException e) {
303             throw new ChannelException(e);
304         }
305     }
306 
307     @Override
308     public boolean isBroadcast() {
309         try {
310             return ((AbstractIoUringChannel) channel).socket.isBroadcast();
311         } catch (IOException e) {
312             throw new ChannelException(e);
313         }
314     }
315 
316     @Override
317     public IoUringDatagramChannelConfig setBroadcast(boolean broadcast) {
318         try {
319             ((AbstractIoUringChannel) channel).socket.setBroadcast(broadcast);
320             return this;
321         } catch (IOException e) {
322             throw new ChannelException(e);
323         }
324     }
325 
326     @Override
327     public boolean isLoopbackModeDisabled() {
328         try {
329             return ((AbstractIoUringChannel) channel).socket.isLoopbackModeDisabled();
330         } catch (IOException e) {
331             throw new ChannelException(e);
332         }
333     }
334 
335     @Override
336     public IoUringDatagramChannelConfig setLoopbackModeDisabled(boolean loopbackModeDisabled) {
337         try {
338             ((AbstractIoUringChannel) channel).socket.setLoopbackModeDisabled(loopbackModeDisabled);
339             return this;
340         } catch (IOException e) {
341             throw new ChannelException(e);
342         }
343     }
344 
345     @Override
346     public int getTimeToLive() {
347         try {
348             return ((AbstractIoUringChannel) channel).socket.getTimeToLive();
349         } catch (IOException e) {
350             throw new ChannelException(e);
351         }
352     }
353 
354     @Override
355     public IoUringDatagramChannelConfig setTimeToLive(int ttl) {
356         try {
357             ((AbstractIoUringChannel) channel).socket.setTimeToLive(ttl);
358             return this;
359         } catch (IOException e) {
360             throw new ChannelException(e);
361         }
362     }
363 
364     @Override
365     public InetAddress getInterface() {
366         try {
367             return ((AbstractIoUringChannel) channel).socket.getInterface();
368         } catch (IOException e) {
369             throw new ChannelException(e);
370         }
371     }
372 
373     @Override
374     public IoUringDatagramChannelConfig setInterface(InetAddress interfaceAddress) {
375         try {
376             ((AbstractIoUringChannel) channel).socket.setInterface(interfaceAddress);
377             return this;
378         } catch (IOException e) {
379             throw new ChannelException(e);
380         }
381     }
382 
383     @Override
384     public NetworkInterface getNetworkInterface() {
385         try {
386             return ((AbstractIoUringChannel) channel).socket.getNetworkInterface();
387         } catch (IOException e) {
388             throw new ChannelException(e);
389         }
390     }
391 
392     @Override
393     public IoUringDatagramChannelConfig setNetworkInterface(NetworkInterface networkInterface) {
394         try {
395             ((AbstractIoUringChannel) channel).socket.setNetworkInterface(networkInterface);
396             return this;
397         } catch (IOException e) {
398             throw new ChannelException(e);
399         }
400     }
401 
402     /**
403      * Returns {@code true} if the SO_REUSEPORT option is set.
404      */
405     public boolean isReusePort() {
406         try {
407             return ((AbstractIoUringChannel) channel).socket.isReusePort();
408         } catch (IOException e) {
409             throw new ChannelException(e);
410         }
411     }
412 
413     /**
414      * Set the SO_REUSEPORT option on the underlying Channel. This will allow to bind multiple
415      * {@link io.netty.channel.socket.DatagramChannel}s to the same port and so receive datagrams with multiple threads.
416      *
417      * Be aware this method needs be called before
418      * {@link io.netty.channel.socket.DatagramChannel#bind(java.net.SocketAddress)} to have
419      * any affect.
420      */
421     public IoUringDatagramChannelConfig setReusePort(boolean reusePort) {
422         try {
423             ((AbstractIoUringChannel) channel).socket.setReusePort(reusePort);
424             return this;
425         } catch (IOException e) {
426             throw new ChannelException(e);
427         }
428     }
429 
430     /**
431      * Returns {@code true} if <a href="https://man7.org/linux/man-pages/man7/ip.7.html">IP_TRANSPARENT</a> is enabled,
432      * {@code false} otherwise.
433      */
434     public boolean isIpTransparent() {
435         try {
436             return ((AbstractIoUringChannel) channel).socket.isIpTransparent();
437         } catch (IOException e) {
438             throw new ChannelException(e);
439         }
440     }
441 
442     /**
443      * If {@code true} is used <a href="https://man7.org/linux/man-pages/man7/ip.7.html">IP_TRANSPARENT</a> is enabled,
444      * {@code false} for disable it. Default is disabled.
445      */
446     public IoUringDatagramChannelConfig setIpTransparent(boolean ipTransparent) {
447         try {
448             ((AbstractIoUringChannel) channel).socket.setIpTransparent(ipTransparent);
449             return this;
450         } catch (IOException e) {
451             throw new ChannelException(e);
452         }
453     }
454 
455     /**
456      * Returns {@code true} if <a href="https://man7.org/linux/man-pages/man7/ip.7.html">IP_FREEBIND</a> is enabled,
457      * {@code false} otherwise.
458      */
459     public boolean isFreeBind() {
460         try {
461             return ((AbstractIoUringChannel) channel).socket.isIpFreeBind();
462         } catch (IOException e) {
463             throw new ChannelException(e);
464         }
465     }
466 
467     /**
468      * If {@code true} is used <a href="https://man7.org/linux/man-pages/man7/ip.7.html">IP_FREEBIND</a> is enabled,
469      * {@code false} for disable it. Default is disabled.
470      */
471     public IoUringDatagramChannelConfig setFreeBind(boolean freeBind) {
472         try {
473             ((AbstractIoUringChannel) channel).socket.setIpFreeBind(freeBind);
474             return this;
475         } catch (IOException e) {
476             throw new ChannelException(e);
477         }
478     }
479 
480     /**
481      * Set the maximum {@link io.netty.channel.socket.DatagramPacket} size. This will be used to determine if
482      * a batch of {@code IORING_IO_RECVMSG} should be used when reading from the underlying socket.
483      * When batched {@code recvmmsg} is used
484      * we may be able to read multiple {@link io.netty.channel.socket.DatagramPacket}s with one syscall and so
485      * greatly improve the performance. This number will be used to slice {@link ByteBuf}s returned by the used
486      * {@link RecvByteBufAllocator}. You can use {@code 0} to disable the usage of batching, any other bigger value
487      * will enable it.
488      */
489     public IoUringDatagramChannelConfig setMaxDatagramPayloadSize(int maxDatagramSize) {
490         this.maxDatagramSize = ObjectUtil.checkPositiveOrZero(maxDatagramSize, "maxDatagramSize");
491         return this;
492     }
493 
494     /**
495      * Get the maximum {@link io.netty.channel.socket.DatagramPacket} size.
496      */
497     public int getMaxDatagramPayloadSize() {
498         return maxDatagramSize;
499     }
500 
501     /**
502      * If {@code true} is used <a href="https://man7.org/linux/man-pages/man7/ip.7.html">IP_MULTICAST_ALL</a> is
503      * enabled (or IPV6_MULTICAST_ALL for IPV6), {@code false} for disable it. Default is enabled.
504      */
505     public IoUringDatagramChannelConfig setIpMulticastAll(boolean multicastAll) {
506         try {
507             ((IoUringDatagramChannel) channel).socket.setIpMulticastAll(multicastAll);
508             return this;
509         } catch (IOException e) {
510             throw new ChannelException(e);
511         }
512     }
513 
514     /**
515      * Returns {@code true} if <a href="https://man7.org/linux/man-pages/man7/ip.7.html">IP_MULTICAST_ALL</a> (or
516      * IPV6_MULTICAST_ALL for IPV6) is enabled, {@code false} otherwise.
517      */
518     public boolean isIpMulticastAll() {
519         try {
520             return ((IoUringDatagramChannel) channel).socket.isIpMulticastAll();
521         } catch (IOException e) {
522             throw new ChannelException(e);
523         }
524     }
525 }