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;
17  
18  import io.netty.buffer.ByteBufAllocator;
19  import io.netty.channel.ChannelException;
20  import io.netty.channel.ChannelOption;
21  import io.netty.channel.DefaultChannelConfig;
22  import io.netty.channel.FixedRecvByteBufAllocator;
23  import io.netty.channel.MessageSizeEstimator;
24  import io.netty.channel.RecvByteBufAllocator;
25  import io.netty.util.internal.PlatformDependent;
26  import io.netty.util.internal.logging.InternalLogger;
27  import io.netty.util.internal.logging.InternalLoggerFactory;
28  
29  import java.io.IOException;
30  import java.net.DatagramSocket;
31  import java.net.InetAddress;
32  import java.net.MulticastSocket;
33  import java.net.NetworkInterface;
34  import java.net.SocketException;
35  import java.util.Map;
36  
37  import static io.netty.channel.ChannelOption.*;
38  
39  /**
40   * The default {@link DatagramChannelConfig} implementation.
41   */
42  public class DefaultDatagramChannelConfig extends DefaultChannelConfig implements DatagramChannelConfig {
43  
44      private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultDatagramChannelConfig.class);
45  
46      private static final RecvByteBufAllocator DEFAULT_RCVBUF_ALLOCATOR = new FixedRecvByteBufAllocator(2048);
47  
48      private final DatagramSocket javaSocket;
49      private volatile boolean activeOnOpen;
50  
51      /**
52       * Creates a new instance.
53       */
54      public DefaultDatagramChannelConfig(DatagramChannel channel, DatagramSocket javaSocket) {
55          super(channel);
56          if (javaSocket == null) {
57              throw new NullPointerException("javaSocket");
58          }
59          this.javaSocket = javaSocket;
60          setRecvByteBufAllocator(DEFAULT_RCVBUF_ALLOCATOR);
61      }
62  
63      @Override
64      @SuppressWarnings("deprecation")
65      public Map<ChannelOption<?>, Object> getOptions() {
66          return getOptions(
67                  super.getOptions(),
68                  SO_BROADCAST, SO_RCVBUF, SO_SNDBUF, SO_REUSEADDR, IP_MULTICAST_LOOP_DISABLED,
69                  IP_MULTICAST_ADDR, IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_TOS, DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION);
70      }
71  
72      @Override
73      @SuppressWarnings({ "unchecked", "deprecation" })
74      public <T> T getOption(ChannelOption<T> option) {
75          if (option == SO_BROADCAST) {
76              return (T) Boolean.valueOf(isBroadcast());
77          }
78          if (option == SO_RCVBUF) {
79              return (T) Integer.valueOf(getReceiveBufferSize());
80          }
81          if (option == SO_SNDBUF) {
82              return (T) Integer.valueOf(getSendBufferSize());
83          }
84          if (option == SO_REUSEADDR) {
85              return (T) Boolean.valueOf(isReuseAddress());
86          }
87          if (option == IP_MULTICAST_LOOP_DISABLED) {
88              return (T) Boolean.valueOf(isLoopbackModeDisabled());
89          }
90          if (option == IP_MULTICAST_ADDR) {
91              return (T) getInterface();
92          }
93          if (option == IP_MULTICAST_IF) {
94              return (T) getNetworkInterface();
95          }
96          if (option == IP_MULTICAST_TTL) {
97              return (T) Integer.valueOf(getTimeToLive());
98          }
99          if (option == IP_TOS) {
100             return (T) Integer.valueOf(getTrafficClass());
101         }
102         if (option == DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION) {
103             return (T) Boolean.valueOf(activeOnOpen);
104         }
105         return super.getOption(option);
106     }
107 
108     @Override
109     @SuppressWarnings("deprecation")
110     public <T> boolean setOption(ChannelOption<T> option, T value) {
111         validate(option, value);
112 
113         if (option == SO_BROADCAST) {
114             setBroadcast((Boolean) value);
115         } else if (option == SO_RCVBUF) {
116             setReceiveBufferSize((Integer) value);
117         } else if (option == SO_SNDBUF) {
118             setSendBufferSize((Integer) value);
119         } else if (option == SO_REUSEADDR) {
120             setReuseAddress((Boolean) value);
121         } else if (option == IP_MULTICAST_LOOP_DISABLED) {
122             setLoopbackModeDisabled((Boolean) value);
123         } else if (option == IP_MULTICAST_ADDR) {
124             setInterface((InetAddress) value);
125         } else if (option == IP_MULTICAST_IF) {
126             setNetworkInterface((NetworkInterface) value);
127         } else if (option == IP_MULTICAST_TTL) {
128             setTimeToLive((Integer) value);
129         } else if (option == IP_TOS) {
130             setTrafficClass((Integer) value);
131         } else if (option == DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION) {
132             setActiveOnOpen((Boolean) value);
133         } else {
134             return super.setOption(option, value);
135         }
136 
137         return true;
138     }
139 
140     private void setActiveOnOpen(boolean activeOnOpen) {
141         if (channel.isRegistered()) {
142             throw new IllegalStateException("Can only changed before channel was registered");
143         }
144         this.activeOnOpen = activeOnOpen;
145     }
146 
147     @Override
148     public boolean isBroadcast() {
149         try {
150             return javaSocket.getBroadcast();
151         } catch (SocketException e) {
152             throw new ChannelException(e);
153         }
154     }
155 
156     @Override
157     public DatagramChannelConfig setBroadcast(boolean broadcast) {
158         try {
159             // See: https://github.com/netty/netty/issues/576
160             if (broadcast &&
161                 !javaSocket.getLocalAddress().isAnyLocalAddress() &&
162                 !PlatformDependent.isWindows() && !PlatformDependent.isRoot()) {
163                 // Warn a user about the fact that a non-root user can't receive a
164                 // broadcast packet on *nix if the socket is bound on non-wildcard address.
165                 logger.warn(
166                         "A non-root user can't receive a broadcast packet if the socket " +
167                         "is not bound to a wildcard address; setting the SO_BROADCAST flag " +
168                         "anyway as requested on the socket which is bound to " +
169                         javaSocket.getLocalSocketAddress() + '.');
170             }
171 
172             javaSocket.setBroadcast(broadcast);
173         } catch (SocketException e) {
174             throw new ChannelException(e);
175         }
176         return this;
177     }
178 
179     @Override
180     public InetAddress getInterface() {
181         if (javaSocket instanceof MulticastSocket) {
182             try {
183                 return ((MulticastSocket) javaSocket).getInterface();
184             } catch (SocketException e) {
185                 throw new ChannelException(e);
186             }
187         } else {
188             throw new UnsupportedOperationException();
189         }
190     }
191 
192     @Override
193     public DatagramChannelConfig setInterface(InetAddress interfaceAddress) {
194         if (javaSocket instanceof MulticastSocket) {
195             try {
196                 ((MulticastSocket) javaSocket).setInterface(interfaceAddress);
197             } catch (SocketException e) {
198                 throw new ChannelException(e);
199             }
200         } else {
201             throw new UnsupportedOperationException();
202         }
203         return this;
204     }
205 
206     @Override
207     public boolean isLoopbackModeDisabled() {
208         if (javaSocket instanceof MulticastSocket) {
209             try {
210                 return ((MulticastSocket) javaSocket).getLoopbackMode();
211             } catch (SocketException e) {
212                 throw new ChannelException(e);
213             }
214         } else {
215             throw new UnsupportedOperationException();
216         }
217     }
218 
219     @Override
220     public DatagramChannelConfig setLoopbackModeDisabled(boolean loopbackModeDisabled) {
221         if (javaSocket instanceof MulticastSocket) {
222             try {
223                 ((MulticastSocket) javaSocket).setLoopbackMode(loopbackModeDisabled);
224             } catch (SocketException e) {
225                 throw new ChannelException(e);
226             }
227         } else {
228             throw new UnsupportedOperationException();
229         }
230         return this;
231     }
232 
233     @Override
234     public NetworkInterface getNetworkInterface() {
235         if (javaSocket instanceof MulticastSocket) {
236             try {
237                 return ((MulticastSocket) javaSocket).getNetworkInterface();
238             } catch (SocketException e) {
239                 throw new ChannelException(e);
240             }
241         } else {
242             throw new UnsupportedOperationException();
243         }
244     }
245 
246     @Override
247     public DatagramChannelConfig setNetworkInterface(NetworkInterface networkInterface) {
248         if (javaSocket instanceof MulticastSocket) {
249             try {
250                 ((MulticastSocket) javaSocket).setNetworkInterface(networkInterface);
251             } catch (SocketException e) {
252                 throw new ChannelException(e);
253             }
254         } else {
255             throw new UnsupportedOperationException();
256         }
257         return this;
258     }
259 
260     @Override
261     public boolean isReuseAddress() {
262         try {
263             return javaSocket.getReuseAddress();
264         } catch (SocketException e) {
265             throw new ChannelException(e);
266         }
267     }
268 
269     @Override
270     public DatagramChannelConfig setReuseAddress(boolean reuseAddress) {
271         try {
272             javaSocket.setReuseAddress(reuseAddress);
273         } catch (SocketException e) {
274             throw new ChannelException(e);
275         }
276         return this;
277     }
278 
279     @Override
280     public int getReceiveBufferSize() {
281         try {
282             return javaSocket.getReceiveBufferSize();
283         } catch (SocketException e) {
284             throw new ChannelException(e);
285         }
286     }
287 
288     @Override
289     public DatagramChannelConfig setReceiveBufferSize(int receiveBufferSize) {
290         try {
291             javaSocket.setReceiveBufferSize(receiveBufferSize);
292         } catch (SocketException e) {
293             throw new ChannelException(e);
294         }
295         return this;
296     }
297 
298     @Override
299     public int getSendBufferSize() {
300         try {
301             return javaSocket.getSendBufferSize();
302         } catch (SocketException e) {
303             throw new ChannelException(e);
304         }
305     }
306 
307     @Override
308     public DatagramChannelConfig setSendBufferSize(int sendBufferSize) {
309         try {
310             javaSocket.setSendBufferSize(sendBufferSize);
311         } catch (SocketException e) {
312             throw new ChannelException(e);
313         }
314         return this;
315     }
316 
317     @Override
318     public int getTimeToLive() {
319         if (javaSocket instanceof MulticastSocket) {
320             try {
321                 return ((MulticastSocket) javaSocket).getTimeToLive();
322             } catch (IOException e) {
323                 throw new ChannelException(e);
324             }
325         } else {
326             throw new UnsupportedOperationException();
327         }
328     }
329 
330     @Override
331     public DatagramChannelConfig setTimeToLive(int ttl) {
332         if (javaSocket instanceof MulticastSocket) {
333             try {
334                 ((MulticastSocket) javaSocket).setTimeToLive(ttl);
335             } catch (IOException e) {
336                 throw new ChannelException(e);
337             }
338         } else {
339             throw new UnsupportedOperationException();
340         }
341         return this;
342     }
343 
344     @Override
345     public int getTrafficClass() {
346         try {
347             return javaSocket.getTrafficClass();
348         } catch (SocketException e) {
349             throw new ChannelException(e);
350         }
351     }
352 
353     @Override
354     public DatagramChannelConfig setTrafficClass(int trafficClass) {
355         try {
356             javaSocket.setTrafficClass(trafficClass);
357         } catch (SocketException e) {
358             throw new ChannelException(e);
359         }
360         return this;
361     }
362 
363     @Override
364     public DatagramChannelConfig setWriteSpinCount(int writeSpinCount) {
365         super.setWriteSpinCount(writeSpinCount);
366         return this;
367     }
368 
369     @Override
370     public DatagramChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis) {
371         super.setConnectTimeoutMillis(connectTimeoutMillis);
372         return this;
373     }
374 
375     @Override
376     public DatagramChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead) {
377         super.setMaxMessagesPerRead(maxMessagesPerRead);
378         return this;
379     }
380 
381     @Override
382     public DatagramChannelConfig setAllocator(ByteBufAllocator allocator) {
383         super.setAllocator(allocator);
384         return this;
385     }
386 
387     @Override
388     public DatagramChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) {
389         super.setRecvByteBufAllocator(allocator);
390         return this;
391     }
392 
393     @Override
394     public DatagramChannelConfig setAutoRead(boolean autoRead) {
395         super.setAutoRead(autoRead);
396         return this;
397     }
398 
399     @Override
400     public DatagramChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) {
401         super.setWriteBufferHighWaterMark(writeBufferHighWaterMark);
402         return this;
403     }
404 
405     @Override
406     public DatagramChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) {
407         super.setWriteBufferLowWaterMark(writeBufferLowWaterMark);
408         return this;
409     }
410 
411     @Override
412     public DatagramChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) {
413         super.setMessageSizeEstimator(estimator);
414         return this;
415     }
416 }