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