2005-12-08 07:13:07 +00:00

838 lines
21 KiB
Java

/*
* Copyright (C) 2005 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.filesys.smb.server;
import java.io.IOException;
import org.alfresco.filesys.netbios.RFCNetBIOSProtocol;
import org.alfresco.filesys.smb.PacketType;
import org.alfresco.filesys.smb.TransactBuffer;
import org.alfresco.filesys.util.DataBuffer;
import org.alfresco.filesys.util.DataPacker;
/**
* SMB server transact packet class
*/
class SMBSrvTransPacket extends SMBTransPacket
{
// Define the number of standard parameters for a server response
private static final int StandardParamsResponse = 10;
// Offset to the setup response paramaters
protected static final int SetupOffsetResponse = PARAMWORDS + (StandardParamsResponse * 2);
/**
* Construct an SMB transaction packet
*
* @param buf Buffer that contains the SMB transaction packet.
*/
public SMBSrvTransPacket(byte[] buf)
{
super(buf);
}
/**
* Construct an SMB transaction packet
*
* @param siz Size of packet to allocate.
*/
public SMBSrvTransPacket(int siz)
{
super(siz);
// Set the multiplex id for this transaction
setMultiplexId(getNextMultiplexId());
}
/**
* Initialize the transact reply parameters.
*
* @param pkt Reply SMB packet.
* @param prmCnt Count of returned parameter bytes.
* @param prmPos Starting offset to the parameter block.
* @param dataCnt Count of returned data bytes.
* @param dataPos Starting offset to the data block.
*/
public final static void initTransactReply(SMBSrvPacket pkt, int prmCnt, int prmPos, int dataCnt, int dataPos)
{
// Set the total parameter words
pkt.setParameterCount(10);
// Set the total parameter/data bytes
pkt.setParameter(0, prmCnt);
pkt.setParameter(1, dataCnt);
// Clear the reserved parameter
pkt.setParameter(2, 0);
// Set the parameter byte count/offset for this packet
pkt.setParameter(3, prmCnt);
pkt.setParameter(4, prmPos - RFCNetBIOSProtocol.HEADER_LEN);
// Set the parameter displacement
pkt.setParameter(5, 0);
// Set the data byte count/offset for this packet
pkt.setParameter(6, dataCnt);
pkt.setParameter(7, dataPos - RFCNetBIOSProtocol.HEADER_LEN);
// Set the data displacement
pkt.setParameter(8, 0);
// Set up word count
pkt.setParameter(9, 0);
}
/**
* Calculate the data item size from the data descriptor string.
*
* @param desc java.lang.String
* @return int
*/
protected final static int CalculateDataItemSize(String desc)
{
// Scan the data descriptor string and calculate the data item size
int len = 0;
int pos = 0;
while (pos < desc.length())
{
// Get the current data item type
char dtype = desc.charAt(pos++);
int dlen = 1;
// Check if a data length has been specified
if (pos < desc.length() && Character.isDigit(desc.charAt(pos)))
{
// Convert the data length string
int numlen = 1;
int numpos = pos + 1;
while (numpos < desc.length() && Character.isDigit(desc.charAt(numpos++)))
numlen++;
// Set the data length
dlen = Integer.parseInt(desc.substring(pos, pos + numlen));
// Update the descriptor string position
pos = numpos - 1;
}
// Convert the current data item
switch (dtype)
{
// Word (16 bit) data type
case 'W':
len += 2;
break;
// Integer (32 bit) data type
case 'D':
len += 4;
break;
// Byte data type, may be multiple bytes if 'B<n>'
case 'B':
len += dlen;
break;
// Null terminated string data type, offset into buffer only
case 'z':
len += 4;
break;
// Skip 'n' bytes in the buffer
case '.':
len += dlen;
break;
// Integer (32 bit) data type converted to a date/time value
case 'T':
len += 4;
break;
} // end switch data type
} // end while descriptor string
// Return the data length of each item
return len;
}
/**
* Return the offset to the data block within the SMB packet. The data block is word aligned
* within the byte buffer area of the SMB packet. This method must be called after the parameter
* count has been set.
*
* @param prmLen Parameter block length, in bytes.
* @return int Offset to the data block area.
*/
public final int getDataBlockOffset(int prmLen)
{
// Get the position of the parameter block
int pos = getParameterBlockOffset() + prmLen;
if ((pos & 0x01) != 0)
pos++;
return pos;
}
/**
* Return the data block offset.
*
* @return int Offset to data block within packet.
*/
public final int getRxDataBlock()
{
return getParameter(12) + RFCNetBIOSProtocol.HEADER_LEN;
}
/**
* Return the received transaction data block length.
*
* @return int
*/
public final int getRxDataBlockLength()
{
return getParameter(11);
}
/**
* Get the required transact parameter word (16 bit).
*
* @param prmIdx int
* @return int
*/
public final int getRxParameter(int prmIdx)
{
// Get the parameter block offset
int pos = getRxParameterBlock();
// Get the required transact parameter word.
pos += prmIdx * 2; // 16 bit words
return DataPacker.getIntelShort(getBuffer(), pos);
}
/**
* Return the position of the parameter block within the received packet.
*
* @param prmblk Array to unpack the parameter block words into.
*/
public final int getRxParameterBlock()
{
// Get the offset to the parameter words, add the NetBIOS header length
// to the offset.
return getParameter(10) + RFCNetBIOSProtocol.HEADER_LEN;
}
/**
* Return the received transaction parameter block length.
*
* @return int
*/
public final int getRxParameterBlockLength()
{
return getParameter(9);
}
/**
* Return the received transaction setup parameter count.
*
* @return int
*/
public final int getRxParameterCount()
{
return getParameterCount() - STD_PARAMS;
}
/**
* Get the required transact parameter int value (32-bit).
*
* @param prmIdx int
* @return int
*/
public final int getRxParameterInt(int prmIdx)
{
// Get the parameter block offset
int pos = getRxParameterBlock();
// Get the required transact parameter word.
pos += prmIdx * 2; // 16 bit words
return DataPacker.getIntelInt(getBuffer(), pos);
}
/**
* Get the required transact parameter string.
*
* @param pos Offset to the string within the parameter block.
* @param uni Unicode if true, else ASCII
* @return int
*/
public final String getRxParameterString(int pos, boolean uni)
{
// Get the parameter block offset
pos += getRxParameterBlock();
// Get the transact parameter string
byte[] buf = getBuffer();
int len = (buf[pos++] & 0x00FF);
return DataPacker.getString(buf, pos, len, uni);
}
/**
* Get the required transact parameter string.
*
* @param pos Offset to the string within the parameter block.
* @param len Length of the string.
* @param uni Unicode if true, else ASCII
* @return int
*/
public final String getRxParameterString(int pos, int len, boolean uni)
{
// Get the parameter block offset
pos += getRxParameterBlock();
// Get the transact parameter string
byte[] buf = getBuffer();
return DataPacker.getString(buf, pos, len, uni);
}
/**
* Return the received transaction name.
*
* @return java.lang.String
*/
public final String getRxTransactName()
{
// Check if the transaction has a name
if (getCommand() == PacketType.Transaction2)
return "";
// Unpack the transaction name string
int pos = getByteOffset();
return DataPacker.getString(getBuffer(), pos, getByteCount());
}
/**
* Return the setup parameter count
*
* @return int
*/
public final int getSetupCount()
{
return getParameter(13) & 0xFF;
}
/**
* Return the buffer offset to the setup parameters
*
* @return int
*/
public final int getSetupOffset()
{
return WORDCNT + 29; // 14 setup words + word count byte
}
/**
* Return the specified transaction setup parameter.
*
* @param idx Setup parameter index.
* @return int
*/
public final int getSetupParameter(int idx)
{
// Check if the setup parameter index is valid
if (idx >= getRxParameterCount())
throw new java.lang.ArrayIndexOutOfBoundsException();
// Get the setup parameter
return getParameter(idx + STD_PARAMS);
}
/**
* Return the maximum return paramater byte count
*
* @return int
*/
public final int getMaximumReturnParameterCount()
{
return getParameter(2);
}
/**
* Return the maximum return data byte count
*
* @return int
*/
public final int getMaximumReturnDataCount()
{
return getParameter(3);
}
/**
* Return the maximum return setup count
*
* @return int
*/
public final int getMaximumReturnSetupCount()
{
return getParameter(4);
}
/**
* Return the specified transaction setup parameter 32bit value.
*
* @param idx Setup parameter index.
* @return int
*/
public final int getSetupParameterInt(int idx)
{
// Check if the setup parameter index is valid
if (idx >= getRxParameterCount())
throw new java.lang.ArrayIndexOutOfBoundsException();
// Get the setup parameter
return getParameterLong(idx + STD_PARAMS);
}
/**
* Set the total parameter block length, in bytes
*
* @param cnt int
*/
public final void setTotalParameterCount(int cnt)
{
setParameter(0, cnt);
}
/**
* Set the total data block length, in bytes
*
* @param cnt int
*/
public final void setTotalDataCount(int cnt)
{
setParameter(1, cnt);
}
/**
* Set the parameter block count for this packet
*
* @param len int
*/
public final void setParameterBlockCount(int len)
{
setParameter(3, len);
}
/**
* Set the parameter block offset
*
* @param off int
*/
public final void setParameterBlockOffset(int off)
{
setParameter(4, off != 0 ? off - RFCNetBIOSProtocol.HEADER_LEN : 0);
}
/**
* Set the parameter block displacement within the total parameter block
*
* @param disp int
*/
public final void setParameterBlockDisplacement(int disp)
{
setParameter(5, disp);
}
/**
* Set the data block count for this packet
*
* @param len int
*/
public final void setDataBlockCount(int len)
{
setParameter(6, len);
}
/**
* Set the data block offset, from the start of the packet
*
* @param off int
*/
public final void setDataBlockOffset(int off)
{
setParameter(7, off != 0 ? off - RFCNetBIOSProtocol.HEADER_LEN : 0);
}
/**
* Set the data block displacement within the total data block
*
* @param disp int
*/
public final void setDataBlockDisplacement(int disp)
{
setParameter(8, disp);
}
/**
* Send one or more transaction response SMBs to the client
*
* @param sess SMBSrvSession
* @param tbuf TransactBuffer
* @exception java.io.IOException If an I/O error occurs.
*/
protected final void doTransactionResponse(SMBSrvSession sess, TransactBuffer tbuf) throws IOException
{
// Initialize the transaction response packet
setCommand(tbuf.isType());
// Get the individual buffers from the transact buffer
tbuf.setEndOfBuffer();
DataBuffer setupBuf = tbuf.getSetupBuffer();
DataBuffer paramBuf = tbuf.getParameterBuffer();
DataBuffer dataBuf = tbuf.getDataBuffer();
// Set the parameter count
if (tbuf.hasSetupBuffer())
setParameterCount(StandardParamsResponse + setupBuf.getLengthInWords());
else
setParameterCount(StandardParamsResponse);
// Clear the parameters
for (int i = 0; i < getParameterCount(); i++)
setParameter(i, 0);
// Get the total parameter/data block lengths
int totParamLen = paramBuf != null ? paramBuf.getLength() : 0;
int totDataLen = dataBuf != null ? dataBuf.getLength() : 0;
// Initialize the parameters
setTotalParameterCount(totParamLen);
setTotalDataCount(totDataLen);
// Get the available data space within the packet
int availBuf = getAvailableLength();
int clientLen = getAvailableLength(sess.getClientMaximumBufferSize());
if (availBuf > clientLen)
availBuf = clientLen;
// Check if the transaction parameter block and data block will fit within a single request
// packet
int plen = totParamLen;
int dlen = totDataLen;
if ((plen + dlen) > availBuf)
{
// Calculate the parameter/data block sizes to send in the first request packet
if (plen > 0)
{
// Check if the parameter block can fit into the packet
if (plen <= availBuf)
{
// Pack all of the parameter block and fill the remaining buffer with the data
// block
if (dlen > 0)
dlen = availBuf - plen;
}
else
{
// Split the parameter/data space in the packet
plen = availBuf / 2;
dlen = plen;
}
}
else if (dlen > availBuf)
{
// Fill the packet with the first section of the data block
dlen = availBuf;
}
}
// Set the parameter/data block counts for this packet
setParameterBlockCount(plen);
setDataBlockCount(dlen);
// Pack the setup bytes
if (setupBuf != null)
setupBuf.copyData(getBuffer(), SetupOffsetResponse);
// Pack the parameter block
int pos = DataPacker.wordAlign(getByteOffset());
setPosition(pos);
// Set the parameter block offset, from the start of the SMB packet
setParameterBlockCount(plen);
setParameterBlockOffset(pos);
int packLen = -1;
if (paramBuf != null)
{
// Pack the parameter block
packLen = paramBuf.copyData(getBuffer(), pos, plen);
// Update the buffer position for the data block
pos = DataPacker.longwordAlign(pos + packLen);
setPosition(pos);
}
// Set the data block offset
setDataBlockCount(dlen);
setDataBlockOffset(pos);
// Pack the data block
if (dataBuf != null)
{
// Pack the data block
packLen = dataBuf.copyData(getBuffer(), pos, dlen);
// Update the end of buffer position
setPosition(pos + packLen);
}
// Set the byte count for the SMB packet
setByteCount();
// Send the start of the transaction request
sess.sendResponseSMB(this);
// Get the available parameter/data block buffer space for the secondary packet
availBuf = getAvailableLength();
if (availBuf > clientLen)
availBuf = clientLen;
// Loop until all parameter/data block data has been sent to the server
TransactBuffer rxBuf = null;
while ((paramBuf != null && paramBuf.getAvailableLength() > 0)
|| (dataBuf != null && dataBuf.getAvailableLength() > 0))
{
// Setup the NT transaction secondary packet to send the remaining parameter/data blocks
setCommand(tbuf.isType());
// Get the remaining parameter/data block lengths
plen = paramBuf != null ? paramBuf.getAvailableLength() : 0;
dlen = dataBuf != null ? dataBuf.getAvailableLength() : 0;
if ((plen + dlen) > availBuf)
{
// Calculate the parameter/data block sizes to send in the first request packet
if (plen > 0)
{
// Check if the remaining parameter block can fit into the packet
if (plen <= availBuf)
{
// Pack all of the parameter block and fill the remaining buffer with the
// data block
if (dlen > 0)
dlen = availBuf - plen;
}
else
{
// Split the parameter/data space in the packet
plen = availBuf / 2;
dlen = plen;
}
}
else if (dlen > availBuf)
{
// Fill the packet with the first section of the data block
dlen = availBuf;
}
}
// Pack the parameter block data, if any
resetBytePointerAlign();
packLen = -1;
pos = getPosition();
if (plen > 0 && paramBuf != null)
{
// Set the parameter block offset, from the start of the SMB packet
setParameterBlockOffset(pos);
setParameterBlockCount(plen);
setParameterBlockDisplacement(paramBuf.getDisplacement());
// Pack the parameter block
packLen = paramBuf.copyData(getBuffer(), pos, plen);
// Update the buffer position for the data block
pos = DataPacker.wordAlign(pos + packLen);
setPosition(pos);
}
else
{
// No parameter data, clear the count/offset
setParameterBlockCount(0);
setParameterBlockOffset(pos);
}
// Pack the data block, if any
if (dlen > 0 && dataBuf != null)
{
// Set the data block offset
setDataBlockOffset(pos);
setDataBlockCount(dlen);
setDataBlockDisplacement(dataBuf.getDisplacement());
// Pack the data block
packLen = dataBuf.copyData(getBuffer(), pos, dlen);
// Update the end of buffer position
setPosition(pos + packLen);
}
else
{
// No data, clear the count/offset
setDataBlockCount(0);
setDataBlockOffset(pos);
}
// Set the byte count for the SMB packet to set the overall length
setByteCount();
// Send the transaction response packet
sess.sendResponseSMB(this);
}
}
}