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.filter.support;
    21
    22  import java.nio.ByteBuffer;
    23
    24  import javax.net.ssl.SSLEngine;
    25
    26  import org.apache.mina.util.Stack;
    27
    28  /**
    29   * Simple ByteBuffer pool used by SSLHandler.
    30   * ByteBuffers are by default allocated as direct byte buffers. To use non-direct
    31   * ByteBuffers, set system property mina.sslfilter.directbuffer to false.
    32   *
    33   * @author The Apache Directory Project (mina-dev@directory.apache.org)
    34   * @version $Rev: 555855 $, $Date: 2007-07-13 05:19:00 +0200 (Fri, 13 Jul 2007) $
    35   */
    36  class SSLByteBufferPool {
    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          if (!initiated) {
    63              // Use direct allocated memory or not?
    64              String prop = System.getProperty(DIRECT_MEMORY_PROP);
    65              if (prop != null) {
    66                  useDirectAllocatedBuffers = Boolean
    67                          .getBoolean(DIRECT_MEMORY_PROP);
    68              }
    69
    70              // init buffer sizes from SSLEngine
    71              packetBufferSize = sslEngine.getSession().getPacketBufferSize();
    72
    73              // application buffer size has been doubled because SSLEngine
    74              // returns BUFFER_OVERFLOW even if there is enough room for the buffer.
    75              // So for now we use a size double the packet size as a workaround.
    76              appBufferSize = packetBufferSize * 2;
    77              initiateBufferStacks();
    78              initiated = true;
    79          }
    80      }
    81
    82      /**
    83       * Get bytebuffer with size the size of the largest SSL/TLS packet that may occur
    84       * (as defined by SSLSession).
    85       */
    86      static ByteBuffer getPacketBuffer() {
    87          if (!initiated) {
    88              throw new IllegalStateException("Not initialized");
    89          }
    90          return allocate(PACKET_BUFFER_INDEX);
    91      }
    92
    93      /**
    94       * Get ByteBuffer with the size of the largest application buffer that may occur
    95       * (as defined by SSLSession).
    96       */
    97      static ByteBuffer getApplicationBuffer() {
    98          if (!initiated) {
    99              throw new IllegalStateException("Not initialized");
    100         }
    101         return allocate(APPLICATION_BUFFER_INDEX);
    102     }
    103
    104     /**
    105      * Allocate or get the buffer which is capable of the specified size.
    106      */
    107     private static ByteBuffer allocate(int idx) {
    108         Stack stack = bufferStacks[idx];
    109
    110         ByteBuffer buf;
    111         synchronized (stack) {
    112             buf = (ByteBuffer) stack.pop();
    113             if (buf == null) {
    114                 buf = createBuffer(bufferStackSizes[idx]);
    115             }
    116         }
    117
    118         buf.clear();
    119         return buf;
    120     }
    121
    122     /**
    123      * Releases the specified buffer to buffer pool.
    124      */
    125     public static void release(ByteBuffer buf) {
    126         // Sweep buffer for security.
    127         org.apache.mina.common.ByteBuffer.wrap(buf).sweep().release();
    128
    129         int stackIndex = getBufferStackIndex(buf.capacity());
    130         if (stackIndex >= PACKET_BUFFER_INDEX) {
    131             Stack stack = bufferStacks[getBufferStackIndex(buf.capacity())];
    132             synchronized (stack) {
    133                 stack.push(buf);
    134             }
    135         }
    136     }
    137
    138     /**
    139      * Expand size of provided buffer
    140      * @param buf buffer to be expande
    141      * @param newCapacity new capacity
    142      */
    143     public static ByteBuffer expandBuffer(ByteBuffer buf, int newCapacity) {
    144         ByteBuffer newBuf = createBuffer(newCapacity);
    145         buf.flip();
    146         newBuf.put(buf);
    147         release(buf);
    148         return newBuf;
    149     }
    150
    151     private static void initiateBufferStacks() {
    152         bufferStackSizes = new int[2];
    153         bufferStackSizes[PACKET_BUFFER_INDEX] = packetBufferSize;
    154         bufferStackSizes[APPLICATION_BUFFER_INDEX] = appBufferSize;
    155     }
    156
    157     private static int getBufferStackIndex(int size) {
    158         if (size == packetBufferSize)
    159             return PACKET_BUFFER_INDEX;
    160         if (size == appBufferSize)
    161             return APPLICATION_BUFFER_INDEX;
    162         return -1; // not reused
    163     }
    164
    165     private static ByteBuffer createBuffer(int capacity) {
    166         if (useDirectAllocatedBuffers) {
    167             try {
    168                 return ByteBuffer.allocateDirect(capacity);
    169             } catch (OutOfMemoryError e) {
    170                 useDirectAllocatedBuffers = false;
    171                 System.err
    172                         .println("OutOfMemoryError: No more direct buffers available; trying heap buffer instead");
    173             }
    174         }
    175         return ByteBuffer.allocate(capacity);
    176     }
    177
    178 }