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      protected final DatagramSocket javaSocket() {
64          return javaSocket;
65      }
66  
67      @Override
68      @SuppressWarnings("deprecation")
69      public Map<ChannelOption<?>, Object> getOptions() {
70          return getOptions(
71                  super.getOptions(),
72                  SO_BROADCAST, SO_RCVBUF, SO_SNDBUF, SO_REUSEADDR, IP_MULTICAST_LOOP_DISABLED,
73                  IP_MULTICAST_ADDR, IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_TOS, DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION);
74      }
75  
76      @Override
77      @SuppressWarnings({ "unchecked", "deprecation" })
78      public <T> T getOption(ChannelOption<T> option) {
79          if (option == SO_BROADCAST) {
80              return (T) Boolean.valueOf(isBroadcast());
81          }
82          if (option == SO_RCVBUF) {
83              return (T) Integer.valueOf(getReceiveBufferSize());
84          }
85          if (option == SO_SNDBUF) {
86              return (T) Integer.valueOf(getSendBufferSize());
87          }
88          if (option == SO_REUSEADDR) {
89              return (T) Boolean.valueOf(isReuseAddress());
90          }
91          if (option == IP_MULTICAST_LOOP_DISABLED) {
92              return (T) Boolean.valueOf(isLoopbackModeDisabled());
93          }
94          if (option == IP_MULTICAST_ADDR) {
95              return (T) getInterface();
96          }
97          if (option == IP_MULTICAST_IF) {
98              return (T) getNetworkInterface();
99          }
100         if (option == IP_MULTICAST_TTL) {
101             return (T) Integer.valueOf(getTimeToLive());
102         }
103         if (option == IP_TOS) {
104             return (T) Integer.valueOf(getTrafficClass());
105         }
106         if (option == DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION) {
107             return (T) Boolean.valueOf(activeOnOpen);
108         }
109         return super.getOption(option);
110     }
111 
112     @Override
113     @SuppressWarnings("deprecation")
114     public <T> boolean setOption(ChannelOption<T> option, T value) {
115         validate(option, value);
116 
117         if (option == SO_BROADCAST) {
118             setBroadcast((Boolean) value);
119         } else if (option == SO_RCVBUF) {
120             setReceiveBufferSize((Integer) value);
121         } else if (option == SO_SNDBUF) {
122             setSendBufferSize((Integer) value);
123         } else if (option == SO_REUSEADDR) {
124             setReuseAddress((Boolean) value);
125         } else if (option == IP_MULTICAST_LOOP_DISABLED) {
126             setLoopbackModeDisabled((Boolean) value);
127         } else if (option == IP_MULTICAST_ADDR) {
128             setInterface((InetAddress) value);
129         } else if (option == IP_MULTICAST_IF) {
130             setNetworkInterface((NetworkInterface) value);
131         } else if (option == IP_MULTICAST_TTL) {
132             setTimeToLive((Integer) value);
133         } else if (option == IP_TOS) {
134             setTrafficClass((Integer) value);
135         } else if (option == DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION) {
136             setActiveOnOpen((Boolean) value);
137         } else {
138             return super.setOption(option, value);
139         }
140 
141         return true;
142     }
143 
144     private void setActiveOnOpen(boolean activeOnOpen) {
145         if (channel.isRegistered()) {
146             throw new IllegalStateException("Can only changed before channel was registered");
147         }
148         this.activeOnOpen = activeOnOpen;
149     }
150     @Override
151     public boolean isBroadcast() {
152         try {
153             return javaSocket.getBroadcast();
154         } catch (SocketException e) {
155             throw new ChannelException(e);
156         }
157     }
158 
159     @Override
160     public DatagramChannelConfig setBroadcast(boolean broadcast) {
161         try {
162             // See: https://github.com/netty/netty/issues/576
163             if (broadcast &&
164                 !javaSocket.getLocalAddress().isAnyLocalAddress() &&
165                 !PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) {
166                 // Warn a user about the fact that a non-root user can't receive a
167                 // broadcast packet on *nix if the socket is bound on non-wildcard address.
168                 logger.warn(
169                         "A non-root user can't receive a broadcast packet if the socket " +
170                         "is not bound to a wildcard address; setting the SO_BROADCAST flag " +
171                         "anyway as requested on the socket which is bound to " +
172                         javaSocket.getLocalSocketAddress() + '.');
173             }
174 
175             javaSocket.setBroadcast(broadcast);
176         } catch (SocketException e) {
177             throw new ChannelException(e);
178         }
179         return this;
180     }
181 
182     @Override
183     public InetAddress getInterface() {
184         if (javaSocket instanceof MulticastSocket) {
185             try {
186                 return ((MulticastSocket) javaSocket).getInterface();
187             } catch (SocketException e) {
188                 throw new ChannelException(e);
189             }
190         } else {
191             throw new UnsupportedOperationException();
192         }
193     }
194 
195     @Override
196     public DatagramChannelConfig setInterface(InetAddress interfaceAddress) {
197         if (javaSocket instanceof MulticastSocket) {
198             try {
199                 ((MulticastSocket) javaSocket).setInterface(interfaceAddress);
200             } catch (SocketException e) {
201                 throw new ChannelException(e);
202             }
203         } else {
204             throw new UnsupportedOperationException();
205         }
206         return this;
207     }
208 
209     @Override
210     public boolean isLoopbackModeDisabled() {
211         if (javaSocket instanceof MulticastSocket) {
212             try {
213                 return ((MulticastSocket) javaSocket).getLoopbackMode();
214             } catch (SocketException e) {
215                 throw new ChannelException(e);
216             }
217         } else {
218             throw new UnsupportedOperationException();
219         }
220     }
221 
222     @Override
223     public DatagramChannelConfig setLoopbackModeDisabled(boolean loopbackModeDisabled) {
224         if (javaSocket instanceof MulticastSocket) {
225             try {
226                 ((MulticastSocket) javaSocket).setLoopbackMode(loopbackModeDisabled);
227             } catch (SocketException e) {
228                 throw new ChannelException(e);
229             }
230         } else {
231             throw new UnsupportedOperationException();
232         }
233         return this;
234     }
235 
236     @Override
237     public NetworkInterface getNetworkInterface() {
238         if (javaSocket instanceof MulticastSocket) {
239             try {
240                 return ((MulticastSocket) javaSocket).getNetworkInterface();
241             } catch (SocketException e) {
242                 throw new ChannelException(e);
243             }
244         } else {
245             throw new UnsupportedOperationException();
246         }
247     }
248 
249     @Override
250     public DatagramChannelConfig setNetworkInterface(NetworkInterface networkInterface) {
251         if (javaSocket instanceof MulticastSocket) {
252             try {
253                 ((MulticastSocket) javaSocket).setNetworkInterface(networkInterface);
254             } catch (SocketException e) {
255                 throw new ChannelException(e);
256             }
257         } else {
258             throw new UnsupportedOperationException();
259         }
260         return this;
261     }
262 
263     @Override
264     public boolean isReuseAddress() {
265         try {
266             return javaSocket.getReuseAddress();
267         } catch (SocketException e) {
268             throw new ChannelException(e);
269         }
270     }
271 
272     @Override
273     public DatagramChannelConfig setReuseAddress(boolean reuseAddress) {
274         try {
275             javaSocket.setReuseAddress(reuseAddress);
276         } catch (SocketException e) {
277             throw new ChannelException(e);
278         }
279         return this;
280     }
281 
282     @Override
283     public int getReceiveBufferSize() {
284         try {
285             return javaSocket.getReceiveBufferSize();
286         } catch (SocketException e) {
287             throw new ChannelException(e);
288         }
289     }
290 
291     @Override
292     public DatagramChannelConfig setReceiveBufferSize(int receiveBufferSize) {
293         try {
294             javaSocket.setReceiveBufferSize(receiveBufferSize);
295         } catch (SocketException e) {
296             throw new ChannelException(e);
297         }
298         return this;
299     }
300 
301     @Override
302     public int getSendBufferSize() {
303         try {
304             return javaSocket.getSendBufferSize();
305         } catch (SocketException e) {
306             throw new ChannelException(e);
307         }
308     }
309 
310     @Override
311     public DatagramChannelConfig setSendBufferSize(int sendBufferSize) {
312         try {
313             javaSocket.setSendBufferSize(sendBufferSize);
314         } catch (SocketException e) {
315             throw new ChannelException(e);
316         }
317         return this;
318     }
319 
320     @Override
321     public int getTimeToLive() {
322         if (javaSocket instanceof MulticastSocket) {
323             try {
324                 return ((MulticastSocket) javaSocket).getTimeToLive();
325             } catch (IOException e) {
326                 throw new ChannelException(e);
327             }
328         } else {
329             throw new UnsupportedOperationException();
330         }
331     }
332 
333     @Override
334     public DatagramChannelConfig setTimeToLive(int ttl) {
335         if (javaSocket instanceof MulticastSocket) {
336             try {
337                 ((MulticastSocket) javaSocket).setTimeToLive(ttl);
338             } catch (IOException e) {
339                 throw new ChannelException(e);
340             }
341         } else {
342             throw new UnsupportedOperationException();
343         }
344         return this;
345     }
346 
347     @Override
348     public int getTrafficClass() {
349         try {
350             return javaSocket.getTrafficClass();
351         } catch (SocketException e) {
352             throw new ChannelException(e);
353         }
354     }
355 
356     @Override
357     public DatagramChannelConfig setTrafficClass(int trafficClass) {
358         try {
359             javaSocket.setTrafficClass(trafficClass);
360         } catch (SocketException e) {
361             throw new ChannelException(e);
362         }
363         return this;
364     }
365 
366     @Override
367     public DatagramChannelConfig setWriteSpinCount(int writeSpinCount) {
368         super.setWriteSpinCount(writeSpinCount);
369         return this;
370     }
371 
372     @Override
373     public DatagramChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis) {
374         super.setConnectTimeoutMillis(connectTimeoutMillis);
375         return this;
376     }
377 
378     @Override
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 setMessageSizeEstimator(MessageSizeEstimator estimator) {
422         super.setMessageSizeEstimator(estimator);
423         return this;
424     }
425 }