/* * Copyright (C) 2005-2008 Alfresco, Inc. * * Licensed under the Mozilla Public License version 1.1 * with a permitted attribution clause. You may obtain a * copy of the License at * * http://www.alfresco.org/legal/license.txt * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific * language governing permissions and limitations under the * License. */ package org.alfresco.jlan.smb.server; import org.alfresco.jlan.debug.Debug; import org.alfresco.jlan.server.core.NoPooledMemoryException; import org.alfresco.jlan.server.memory.ByteBufferPool; /** * CIFs Packet Pool Class * * <p>Allocates buffers from the main byte buffer pool and wraps them in a CIFS specific packet. * * @author gkspencer */ public class CIFSPacketPool { // Constants public static final long CIFSAllocateWaitTime = 250; // milliseconds // Main byte buffer pool private ByteBufferPool m_bufferPool; // Debug enable private boolean m_debug; // Allow over sized packet allocations, maximum over sized packet size to allow private boolean m_allowOverSize = true; private int m_maxOverSize = 128 * 1024; // 128K // Maximum buffer size that the pool provides private int m_maxPoolBufSize; /** * Class constructor * * @param bufPool byteBufferPool */ public CIFSPacketPool( ByteBufferPool bufPool) { m_bufferPool = bufPool; // Set the maximum pooled buffer size m_maxPoolBufSize = m_bufferPool.getLargestSize(); } /** * Allocate a CIFS packet with the specified buffer size * * @param reqSiz int * @return SMBSrvPacket * @exception NoPooledMemoryException */ public final SMBSrvPacket allocatePacket( int reqSiz) throws NoPooledMemoryException { // Check if the buffer can be allocated from the pool byte[] buf = null; if ( reqSiz <= m_maxPoolBufSize) { // Allocate the byte buffer for the CIFS packet buf = m_bufferPool.allocateBuffer( reqSiz, CIFSAllocateWaitTime); } // Check if over sized allocations are allowed else if ( allowsOverSizedAllocations() && reqSiz <= getMaximumOverSizedAllocation()) { // DEBUG if ( Debug.EnableDbg && hasDebug()) Debug.println("[SMB] Allocating an over-sized packet, reqSiz=" + reqSiz); // Allocate an over sized packet buf = new byte[reqSiz]; } // Check if the buffer was allocated if ( buf == null) { // DEBUG if ( Debug.EnableDbg && hasDebug()) Debug.println("[SMB] CIFS Packet allocate failed, reqSiz=" + reqSiz); // Throw an exception, no memory available throw new NoPooledMemoryException( "Request size " + reqSiz); } // Create the CIFS packet return new SMBSrvPacket( buf); } /** * Allocate a CIFS packet with the specified buffer size, copy the header from the * request packet * * @param reqSiz int * @param reqPkt SMBSrvPacket * @return SMBSrvPacket * @exception NoPooledMemoryException */ public final SMBSrvPacket allocatePacket( int reqSiz, SMBSrvPacket reqPkt) throws NoPooledMemoryException { // Allocate a new packet, copy the standard header length return allocatePacket( reqSiz, reqPkt, -1); } /** * Allocate a CIFS packet with the specified buffer size, copy the header from the * request packet * * @param reqSiz int * @param reqPkt SMBSrvPacket * @param copyLen int * @return SMBSrvPacket * @exception NoPooledMemoryException */ public final SMBSrvPacket allocatePacket( int reqSiz, SMBSrvPacket reqPkt, int copyLen) throws NoPooledMemoryException { // Allocate the response packet SMBSrvPacket respPkt = allocatePacket( reqSiz); // Copy the header from the request to the response System.arraycopy( reqPkt.getBuffer(), 4, respPkt.getBuffer(), 4, copyLen == -1 ? SMBSrvPacket.HeaderLength : copyLen); // Attach the response packet to the request reqPkt.setAssociatedPacket( respPkt); // DEBUG if ( Debug.EnableDbg && hasDebug()) Debug.println("[SMB] Associated packet reqSiz=" + reqSiz + " with pktSiz=" + reqPkt.getBuffer().length); // Return the new packet return respPkt; } /** * Release a CIFS packet buffer back to the pool * * @param smbPkt SMBSrvPacket */ public final void releasePacket( SMBSrvPacket smbPkt) { // TEST // // Check if the packet is queued for async I/O if ( smbPkt.isQueuedForAsyncIO()) Debug.println("*** Packet queued for async I/O, pkt=" + smbPkt); // Check if the packet is an over sized packet, just let the garbage collector pick it up if ( smbPkt.getBuffer().length <= m_maxPoolBufSize) { // Release the buffer from the CIFS packet back to the pool m_bufferPool.releaseBuffer( smbPkt.getBuffer()); // DEBUG if ( Debug.EnableDbg && hasDebug() && smbPkt.hasAssociatedPacket() == false) Debug.println("[SMB] CIFS Packet released bufSiz=" + smbPkt.getBuffer().length); } else if ( Debug.EnableDbg && hasDebug()) Debug.println("[SMB] Over sized packet left for garbage collector"); // Check if the packet has an associated packet which also needs releasing if ( smbPkt.hasAssociatedPacket()) { // Check if the associated packet is using an over sized packet byte[] assocBuf = smbPkt.getAssociatedPacket().getBuffer(); if ( assocBuf.length <= m_maxPoolBufSize) { // Release the associated packets buffer back to the pool m_bufferPool.releaseBuffer( smbPkt.getAssociatedPacket().getBuffer()); // DEBUG if ( Debug.EnableDbg && hasDebug()) Debug.println("[SMB] CIFS Packet released bufSiz=" + smbPkt.getBuffer().length + " and assoc packet, bufSiz=" + smbPkt.getAssociatedPacket().getBuffer().length); } else if ( Debug.EnableDbg && hasDebug()) Debug.println("[SMB] Over sized associated packet left for garbage collector"); // Clear the associated packet smbPkt.clearAssociatedPacket(); } } /** * Return the length of the smallest packet size available * * @return int */ public final int getSmallestSize() { return m_bufferPool.getSmallestSize(); } /** * Return the length of the largest packet size available * * @return int */ public final int getLargestSize() { return m_bufferPool.getLargestSize(); } /** * Check if over sized packet allocations are allowed * * @return boolean */ public final boolean allowsOverSizedAllocations() { return m_allowOverSize; } /** * Return the maximum size of over sized packet that is allowed * * @return int */ public final int getMaximumOverSizedAllocation() { return m_maxOverSize; } /** * Enable/disable debug output * * @param ena boolean */ public final void setDebug( boolean ena) { m_debug = ena; } /** * Check if debug output is enabled * * @return boolean */ public final boolean hasDebug() { return m_debug; } /** * Enable/disable over sized packet allocations * * @param ena */ public final void setAllowOverSizedAllocations(boolean ena) { m_allowOverSize = ena; } /** * Return the packet pool details as a string * * @return String */ public String toString() { return m_bufferPool.toString(); } }