View Javadoc
1   /*
2    * Copyright 2018 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.netty5.channel.socket.nio;
17  
18  import io.netty5.channel.ChannelException;
19  import io.netty5.channel.ChannelOption;
20  
21  import java.io.IOException;
22  import java.net.SocketOption;
23  import java.net.StandardSocketOptions;
24  import java.nio.channels.NetworkChannel;
25  import java.nio.channels.ServerSocketChannel;
26  
27  /**
28   * Provides {@link ChannelOption} over a given {@link java.net.SocketOption} which is then passed through the underlying
29   * {@link java.nio.channels.NetworkChannel}.
30   */
31  public final class NioChannelOption<T> extends ChannelOption<T> {
32  
33      private final java.net.SocketOption<T> option;
34  
35      @SuppressWarnings("deprecation")
36      private NioChannelOption(java.net.SocketOption<T> option) {
37          super(option.name());
38          this.option = option;
39      }
40  
41      /**
42       * Returns a {@link ChannelOption} for the given {@link java.net.SocketOption}.
43       */
44      public static <T> ChannelOption<T> of(java.net.SocketOption<T> option) {
45          return new NioChannelOption<>(option);
46      }
47  
48      // Internal helper methods to remove code duplication between Nio*Channel implementations.
49      static <T> void setOption(NetworkChannel channel, SocketOption<T> option, T value) {
50          if (channel instanceof ServerSocketChannel && option == java.net.StandardSocketOptions.IP_TOS) {
51              // Skip IP_TOS as a workaround for a JDK bug:
52              // See https://mail.openjdk.java.net/pipermail/nio-dev/2018-August/005365.html
53              return;
54          }
55          try {
56              channel.setOption(option, value);
57          } catch (IOException e) {
58              throw new ChannelException(e);
59          }
60      }
61  
62      static <T> T getOption(NetworkChannel channel, SocketOption<T> option) {
63          if (channel instanceof ServerSocketChannel && option == java.net.StandardSocketOptions.IP_TOS) {
64              // Skip IP_TOS as a workaround for a JDK bug:
65              // See https://mail.openjdk.java.net/pipermail/nio-dev/2018-August/005365.html
66              return null;
67          }
68          try {
69              return channel.getOption(option);
70          } catch (IOException e) {
71              throw new ChannelException(e);
72          }
73      }
74  
75      static boolean isOptionSupported(NetworkChannel channel, SocketOption<?> option) {
76          return channel.supportedOptions().contains(option);
77      }
78  
79      @SuppressWarnings("unchecked")
80      static <T> SocketOption<T> toSocketOption(ChannelOption<T> option) {
81          if (option instanceof NioChannelOption<?>) {
82              return ((NioChannelOption<T>) option).option;
83          }
84          if (option == SO_RCVBUF) {
85              return (SocketOption<T>) StandardSocketOptions.SO_RCVBUF;
86          }
87          if (option == SO_SNDBUF) {
88              return (SocketOption<T>) StandardSocketOptions.SO_SNDBUF;
89          }
90          if (option == TCP_NODELAY) {
91              return (SocketOption<T>) StandardSocketOptions.TCP_NODELAY;
92          }
93          if (option == SO_KEEPALIVE) {
94              return (SocketOption<T>) StandardSocketOptions.SO_KEEPALIVE;
95          }
96          if (option == SO_REUSEADDR) {
97              return (SocketOption<T>) StandardSocketOptions.SO_REUSEADDR;
98          }
99          if (option == SO_LINGER) {
100             return (SocketOption<T>) StandardSocketOptions.SO_LINGER;
101         }
102         if (option == SO_BROADCAST) {
103             return (SocketOption<T>) StandardSocketOptions.SO_BROADCAST;
104         }
105         if (option == IP_MULTICAST_LOOP_DISABLED) {
106             return (SocketOption<T>) StandardSocketOptions.IP_MULTICAST_LOOP;
107         }
108         if (option == IP_MULTICAST_IF) {
109             return (SocketOption<T>) StandardSocketOptions.IP_MULTICAST_IF;
110         }
111         if (option == IP_MULTICAST_TTL) {
112             return (SocketOption<T>) StandardSocketOptions.IP_MULTICAST_TTL;
113         }
114         if (option == IP_TOS) {
115             return (SocketOption<T>) StandardSocketOptions.IP_TOS;
116         }
117         return null;
118     }
119 }