View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.transport.socket;
21  
22  import java.io.IOException;
23  import java.net.InetAddress;
24  import java.net.InetSocketAddress;
25  import java.net.ServerSocket;
26  import java.net.Socket;
27  import java.net.SocketException;
28  import java.net.UnknownHostException;
29  import java.util.LinkedHashMap;
30  import java.util.Map;
31  import java.util.Map.Entry;
32  
33  import org.apache.mina.core.service.IoService;
34  import org.apache.mina.util.ExceptionMonitor;
35  
36  /**
37   * A default implementation of {@link SocketSessionConfig}.
38   *
39   * @author The Apache MINA Project (dev@mina.apache.org)
40   * @version $Rev: 678335 $, $Date: 2008-07-21 03:25:08 +0200 (lun, 21 jui 2008) $
41   */
42  public class DefaultSocketSessionConfig extends AbstractSocketSessionConfig {
43  
44      private static Map<InetSocketAddress, InetAddress> TEST_ADDRESSES = new LinkedHashMap<InetSocketAddress, InetAddress>();
45  
46      private static boolean SET_RECEIVE_BUFFER_SIZE_AVAILABLE = false;
47      private static boolean SET_SEND_BUFFER_SIZE_AVAILABLE = false;
48      private static boolean GET_TRAFFIC_CLASS_AVAILABLE = false;
49      private static boolean SET_TRAFFIC_CLASS_AVAILABLE = false;
50      private static boolean DEFAULT_REUSE_ADDRESS = false;
51      private static int DEFAULT_RECEIVE_BUFFER_SIZE = 1024;
52      private static int DEFAULT_SEND_BUFFER_SIZE = 1024;
53      private static int DEFAULT_TRAFFIC_CLASS = 0;
54      private static boolean DEFAULT_KEEP_ALIVE = false;
55      private static boolean DEFAULT_OOB_INLINE = false;
56      private static int DEFAULT_SO_LINGER = -1;
57      private static boolean DEFAULT_TCP_NO_DELAY = false;
58  
59      static {
60          initializeTestAddresses();
61  
62          boolean success = false;
63          for (Entry<InetSocketAddress, InetAddress> e : TEST_ADDRESSES
64                  .entrySet()) {
65              success = initializeDefaultSocketParameters(e.getKey(), e
66                      .getValue());
67              if (success) {
68                  break;
69              }
70          }
71  
72          if (!success) {
73              initializeFallbackDefaultSocketParameters();
74          }
75      }
76  
77      private static void initializeFallbackDefaultSocketParameters() {
78          Socket unconnectedSocket = new Socket(); // Use a unconnected socket.
79          try {
80              initializeDefaultSocketParameters(unconnectedSocket);
81          } catch (SocketException se) {
82              ExceptionMonitor.getInstance().exceptionCaught(se);
83  
84              try {
85                  unconnectedSocket.close();
86              } catch (IOException ioe) {
87                  ExceptionMonitor.getInstance().exceptionCaught(ioe);
88              }
89          }
90      }
91  
92      private static void initializeTestAddresses() {
93          try {
94              // These two tests were disabled due to DIRMINA-560
95              // (IPv4 localhost TEST_ADDRESS causes server to hang)
96  
97              // IPv6 localhost
98              //TEST_ADDRESSES.put(new InetSocketAddress(InetAddress
99              //        .getByAddress(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100             //                0, 0, 0, 0, 1 }), 0), InetAddress
101             //        .getByAddress(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102             //                0, 0, 0, 0, 1 }));
103 
104             // IPv4 localhost
105             //TEST_ADDRESSES.put(new InetSocketAddress(InetAddress
106             //        .getByAddress(new byte[] { 127, 0, 0, 1 }), 0), InetAddress
107             //        .getByAddress(new byte[] { 127, 0, 0, 1 }));
108 
109             // Bind to wildcard interface and connect to IPv6 localhost
110             TEST_ADDRESSES.put(new InetSocketAddress(0), InetAddress
111                     .getByAddress(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112                             0, 0, 0, 0, 1 }));
113 
114             // Bind to wildcard interface and connect to IPv4 localhost
115             TEST_ADDRESSES.put(new InetSocketAddress(0), InetAddress
116                     .getByAddress(new byte[] { 127, 0, 0, 1 }));
117 
118         } catch (UnknownHostException e) {
119             ExceptionMonitor.getInstance().exceptionCaught(e);
120         }
121     }
122 
123     private static boolean initializeDefaultSocketParameters(
124             InetSocketAddress bindAddress, InetAddress connectAddress) {
125         ServerSocket ss = null;
126         Socket socket = null;
127 
128         try {
129             ss = new ServerSocket();
130             ss.bind(bindAddress);
131             socket = new Socket();
132 
133             // Timeout is set to 10 seconds in case of infinite blocking
134             // on some platform.
135             socket.connect(new InetSocketAddress(connectAddress, ss
136                     .getLocalPort()), 10000);
137 
138             initializeDefaultSocketParameters(socket);
139             return true;
140         } catch (IOException ioe) {
141             return false;
142         } finally {
143             if (socket != null) {
144                 try {
145                     socket.close();
146                 } catch (IOException e) {
147                     ExceptionMonitor.getInstance().exceptionCaught(e);
148                 }
149             }
150 
151             if (ss != null) {
152                 try {
153                     ss.close();
154                 } catch (IOException e) {
155                     ExceptionMonitor.getInstance().exceptionCaught(e);
156                 }
157             }
158        }
159     }
160 
161     private static void initializeDefaultSocketParameters(Socket socket)
162             throws SocketException {
163         DEFAULT_REUSE_ADDRESS = socket.getReuseAddress();
164         DEFAULT_RECEIVE_BUFFER_SIZE = socket.getReceiveBufferSize();
165         DEFAULT_SEND_BUFFER_SIZE = socket.getSendBufferSize();
166         DEFAULT_KEEP_ALIVE = socket.getKeepAlive();
167         DEFAULT_OOB_INLINE = socket.getOOBInline();
168         DEFAULT_SO_LINGER = socket.getSoLinger();
169         DEFAULT_TCP_NO_DELAY = socket.getTcpNoDelay();
170 
171         // Check if setReceiveBufferSize is supported.
172         try {
173             socket.setReceiveBufferSize(DEFAULT_RECEIVE_BUFFER_SIZE);
174             SET_RECEIVE_BUFFER_SIZE_AVAILABLE = true;
175         } catch (SocketException e) {
176             SET_RECEIVE_BUFFER_SIZE_AVAILABLE = false;
177         }
178 
179         // Check if setSendBufferSize is supported.
180         try {
181             socket.setSendBufferSize(DEFAULT_SEND_BUFFER_SIZE);
182             SET_SEND_BUFFER_SIZE_AVAILABLE = true;
183         } catch (SocketException e) {
184             SET_SEND_BUFFER_SIZE_AVAILABLE = false;
185         }
186 
187         // Check if getTrafficClass is supported.
188         try {
189             DEFAULT_TRAFFIC_CLASS = socket.getTrafficClass();
190             GET_TRAFFIC_CLASS_AVAILABLE = true;
191         } catch (SocketException e) {
192             GET_TRAFFIC_CLASS_AVAILABLE = false;
193             DEFAULT_TRAFFIC_CLASS = 0;
194         }
195     }
196 
197     public static boolean isSetReceiveBufferSizeAvailable() {
198         return SET_RECEIVE_BUFFER_SIZE_AVAILABLE;
199     }
200 
201     public static boolean isSetSendBufferSizeAvailable() {
202         return SET_SEND_BUFFER_SIZE_AVAILABLE;
203     }
204 
205     public static boolean isGetTrafficClassAvailable() {
206         return GET_TRAFFIC_CLASS_AVAILABLE;
207     }
208 
209     public static boolean isSetTrafficClassAvailable() {
210         return SET_TRAFFIC_CLASS_AVAILABLE;
211     }
212 
213     private IoService parent;
214     private boolean defaultReuseAddress;
215     private int defaultReceiveBufferSize = DEFAULT_RECEIVE_BUFFER_SIZE;
216 
217     private boolean reuseAddress;
218     private int receiveBufferSize = defaultReceiveBufferSize;
219     private int sendBufferSize = DEFAULT_SEND_BUFFER_SIZE;
220     private int trafficClass = DEFAULT_TRAFFIC_CLASS;
221     private boolean keepAlive = DEFAULT_KEEP_ALIVE;
222     private boolean oobInline = DEFAULT_OOB_INLINE;
223     private int soLinger = DEFAULT_SO_LINGER;
224     private boolean tcpNoDelay = DEFAULT_TCP_NO_DELAY;
225 
226     /**
227      * Creates a new instance.
228      */
229     public DefaultSocketSessionConfig() {
230     }
231 
232     public void init(IoService parent) {
233         this.parent = parent;
234         if (parent instanceof SocketAcceptor) {
235             defaultReuseAddress = true;
236         } else {
237             defaultReuseAddress = DEFAULT_REUSE_ADDRESS;
238         }
239         reuseAddress = defaultReuseAddress;
240     }
241 
242     public boolean isReuseAddress() {
243         return reuseAddress;
244     }
245 
246     public void setReuseAddress(boolean reuseAddress) {
247         this.reuseAddress = reuseAddress;
248     }
249 
250     public int getReceiveBufferSize() {
251         return receiveBufferSize;
252     }
253 
254     public void setReceiveBufferSize(int receiveBufferSize) {
255         this.receiveBufferSize = receiveBufferSize;
256 
257         // The acceptor configures the SO_RCVBUF value of the
258         // server socket when it is activated.  Consequently,
259         // a newly accepted session doesn't need to update its
260         // SO_RCVBUF parameter.  Therefore, we need to update
261         // the default receive buffer size if the acceptor is
262         // not bound yet to avoid a unnecessary system call
263         // when the acceptor is activated and new sessions are
264         // created.
265         if (!parent.isActive() && parent instanceof SocketAcceptor) {
266             defaultReceiveBufferSize = receiveBufferSize;
267         }
268     }
269 
270     public int getSendBufferSize() {
271         return sendBufferSize;
272     }
273 
274     public void setSendBufferSize(int sendBufferSize) {
275         this.sendBufferSize = sendBufferSize;
276     }
277 
278     public int getTrafficClass() {
279         return trafficClass;
280     }
281 
282     public void setTrafficClass(int trafficClass) {
283         this.trafficClass = trafficClass;
284     }
285 
286     public boolean isKeepAlive() {
287         return keepAlive;
288     }
289 
290     public void setKeepAlive(boolean keepAlive) {
291         this.keepAlive = keepAlive;
292     }
293 
294     public boolean isOobInline() {
295         return oobInline;
296     }
297 
298     public void setOobInline(boolean oobInline) {
299         this.oobInline = oobInline;
300     }
301 
302     public int getSoLinger() {
303         return soLinger;
304     }
305 
306     public void setSoLinger(int soLinger) {
307         this.soLinger = soLinger;
308     }
309 
310     public boolean isTcpNoDelay() {
311         return tcpNoDelay;
312     }
313 
314     public void setTcpNoDelay(boolean tcpNoDelay) {
315         this.tcpNoDelay = tcpNoDelay;
316     }
317 
318     @Override
319     protected boolean isKeepAliveChanged() {
320         return keepAlive != DEFAULT_KEEP_ALIVE;
321     }
322 
323     @Override
324     protected boolean isOobInlineChanged() {
325         return oobInline != DEFAULT_OOB_INLINE;
326     }
327 
328     @Override
329     protected boolean isReceiveBufferSizeChanged() {
330         return receiveBufferSize != defaultReceiveBufferSize;
331     }
332 
333     @Override
334     protected boolean isReuseAddressChanged() {
335         return reuseAddress != defaultReuseAddress;
336     }
337 
338     @Override
339     protected boolean isSendBufferSizeChanged() {
340         return sendBufferSize != DEFAULT_SEND_BUFFER_SIZE;
341     }
342 
343     @Override
344     protected boolean isSoLingerChanged() {
345         return soLinger != DEFAULT_SO_LINGER;
346     }
347 
348     @Override
349     protected boolean isTcpNoDelayChanged() {
350         return tcpNoDelay != DEFAULT_TCP_NO_DELAY;
351     }
352 
353     @Override
354     protected boolean isTrafficClassChanged() {
355         return trafficClass != DEFAULT_TRAFFIC_CLASS;
356     }
357 }