/* * 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.mailslot; import org.alfresco.filesys.util.DataPacker; /** * SMB Mailslot Packet Class */ public class SMBMailslotPacket { // SMB packet offsets public static final int SIGNATURE = 0; public static final int COMMAND = 4; public static final int ERRORCODE = 5; public static final int ERRORCLASS = 5; public static final int ERROR = 7; public static final int FLAGS = 9; public static final int FLAGS2 = 10; public static final int PIDHIGH = 12; public static final int SID = 18; public static final int SEQNO = 20; public static final int TID = 24; public static final int PID = 26; public static final int UID = 28; public static final int MID = 30; public static final int WORDCNT = 32; public static final int ANDXCOMMAND = 33; public static final int ANDXRESERVED= 34; public static final int PARAMWORDS = 33; // SMB packet header length for a transaction type request public static final int TRANS_HEADERLEN = 66; // Minimum receive length for a valid SMB packet public static final int MIN_RXLEN = 32; // Default buffer size to allocate for SMB mailslot packets public static final int DEFAULT_BUFSIZE = 500; // Flag bits public static final int FLG_SUBDIALECT = 0x01; public static final int FLG_CASELESS = 0x08; public static final int FLG_CANONICAL = 0x10; public static final int FLG_OPLOCK = 0x20; public static final int FLG_NOTIFY = 0x40; public static final int FLG_RESPONSE = 0x80; // Flag2 bits public static final int FLG2_LONGFILENAMES = 0x0001; public static final int FLG2_EXTENDEDATTRIB = 0x0002; public static final int FLG2_READIFEXE = 0x2000; public static final int FLG2_LONGERRORCODE = 0x4000; public static final int FLG2_UNICODE = 0x8000; // SMB packet buffer and offset private byte[] m_smbbuf; private int m_offset; // Define the number of standard parameters for a server response private static final int STD_PARAMS = 14; // SMB packet types we expect to receive in a mailslot public static final int Transaction = 0x25; public static final int Transaction2 = 0x32; /** * Default constructor */ public SMBMailslotPacket() { m_smbbuf = new byte[DEFAULT_BUFSIZE]; m_offset = 0; } /** * Class constructor * * @param buf byte[] */ public SMBMailslotPacket(byte[] buf) { m_smbbuf = buf; m_offset = 0; } /** * Class constructor * * @param buf byte[] * @param off int */ public SMBMailslotPacket(byte[] buf, int off) { m_smbbuf = buf; m_offset = off; } /** * Reset the mailslot packet to use the specified buffer and offset * * @param buf byte[] * @param offset int */ public final void resetPacket(byte[] buf, int offset) { m_smbbuf = buf; m_offset = offset; } /** * Get the secondary command code * * @return Secondary command code */ public final int getAndXCommand() { return (int) (m_smbbuf[ANDXCOMMAND + m_offset] & 0xFF); } /** * Return the byte array used for the SMB packet * * @return Byte array used for the SMB packet. */ public final byte[] getBuffer() { return m_smbbuf; } /** * Return the total buffer size available to the SMB request * * @return Total SMB buffer length available. */ public final int getBufferLength() { return m_smbbuf.length - m_offset; } /** * Get the data byte count for the SMB packet * * @return Data byte count */ public final int getByteCount() { // Calculate the offset of the byte count int pos = PARAMWORDS + (2 * getParameterCount()); return (int) DataPacker.getIntelShort(m_smbbuf, pos); } /** * Get the data byte area offset within the SMB packet * * @return Data byte offset within the SMB packet. */ public final int getByteOffset() { // Calculate the offset of the byte buffer int pCnt = getParameterCount(); int pos = WORDCNT + (2 * pCnt) + 3 + m_offset; return pos; } /** * Get the SMB command * * @return SMB command code. */ public final int getCommand() { return (int) (m_smbbuf[COMMAND + m_offset] & 0xFF); } /** * Determine if normal or long error codes have been returned * * @return boolean */ public final boolean hasLongErrorCode() { if ((getFlags2() & FLG2_LONGERRORCODE) == 0) return false; return true; } /** * Get the SMB error class * * @return SMB error class. */ public final int getErrorClass() { return (int) m_smbbuf[ERRORCLASS + m_offset] & 0xFF; } /** * Get the SMB error code * * @return SMB error code. */ public final int getErrorCode() { return (int) m_smbbuf[ERROR + m_offset] & 0xFF; } /** * Get the SMB flags value. * * @return SMB flags value. */ public final int getFlags() { return (int) m_smbbuf[FLAGS + m_offset] & 0xFF; } /** * Get the SMB flags2 value. * * @return SMB flags2 value. */ public final int getFlags2() { return (int) DataPacker.getIntelShort(m_smbbuf, FLAGS2 + m_offset); } /** * Calculate the total used packet length. * * @return Total used packet length. */ public final int getLength() { return (getByteOffset() + getByteCount()) - m_offset; } /** * Get the long SMB error code * * @return Long SMB error code. */ public final int getLongErrorCode() { return DataPacker.getIntelInt(m_smbbuf, ERRORCODE + m_offset); } /** * Get the multiplex identifier. * * @return Multiplex identifier. */ public final int getMultiplexId() { return DataPacker.getIntelShort(m_smbbuf, MID + m_offset); } /** * Get a parameter word from the SMB packet. * * @param idx Parameter index (zero based). * @return Parameter word value. * @exception java.lang.IndexOutOfBoundsException If the parameter index is out of range. */ public final int getParameter(int idx) throws java.lang.IndexOutOfBoundsException { // Range check the parameter index if (idx > getParameterCount()) throw new java.lang.IndexOutOfBoundsException(); // Calculate the parameter word offset int pos = WORDCNT + (2 * idx) + 1 + m_offset; return (int) (DataPacker.getIntelShort(m_smbbuf, pos) & 0xFFFF); } /** * Get the parameter count * * @return Parameter word count. */ public final int getParameterCount() { return (int) m_smbbuf[WORDCNT + m_offset]; } /** * Get the process indentifier (PID) * * @return Process identifier value. */ public final int getProcessId() { return DataPacker.getIntelShort(m_smbbuf, PID + m_offset); } /** * Get the tree identifier (TID) * * @return Tree identifier (TID) */ public final int getTreeId() { return DataPacker.getIntelShort(m_smbbuf, TID + m_offset); } /** * Get the user identifier (UID) * * @return User identifier (UID) */ public final int getUserId() { return DataPacker.getIntelShort(m_smbbuf, UID + m_offset); } /** * 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 and parameter block length have been set. * * @return int Offset to the data block area. */ public final int getDataBlockOffset() { // Get the position of the parameter block int pos = (getParameterBlockOffset() + getParameter(3)) + m_offset; if ((pos & 0x01) != 0) pos++; return pos; } /** * 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 parameter block offset where the parameter bytes should be placed. This method * must be called after the paramter count has been set. The parameter offset is word aligned. * * @return int Offset to the parameter block area. */ public final int getParameterBlockOffset() { // Get the offset to the byte buffer area of the SMB packet int pos = getByteOffset() + m_offset; 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) + m_offset; } /** * 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 return getParameter(10) + m_offset; } /** * 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. * @return int */ public final String getRxParameterString(int pos) { // 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); } /** * Get the required transact parameter string. * * @param pos Offset to the string within the parameter block. * @param len Length of the string. * @return int */ public final String getRxParameterString(int pos, int len) { // Get the parameter block offset pos += getRxParameterBlock(); // Get the transact parameter string byte[] buf = getBuffer(); return DataPacker.getString(buf, pos, len); } /** * Return the received transaction name. * * @return java.lang.String */ public final String getRxTransactName() { // Check if the transaction has a name if (getCommand() == Transaction2) return ""; // Unpack the transaction name string int pos = getByteOffset(); return DataPacker.getString(getBuffer(), pos, getByteCount()); } /** * Return the specified transaction setup parameter. * * @param idx Setup parameter index. */ public final int getSetupParameter(int idx) throws java.lang.ArrayIndexOutOfBoundsException { // 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 mailslot opcode * * @return int */ public final int getMailslotOpcode() { try { return getSetupParameter(0); } catch (ArrayIndexOutOfBoundsException ex) { } return -1; } /** * Return the mailslot priority * * @return int */ public final int getMailslotPriority() { try { return getSetupParameter(1); } catch (ArrayIndexOutOfBoundsException ex) { } return -1; } /** * Return the mailslot class of service * * @return int */ public final int getMailslotClass() { try { return getSetupParameter(2); } catch (ArrayIndexOutOfBoundsException ex) { } return -1; } /** * Return the mailslot sub-opcode, the first byte from the mailslot data * * @return int */ public final int getMailslotSubOpcode() { return (int) (m_smbbuf[getMailslotDataOffset()] & 0xFF); } /** * Return the mailslot data offset * * @return int */ public final int getMailslotDataOffset() { return getRxDataBlock(); } /** * Initialize a mailslot SMB * * @param name Mailslot name * @param data Request data bytes * @param dlen Data length */ public final void initializeMailslotSMB(String name, byte[] data, int dlen) { // Initialize the SMB packet header initializeBuffer(); // Clear header values setFlags(0); setFlags2(0); setUserId(0); setMultiplexId(0); setTreeId(0); setProcessId(0); // Initialize the transaction initializeTransact(name, 17, null, 0, data, dlen); // Initialize the transactin setup parameters for a mailslot write setSetupParameter(0, MailSlot.WRITE); setSetupParameter(1, 1); setSetupParameter(2, MailSlot.UNRELIABLE); } /** * Initialize the transact SMB packet * * @param name Transaction name * @param pcnt Total parameter count for this transaction * @param paramblk Parameter block data bytes * @param plen Parameter block data length * @param datablk Data block data bytes * @param dlen Data block data length */ protected final void initializeTransact(String name, int pcnt, byte[] paramblk, int plen, byte[] datablk, int dlen) { // Set the SMB command code if (name == null) setCommand(Transaction2); else setCommand(Transaction); // Set the parameter count setParameterCount(pcnt); // Initialize the parameters setParameter(0, plen); // total parameter bytes being sent setParameter(1, dlen); // total data bytes being sent for (int i = 2; i < 9; setParameter(i++, 0)) ; setParameter(6, 1000); // timeout 1 second setParameter(9, plen); // parameter bytes sent in this packet setParameter(11, dlen); // data bytes sent in this packet setParameter(13, pcnt - STD_PARAMS); // number of setup words // Get the data byte offset int pos = getByteOffset(); int startPos = pos; // Check if this is a named transaction, if so then store the name int idx; byte[] buf = getBuffer(); if (name != null) { // Store the transaction name byte[] nam = name.getBytes(); for (idx = 0; idx < nam.length; idx++) buf[pos++] = nam[idx]; } // Word align the buffer offset if ((pos % 2) > 0) pos++; // Store the parameter block if (paramblk != null) { // Set the parameter block offset setParameter(10, pos - m_offset); // Store the parameter block for (idx = 0; idx < plen; idx++) buf[pos++] = paramblk[idx]; } else { // Clear the parameter block offset setParameter(10, 0); } // Word align the data block if ((pos % 2) > 0) pos++; // Store the data block if (datablk != null) { // Set the data block offset setParameter(12, pos - m_offset); // Store the data block for (idx = 0; idx < dlen; idx++) buf[pos++] = datablk[idx]; } else { // Zero the data block offset setParameter(12, 0); } // Set the byte count for the SMB packet setByteCount(pos - startPos); } /** * Set the secondary SMB command * * @param cmd Secondary SMB command code. */ public final void setAndXCommand(int cmd) { m_smbbuf[ANDXCOMMAND + m_offset] = (byte) cmd; m_smbbuf[ANDXRESERVED + m_offset] = (byte) 0; } /** * Set the data byte count for this SMB packet * * @param cnt Data byte count. */ public final void setByteCount(int cnt) { int offset = getByteOffset() - 2; DataPacker.putIntelShort(cnt, m_smbbuf, offset); } /** * Set the data byte area in the SMB packet * * @param byts Byte array containing the data to be copied to the SMB packet. */ public final void setBytes(byte[] byts) { int offset = getByteOffset() - 2; DataPacker.putIntelShort(byts.length, m_smbbuf, offset); offset += 2; for (int idx = 0; idx < byts.length; m_smbbuf[offset + idx] = byts[idx++]) ; } /** * Set the SMB command * * @param cmd SMB command code */ public final void setCommand(int cmd) { m_smbbuf[COMMAND + m_offset] = (byte) cmd; } /** * Set the SMB error class. * * @param cl SMB error class. */ public final void setErrorClass(int cl) { m_smbbuf[ERRORCLASS + m_offset] = (byte) (cl & 0xFF); } /** * Set the SMB error code * * @param sts SMB error code. */ public final void setErrorCode(int sts) { m_smbbuf[ERROR + m_offset] = (byte) (sts & 0xFF); } /** * Set the SMB flags value. * * @param flg SMB flags value. */ public final void setFlags(int flg) { m_smbbuf[FLAGS + m_offset] = (byte) flg; } /** * Set the SMB flags2 value. * * @param flg SMB flags2 value. */ public final void setFlags2(int flg) { DataPacker.putIntelShort(flg, m_smbbuf, FLAGS2 + m_offset); } /** * Set the multiplex identifier. * * @param mid Multiplex identifier */ public final void setMultiplexId(int mid) { DataPacker.putIntelShort(mid, m_smbbuf, MID + m_offset); } /** * Set the specified parameter word. * * @param idx Parameter index (zero based). * @param val Parameter value. */ public final void setParameter(int idx, int val) { int pos = WORDCNT + (2 * idx) + 1 + m_offset; DataPacker.putIntelShort(val, m_smbbuf, pos); } /** * Set the parameter count * * @param cnt Parameter word count. */ public final void setParameterCount(int cnt) { m_smbbuf[WORDCNT + m_offset] = (byte) cnt; } /** * Set the process identifier value (PID). * * @param pid Process identifier value. */ public final void setProcessId(int pid) { DataPacker.putIntelShort(pid, m_smbbuf, PID + m_offset); } /** * Set the packet sequence number, for connectionless commands. * * @param seq Sequence number. */ public final void setSeqNo(int seq) { DataPacker.putIntelShort(seq, m_smbbuf, SEQNO + m_offset); } /** * Set the session id. * * @param sid Session id. */ public final void setSID(int sid) { DataPacker.putIntelShort(sid, m_smbbuf, SID + m_offset); } /** * Set the tree identifier (TID) * * @param tid Tree identifier value. */ public final void setTreeId(int tid) { DataPacker.putIntelShort(tid, m_smbbuf, TID + m_offset); } /** * Set the user identifier (UID) * * @param uid User identifier value. */ public final void setUserId(int uid) { DataPacker.putIntelShort(uid, m_smbbuf, UID + m_offset); } /** * Set the specifiec setup parameter within the SMB packet. * * @param idx Setup parameter index. * @param val Setup parameter value. */ public final void setSetupParameter(int idx, int val) { setParameter(STD_PARAMS + idx, val); } /** * Initialize the SMB packet buffer. */ private final void initializeBuffer() { // Set the packet signature m_smbbuf[SIGNATURE + m_offset] = (byte) 0xFF; m_smbbuf[SIGNATURE + 1 + m_offset] = (byte) 'S'; m_smbbuf[SIGNATURE + 2 + m_offset] = (byte) 'M'; m_smbbuf[SIGNATURE + 3 + m_offset] = (byte) 'B'; } }