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    *   http://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.socket.DatagramChannelConfig;
20  import io.netty.channel.socket.DefaultDatagramChannelConfig;
21  import io.netty.util.internal.PlatformDependent;
22  import io.netty.util.internal.SocketUtils;
23  
24  import java.lang.reflect.Method;
25  import java.net.InetAddress;
26  import java.net.NetworkInterface;
27  import java.net.SocketException;
28  import java.nio.channels.DatagramChannel;
29  import java.util.Enumeration;
30  
31  /**
32   * The default {@link NioDatagramChannelConfig} implementation.
33   */
34  class NioDatagramChannelConfig extends DefaultDatagramChannelConfig {
35  
36      private static final Object IP_MULTICAST_TTL;
37      private static final Object IP_MULTICAST_IF;
38      private static final Object IP_MULTICAST_LOOP;
39      private static final Method GET_OPTION;
40      private static final Method SET_OPTION;
41  
42      static {
43          ClassLoader classLoader = PlatformDependent.getClassLoader(DatagramChannel.class);
44          Class<?> socketOptionType = null;
45          try {
46              socketOptionType = Class.forName("java.net.SocketOption", true, classLoader);
47          } catch (Exception e) {
48              // Not Java 7+
49          }
50          Class<?> stdSocketOptionType = null;
51          try {
52              stdSocketOptionType = Class.forName("java.net.StandardSocketOptions", true, classLoader);
53          } catch (Exception e) {
54              // Not Java 7+
55          }
56  
57          Object ipMulticastTtl = null;
58          Object ipMulticastIf = null;
59          Object ipMulticastLoop = null;
60          Method getOption = null;
61          Method setOption = null;
62          if (socketOptionType != null) {
63              try {
64                  ipMulticastTtl = stdSocketOptionType.getDeclaredField("IP_MULTICAST_TTL").get(null);
65              } catch (Exception e) {
66                  throw new Error("cannot locate the IP_MULTICAST_TTL field", e);
67              }
68  
69              try {
70                  ipMulticastIf = stdSocketOptionType.getDeclaredField("IP_MULTICAST_IF").get(null);
71              } catch (Exception e) {
72                  throw new Error("cannot locate the IP_MULTICAST_IF field", e);
73              }
74  
75              try {
76                  ipMulticastLoop = stdSocketOptionType.getDeclaredField("IP_MULTICAST_LOOP").get(null);
77              } catch (Exception e) {
78                  throw new Error("cannot locate the IP_MULTICAST_LOOP field", e);
79              }
80  
81              Class<?> networkChannelClass = null;
82              try {
83                  networkChannelClass = Class.forName("java.nio.channels.NetworkChannel", true, classLoader);
84              } catch (Throwable ignore) {
85                  // Not Java 7+
86              }
87  
88              if (networkChannelClass == null) {
89                  getOption = null;
90                  setOption = null;
91              } else {
92                  try {
93                      getOption = networkChannelClass.getDeclaredMethod("getOption", socketOptionType);
94                  } catch (Exception e) {
95                      throw new Error("cannot locate the getOption() method", e);
96                  }
97  
98                  try {
99                      setOption = networkChannelClass.getDeclaredMethod("setOption", socketOptionType, Object.class);
100                 } catch (Exception e) {
101                     throw new Error("cannot locate the setOption() method", e);
102                 }
103             }
104         }
105         IP_MULTICAST_TTL = ipMulticastTtl;
106         IP_MULTICAST_IF = ipMulticastIf;
107         IP_MULTICAST_LOOP = ipMulticastLoop;
108         GET_OPTION = getOption;
109         SET_OPTION = setOption;
110     }
111 
112     private final DatagramChannel javaChannel;
113 
114     NioDatagramChannelConfig(NioDatagramChannel channel, DatagramChannel javaChannel) {
115         super(channel, javaChannel.socket());
116         this.javaChannel = javaChannel;
117     }
118 
119     @Override
120     public int getTimeToLive() {
121         return (Integer) getOption0(IP_MULTICAST_TTL);
122     }
123 
124     @Override
125     public DatagramChannelConfig setTimeToLive(int ttl) {
126         setOption0(IP_MULTICAST_TTL, ttl);
127         return this;
128     }
129 
130     @Override
131     public InetAddress getInterface() {
132         NetworkInterface inf = getNetworkInterface();
133         if (inf != null) {
134             Enumeration<InetAddress> addresses = SocketUtils.addressesFromNetworkInterface(inf);
135             if (addresses.hasMoreElements()) {
136                 return addresses.nextElement();
137             }
138         }
139         return null;
140     }
141 
142     @Override
143     public DatagramChannelConfig setInterface(InetAddress interfaceAddress) {
144         try {
145             setNetworkInterface(NetworkInterface.getByInetAddress(interfaceAddress));
146         } catch (SocketException e) {
147             throw new ChannelException(e);
148         }
149         return this;
150     }
151 
152     @Override
153     public NetworkInterface getNetworkInterface() {
154         return (NetworkInterface) getOption0(IP_MULTICAST_IF);
155     }
156 
157     @Override
158     public DatagramChannelConfig setNetworkInterface(NetworkInterface networkInterface) {
159         setOption0(IP_MULTICAST_IF, networkInterface);
160         return this;
161     }
162 
163     @Override
164     public boolean isLoopbackModeDisabled() {
165         return (Boolean) getOption0(IP_MULTICAST_LOOP);
166     }
167 
168     @Override
169     public DatagramChannelConfig setLoopbackModeDisabled(boolean loopbackModeDisabled) {
170         setOption0(IP_MULTICAST_LOOP, loopbackModeDisabled);
171         return this;
172     }
173 
174     @Override
175     public DatagramChannelConfig setAutoRead(boolean autoRead) {
176         super.setAutoRead(autoRead);
177         return this;
178     }
179 
180     @Override
181     protected void autoReadCleared() {
182         ((NioDatagramChannel) channel).clearReadPending0();
183     }
184 
185     private Object getOption0(Object option) {
186         if (GET_OPTION == null) {
187             throw new UnsupportedOperationException();
188         } else {
189             try {
190                 return GET_OPTION.invoke(javaChannel, option);
191             } catch (Exception e) {
192                 throw new ChannelException(e);
193             }
194         }
195     }
196 
197     private void setOption0(Object option, Object value) {
198         if (SET_OPTION == null) {
199             throw new UnsupportedOperationException();
200         } else {
201             try {
202                 SET_OPTION.invoke(javaChannel, option, value);
203             } catch (Exception e) {
204                 throw new ChannelException(e);
205             }
206         }
207     }
208 }