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