View Javadoc

1   /*
2    *   @(#) $Id: SSLByteBufferPool.java 210062 2005-07-11 03:52:38Z trustin $
3    *
4    *   Copyright 2004 The Apache Software Foundation
5    *
6    *   Licensed under the Apache License, Version 2.0 (the "License");
7    *   you may not use this file except in compliance with the License.
8    *   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, software
13   *   distributed under the License is distributed on an "AS IS" BASIS,
14   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *   See the License for the specific language governing permissions and
16   *   limitations under the License.
17   *
18   */
19  package org.apache.mina.io.filter;
20  
21  import java.nio.ByteBuffer;
22  
23  import javax.net.ssl.SSLEngine;
24  
25  import org.apache.mina.util.Stack;
26  
27  /***
28   * Simple ByteBuffer pool used by SSLHandler.
29   * ByteBuffers are by default allocated as direct byte buffers. To use non-direct
30   * ByteBuffers, set system property mina.sslfilter.directbuffer to false.
31   *
32   * @author Jan Andersson (janne@minq.se)
33   * @version $Rev: 210062 $, $Date: 2005-07-11 12:52:38 +0900 $
34   */
35  class SSLByteBufferPool
36  {
37      private static final int PACKET_BUFFER_INDEX = 0;
38  
39      private static final int APPLICATION_BUFFER_INDEX = 1;
40  
41      private static boolean initiated = false;
42  
43      private static final String DIRECT_MEMORY_PROP = "mina.sslfilter.directbuffer";
44  
45      private static boolean useDirectAllocatedBuffers = true;
46  
47      private static int packetBufferSize;
48  
49      private static int appBufferSize;
50  
51      private static int[] bufferStackSizes;
52  
53      private static final Stack[] bufferStacks = new Stack[] { new Stack(),
54                                                               new Stack(), };
55  
56      /***
57       * Initiate buffer pool and buffer sizes from SSLEngine session.
58       *
59       * @param sslEngine SSLEngine
60       */
61      static synchronized void initiate( SSLEngine sslEngine )
62      {
63          if( !initiated )
64          {
65              // Use direct allocated memory or not?
66              String prop = System.getProperty( DIRECT_MEMORY_PROP );
67              if( prop != null )
68              {
69                  useDirectAllocatedBuffers = Boolean
70                          .getBoolean( DIRECT_MEMORY_PROP );
71              }
72              
73              // init buffer sizes from SSLEngine
74              packetBufferSize = sslEngine.getSession().getPacketBufferSize();
75  
76              // application buffer size has been doubled because SSLEngine
77              // returns BUFFER_OVERFLOW even if there is enough room for the buffer.
78              // So for now we use a size double the packet size as a workaround.
79              appBufferSize = packetBufferSize * 2;
80              initiateBufferStacks();
81              initiated = true;
82          }
83      }
84  
85      /***
86       * Get bytebuffer with size the size of the largest SSL/TLS packet that may occur
87       * (as defined by SSLSession).
88       */
89      static ByteBuffer getPacketBuffer()
90      {
91          if( !initiated )
92          {
93              throw new IllegalStateException( "Not initialized" );
94          }
95          return allocate( PACKET_BUFFER_INDEX );
96      }
97  
98      /***
99       * Get ByteBuffer with the size of the largest application buffer that may occur
100      * (as defined by SSLSession).
101      */
102     static ByteBuffer getApplicationBuffer()
103     {
104         if( !initiated )
105         {
106             throw new IllegalStateException( "Not initialized" );
107         }
108         return allocate( APPLICATION_BUFFER_INDEX );
109     }
110 
111     /***
112      * Allocate or get the buffer which is capable of the specified size.
113      */
114     private static ByteBuffer allocate( int idx )
115     {
116         Stack stack = bufferStacks[ idx ];
117 
118         ByteBuffer buf;
119         synchronized( stack )
120         {
121             buf = ( ByteBuffer ) stack.pop();
122             if( buf == null )
123             {
124                 buf = createBuffer( bufferStackSizes[ idx ] );
125             }
126         }
127 
128         buf.clear();
129         return buf;
130     }
131 
132     /***
133      * Releases the specified buffer to buffer pool.
134      */
135     public static void release( ByteBuffer buf )
136     {
137         int stackIndex =getBufferStackIndex( buf.capacity() );
138         if ( stackIndex >= PACKET_BUFFER_INDEX ) {
139             Stack stack = bufferStacks[getBufferStackIndex( buf.capacity() )];
140             synchronized ( stack ) {
141                 stack.push( buf );
142             }
143         }
144     }
145 
146     /***
147      * Expand size of provided buffer
148      * @param buf buffer to be expande
149      * @param newCapacity new capacity
150      */
151     public static ByteBuffer expandBuffer( ByteBuffer buf, int newCapacity )
152     {
153         ByteBuffer newBuf = createBuffer( newCapacity );
154         buf.flip();
155         newBuf.put( buf );
156         release(buf);
157         return newBuf;
158     }
159 
160     private static void initiateBufferStacks()
161     {
162         bufferStackSizes = new int[ 2 ];
163         bufferStackSizes[ PACKET_BUFFER_INDEX ] = packetBufferSize;
164         bufferStackSizes[ APPLICATION_BUFFER_INDEX ] = appBufferSize;
165     }
166 
167     private static int getBufferStackIndex( int size )
168     {
169         if( size == packetBufferSize )
170             return PACKET_BUFFER_INDEX;
171         if( size == appBufferSize )
172             return APPLICATION_BUFFER_INDEX;
173         return -1;  // not reused
174     }
175 
176     private static ByteBuffer createBuffer( int capacity )
177     {
178         if( useDirectAllocatedBuffers )
179         {
180             try
181             {
182                 return ByteBuffer.allocateDirect( capacity );
183             }
184             catch( OutOfMemoryError e )
185             {
186                 useDirectAllocatedBuffers = false;
187                 System.err
188                         .println( "OutOfMemoryError: No more direct buffers available; trying heap buffer instead" );
189             }
190         }
191         return ByteBuffer.allocate( capacity );
192     }
193 
194 }