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             return null;
135         } else {
136             Enumeration<InetAddress> addresses = SocketUtils.addressesFromNetworkInterface(inf);
137             if (addresses.hasMoreElements()) {
138                 return addresses.nextElement();
139             }
140             return null;
141         }
142     }
143 
144     @Override
145     public DatagramChannelConfig setInterface(InetAddress interfaceAddress) {
146         try {
147             setNetworkInterface(NetworkInterface.getByInetAddress(interfaceAddress));
148         } catch (SocketException e) {
149             throw new ChannelException(e);
150         }
151         return this;
152     }
153 
154     @Override
155     public NetworkInterface getNetworkInterface() {
156         return (NetworkInterface) getOption0(IP_MULTICAST_IF);
157     }
158 
159     @Override
160     public DatagramChannelConfig setNetworkInterface(NetworkInterface networkInterface) {
161         setOption0(IP_MULTICAST_IF, networkInterface);
162         return this;
163     }
164 
165     @Override
166     public boolean isLoopbackModeDisabled() {
167         return (Boolean) getOption0(IP_MULTICAST_LOOP);
168     }
169 
170     @Override
171     public DatagramChannelConfig setLoopbackModeDisabled(boolean loopbackModeDisabled) {
172         setOption0(IP_MULTICAST_LOOP, loopbackModeDisabled);
173         return this;
174     }
175 
176     @Override
177     public DatagramChannelConfig setAutoRead(boolean autoRead) {
178         super.setAutoRead(autoRead);
179         return this;
180     }
181 
182     @Override
183     protected void autoReadCleared() {
184         ((NioDatagramChannel) channel).clearReadPending0();
185     }
186 
187     private Object getOption0(Object option) {
188         if (GET_OPTION == null) {
189             throw new UnsupportedOperationException();
190         } else {
191             try {
192                 return GET_OPTION.invoke(javaChannel, option);
193             } catch (Exception e) {
194                 throw new ChannelException(e);
195             }
196         }
197     }
198 
199     private void setOption0(Object option, Object value) {
200         if (SET_OPTION == null) {
201             throw new UnsupportedOperationException();
202         } else {
203             try {
204                 SET_OPTION.invoke(javaChannel, option, value);
205             } catch (Exception e) {
206                 throw new ChannelException(e);
207             }
208         }
209     }
210 }