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