1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel.socket.nio;
17
18 import io.netty.channel.ChannelException;
19 import io.netty.channel.ChannelOption;
20 import io.netty.channel.socket.DatagramChannelConfig;
21 import io.netty.channel.socket.DefaultDatagramChannelConfig;
22 import io.netty.util.internal.PlatformDependent;
23 import io.netty.util.internal.SocketUtils;
24
25 import java.lang.reflect.Method;
26 import java.net.InetAddress;
27 import java.net.NetworkInterface;
28 import java.net.SocketException;
29 import java.nio.channels.DatagramChannel;
30 import java.util.Enumeration;
31 import java.util.Map;
32
33
34
35
36 class NioDatagramChannelConfig extends DefaultDatagramChannelConfig {
37
38 private static final Object IP_MULTICAST_TTL;
39 private static final Object IP_MULTICAST_IF;
40 private static final Object IP_MULTICAST_LOOP;
41 private static final Method GET_OPTION;
42 private static final Method SET_OPTION;
43
44 static {
45 ClassLoader classLoader = PlatformDependent.getClassLoader(DatagramChannel.class);
46 Class<?> socketOptionType = null;
47 try {
48 socketOptionType = Class.forName("java.net.SocketOption", true, classLoader);
49 } catch (Exception e) {
50
51 }
52 Class<?> stdSocketOptionType = null;
53 try {
54 stdSocketOptionType = Class.forName("java.net.StandardSocketOptions", true, classLoader);
55 } catch (Exception e) {
56
57 }
58
59 Object ipMulticastTtl = null;
60 Object ipMulticastIf = null;
61 Object ipMulticastLoop = null;
62 Method getOption = null;
63 Method setOption = null;
64 if (socketOptionType != null) {
65 try {
66 ipMulticastTtl = stdSocketOptionType.getDeclaredField("IP_MULTICAST_TTL").get(null);
67 } catch (Exception e) {
68 throw new Error("cannot locate the IP_MULTICAST_TTL field", e);
69 }
70
71 try {
72 ipMulticastIf = stdSocketOptionType.getDeclaredField("IP_MULTICAST_IF").get(null);
73 } catch (Exception e) {
74 throw new Error("cannot locate the IP_MULTICAST_IF field", e);
75 }
76
77 try {
78 ipMulticastLoop = stdSocketOptionType.getDeclaredField("IP_MULTICAST_LOOP").get(null);
79 } catch (Exception e) {
80 throw new Error("cannot locate the IP_MULTICAST_LOOP field", e);
81 }
82
83 Class<?> networkChannelClass = null;
84 try {
85 networkChannelClass = Class.forName("java.nio.channels.NetworkChannel", true, classLoader);
86 } catch (Throwable ignore) {
87
88 }
89
90 if (networkChannelClass == null) {
91 getOption = null;
92 setOption = null;
93 } else {
94 try {
95 getOption = networkChannelClass.getDeclaredMethod("getOption", socketOptionType);
96 } catch (Exception e) {
97 throw new Error("cannot locate the getOption() method", e);
98 }
99
100 try {
101 setOption = networkChannelClass.getDeclaredMethod("setOption", socketOptionType, Object.class);
102 } catch (Exception e) {
103 throw new Error("cannot locate the setOption() method", e);
104 }
105 }
106 }
107 IP_MULTICAST_TTL = ipMulticastTtl;
108 IP_MULTICAST_IF = ipMulticastIf;
109 IP_MULTICAST_LOOP = ipMulticastLoop;
110 GET_OPTION = getOption;
111 SET_OPTION = setOption;
112 }
113
114 private final DatagramChannel javaChannel;
115
116 NioDatagramChannelConfig(NioDatagramChannel channel, DatagramChannel javaChannel) {
117 super(channel, javaChannel.socket());
118 this.javaChannel = javaChannel;
119 }
120
121 @Override
122 public int getTimeToLive() {
123 return (Integer) getOption0(IP_MULTICAST_TTL);
124 }
125
126 @Override
127 public DatagramChannelConfig setTimeToLive(int ttl) {
128 setOption0(IP_MULTICAST_TTL, ttl);
129 return this;
130 }
131
132 @Override
133 public InetAddress getInterface() {
134 NetworkInterface inf = getNetworkInterface();
135 if (inf != null) {
136 Enumeration<InetAddress> addresses = SocketUtils.addressesFromNetworkInterface(inf);
137 if (addresses.hasMoreElements()) {
138 return addresses.nextElement();
139 }
140 }
141 return null;
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
211 @Override
212 public <T> boolean setOption(ChannelOption<T> option, T value) {
213 if (PlatformDependent.javaVersion() >= 7 && option instanceof NioChannelOption) {
214 return NioChannelOption.setOption(javaChannel, (NioChannelOption<T>) option, value);
215 }
216 return super.setOption(option, value);
217 }
218
219 @Override
220 public <T> T getOption(ChannelOption<T> option) {
221 if (PlatformDependent.javaVersion() >= 7 && option instanceof NioChannelOption) {
222 return NioChannelOption.getOption(javaChannel, (NioChannelOption<T>) option);
223 }
224 return super.getOption(option);
225 }
226
227 @SuppressWarnings("unchecked")
228 @Override
229 public Map<ChannelOption<?>, Object> getOptions() {
230 if (PlatformDependent.javaVersion() >= 7) {
231 return getOptions(super.getOptions(), NioChannelOption.getOptions(javaChannel));
232 }
233 return super.getOptions();
234 }
235 }