1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
66 String prop = System.getProperty( DIRECT_MEMORY_PROP );
67 if( prop != null )
68 {
69 useDirectAllocatedBuffers = Boolean
70 .getBoolean( DIRECT_MEMORY_PROP );
71 }
72
73
74 packetBufferSize = sslEngine.getSession().getPacketBufferSize();
75
76
77
78
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;
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 }