/// <summary>
        /// to decode stack packet from the received message bytes. 
        /// </summary>
        /// <param name = "endPoint">the endpoint from which the message bytes are received. </param>
        /// <param name = "messageBytes">the received message bytes to be decoded. </param>
        /// <param name = "consumedLength">the length of message bytes consumed by decoder. </param>
        /// <param name = "expectedLength">the length of message bytes the decoder expects to receive. </param>
        /// <returns>the stack packets decoded from the received message bytes. </returns>
        public StackPacket[] DecodePacketCallback(
            object endPoint,
            byte[] messageBytes,
            out int consumedLength,
            out int expectedLength)
        {
            // initialize the default values
            consumedLength = 0;
            expectedLength = 0;
            SmbPacket[] packets = new SmbPacket[0];

            SmbPacket request = this.DecodeSmbRequestFromBytes(messageBytes, out consumedLength);
            // Use the decoded packet to UpdateRoleContext if it is not null and ContextUpdate is enabled:
            if (request != null)
            {
                if (this.serverContext.IsContextUpdateEnabled)
                {
                    this.serverContext.UpdateRoleContext(this.serverContext.ConnectionTable[endPoint], request);
                }
                packets = new SmbPacket[] { request };
            }

            expectedLength = 0;
            return packets;
        }
        /// <summary>
        /// Deep copy constructor.
        /// </summary>
        /// <exception cref="System.ArgumentNullException">the smbPacket is null.</exception>
        protected SmbPacket(SmbPacket smbPacket)
            : base()
        {
            if (smbPacket == null)
            {
                throw new ArgumentNullException("smbPacket",
                    "the copy constructor of smbpacket can not accept null smbPacket.");
            }

            lock (smbPacket)
            {
                this.isSignatureCorrect = smbPacket.isSignatureCorrect;
                this.transportHeader = new TransportHeader();
                this.transportHeader.Zero = smbPacket.transportHeader.Zero;
                this.transportHeader.StreamProtocolLength = new byte[3];
                this.transportHeader.StreamProtocolLength = smbPacket.transportHeader.StreamProtocolLength;

                this.SmbHeader = new SmbHeader();
                this.smbHeader.Protocol = smbPacket.smbHeader.Protocol;
                this.smbHeader.Command = smbPacket.smbHeader.Command;
                this.smbHeader.Status = smbPacket.smbHeader.Status;
                this.smbHeader.Flags = smbPacket.smbHeader.Flags;
                this.smbHeader.Flags2 = smbPacket.smbHeader.Flags2;
                this.smbHeader.PidHigh = smbPacket.smbHeader.PidHigh;
                this.smbHeader.SecurityFeatures = smbPacket.smbHeader.SecurityFeatures;
                this.smbHeader.Reserved = smbPacket.smbHeader.Reserved;
                this.smbHeader.Tid = smbPacket.smbHeader.Tid;
                this.smbHeader.PidLow = smbPacket.smbHeader.PidLow;
                this.smbHeader.Uid = smbPacket.smbHeader.Uid;
                this.smbHeader.Mid = smbPacket.smbHeader.Mid;

                this.SmbParametersBlock = new SmbParameters();
                this.smbParametersBlock.WordCount = smbPacket.smbParametersBlock.WordCount;
                if (smbPacket.smbParametersBlock.Words != null)
                {
                    this.smbParametersBlock.Words = new ushort[smbPacket.smbParametersBlock.Words.Length];
                    Array.Copy(smbPacket.smbParametersBlock.Words,
                        this.smbParametersBlock.Words,
                        smbPacket.smbParametersBlock.Words.Length);
                }
                else
                {
                    this.smbParametersBlock.Words = new ushort[0];
                }

                this.SmbDataBlock = new SmbData();
                this.smbDataBlock.ByteCount = smbPacket.smbDataBlock.ByteCount;
                if (smbPacket.smbDataBlock.Bytes != null)
                {
                    this.smbDataBlock.Bytes = new byte[smbPacket.smbDataBlock.Bytes.Length];
                    Array.Copy(smbPacket.smbDataBlock.Bytes,
                        this.smbDataBlock.Bytes,
                        smbPacket.smbDataBlock.Bytes.Length);
                }
                else
                {
                    this.smbDataBlock.Bytes = new byte[0];
                }
            }
        }
 /// <summary>
 /// Deep copy constructor.
 /// </summary>
 protected SmbBatchedRequestPacket(SmbBatchedRequestPacket packet)
     : base(packet)
 {
     lock (packet)
     {
         if (packet.andxPacket != null)
         {
             this.andxPacket = packet.AndxPacket.Clone() as SmbPacket;
         }
     }
 }
        /// <summary>
        /// this function will be invoked every time a packet is sent or received. all logics about 
        /// Client' states will be implemented here.
        /// response packet update the context, do regular transaction.
        /// </summary>
        /// <param name="connection">the connection object.</param>
        /// <param name="packet">the sent or received packet in stack transport.</param>
        protected virtual void ResponsePacketUpdateRoleContextRegular(Connection connection, SmbPacket packet)
        {
            int connectionId = connection.ConnectionId;

            #region RemoveOutstandingRequest
            if (packet.SmbHeader.Status != 0
                ||!(packet is SmbTransactionInterimResponsePacket
                    || packet is SmbTransaction2InterimResponsePacket
                    || packet is SmbNtTransactInterimResponsePacket
                    || packet is SmbWriteRawInterimResponsePacket))
            {
                this.RemoveOutstandingRequest(connectionId, (ulong)packet.SmbHeader.Mid);
            }
            #endregion

            #region RemoveSequenceNumber

            this.RemoveSequenceNumber(connectionId, packet);
            #endregion
        }
 /// <summary>
 /// remove the sequence number.
 /// </summary>
 /// <param name="response">the last response packet.</param>
 /// <exception cref="System.InvalidOperationException">the msg should be response.</exception>
 public void RemoveSequenceNumber(SmbPacket response)
 {
     this.serverSendSequenceNumbers.Remove(response.SmbHeader.Mid);
 }
        protected virtual void ResponsePacketUpdateRoleContext(
            CifsClientPerConnection connection,
            SmbPacket request,
            SmbPacket response)
        {
            int connectionId = connection.ConnectionId;

            if (request ==null | response == null)
            {
                return;
            }

            #region To update Connection/Session/Tree/Open with response

            // Update context with success response:
            if (response.SmbHeader.Status == 0)
            {
                CifsClientPerSession session = new CifsClientPerSession();
                CifsClientPerTreeConnect tree = new CifsClientPerTreeConnect();
                CifsClientPerOpenFile openFile = new CifsClientPerOpenFile();
                CifsClientPerOpenSearch openSearch = new CifsClientPerOpenSearch();
                switch (response.SmbHeader.Command)
                {
                    #region connection
                    case SmbCommand.SMB_COM_NEGOTIATE:
                        #region SMB_COM_NEGOTIATE
                        SmbNegotiateRequestPacket negotiateRequest = request as SmbNegotiateRequestPacket;
                        SmbNegotiateResponsePacket negotiateResponse = response as SmbNegotiateResponsePacket;
                        if (negotiateRequest == null || negotiateResponse == null)
                        {
                            break;
                        }
                        // base class Connection:
                        connection.NegotiateReceived = true;
                        // common ADM:
                        int dialectIndex = (int)(negotiateResponse.SmbParameters.DialectIndex);
                        byte[] dialectBytes = negotiateRequest.SmbData.Dialects;
                        int startIndex = 0;
                        for (int i = 0; i < dialectIndex; i++)
                        {
                            startIndex = Array.IndexOf<byte>(dialectBytes, 0, startIndex,
                                dialectBytes.Length - startIndex) + 1;
                        }
                        connection.SelectedDialect = CifsMessageUtils.ToSmbString(dialectBytes, startIndex, true);
                        // client ADM:
                        connection.ShareLevelAccessControl = ((negotiateResponse.SmbParameters.SecurityMode
                            & SecurityModes.NEGOTIATE_ENCRYPT_PASSWORDS) == SecurityModes.NONE);
                        connection.ServerChallengeResponse = ((negotiateResponse.SmbParameters.SecurityMode
                            & SecurityModes.NEGOTIATE_ENCRYPT_PASSWORDS)
                            == SecurityModes.NEGOTIATE_ENCRYPT_PASSWORDS);
                        if (connection.ServerChallengeResponse
                            && ((negotiateResponse.SmbParameters.SecurityMode
                            & SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_ENABLED)
                            == SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_ENABLED))
                        {
                            connection.ServerSigningState = SignStateValue.ENABLED;
                        }
                        if (connection.ServerSigningState == SignStateValue.ENABLED
                           && ((negotiateResponse.SmbParameters.SecurityMode
                           & SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)
                           == SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED))
                        {
                            connection.ServerSigningState = SignStateValue.REQUIRED;
                        }
                        connection.ServerCapabilities = negotiateResponse.SmbParameters.Capabilities;
                        connection.MaxBufferSize = negotiateResponse.SmbParameters.MaxBufferSize;
                        // negotiate response:
                        connection.SecurityMode = negotiateResponse.SmbParameters.SecurityMode;
                        connection.MaxMpxCount = negotiateResponse.SmbParameters.MaxMpxCount;
                        connection.MaxNumberVcs = negotiateResponse.SmbParameters.MaxNumberVcs;
                        connection.MaxRawSize = negotiateResponse.SmbParameters.MaxRawSize;
                        connection.SessionKey = negotiateResponse.SmbParameters.SessionKey;
                        connection.SystemTime = negotiateResponse.SmbParameters.SystemTime.Time;
                        connection.ServerTimeZone = negotiateResponse.SmbParameters.ServerTimeZone;
                        if (negotiateResponse.SmbData.Challenge != null
                            && negotiateResponse.SmbData.Challenge.Length >= 8)
                        {
                            connection.Challenge =
                                BitConverter.ToUInt64(negotiateResponse.SmbData.Challenge, 0);
                        }
                        if (negotiateResponse.SmbData.DomainName != null)
                        {
                            connection.DomainName = new byte[negotiateResponse.SmbData.DomainName.Length];
                            Array.Copy(negotiateResponse.SmbData.DomainName, connection.DomainName,
                                negotiateResponse.SmbData.DomainName.Length);
                        }
                        // stack sdk design:
                        connection.ConnectionState = StackTransportState.ConnectionEstablished;
                        // update:
                        this.AddOrUpdateConnection(connection);
                        #endregion
                        break;
                    #endregion

                    #region session
                    case SmbCommand.SMB_COM_SESSION_SETUP_ANDX:
                        #region SMB_COM_SESSION_SETUP_ANDX
                        SmbSessionSetupAndxRequestPacket sessionSetupRequest =
                            request as SmbSessionSetupAndxRequestPacket;
                        SmbSessionSetupAndxResponsePacket sessionSetupResponse =
                            response as SmbSessionSetupAndxResponsePacket;
                        if (sessionSetupRequest == null || sessionSetupResponse == null)
                        {
                            break;
                        }

                        session.ConnectionId = connectionId;
                        session.SessionId = (ulong)sessionSetupResponse.SmbHeader.Uid;
                        // in request:
                        session.SessionKey = sessionSetupRequest.ImplicitNtlmSessionKey;
                        session.MaxBufferSize = sessionSetupRequest.SmbParameters.MaxBufferSize;
                        session.MaxMpxCount = sessionSetupRequest.SmbParameters.MaxMpxCount;
                        session.VcNumber = sessionSetupRequest.SmbParameters.VcNumber;
                        session.SessionKeyOfNegotiated = sessionSetupRequest.SmbParameters.SessionKey;
                        session.Capabilities = sessionSetupRequest.SmbParameters.Capabilities;
                        if ((sessionSetupRequest.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) ==
                            SmbFlags2.SMB_FLAGS2_UNICODE)
                        {
                            session.UserAccount = new CifsUserAccount(
                                Encoding.Unicode.GetString(sessionSetupRequest.SmbData.PrimaryDomain),
                                Encoding.Unicode.GetString(sessionSetupRequest.SmbData.AccountName),
                                Encoding.Unicode.GetString(sessionSetupRequest.SmbData.OEMPassword));
                            session.ClientNativeOs =
                                Encoding.Unicode.GetString(sessionSetupRequest.SmbData.NativeOS);
                            session.ClientNativeLanMan =
                                Encoding.Unicode.GetString(sessionSetupRequest.SmbData.NativeLanMan);
                        }
                        else
                        {
                            session.UserAccount = new CifsUserAccount(
                                Encoding.ASCII.GetString(sessionSetupRequest.SmbData.PrimaryDomain),
                                Encoding.ASCII.GetString(sessionSetupRequest.SmbData.AccountName),
                                Encoding.ASCII.GetString(sessionSetupRequest.SmbData.OEMPassword));
                            session.ClientNativeOs =
                                Encoding.ASCII.GetString(sessionSetupRequest.SmbData.NativeOS);
                            session.ClientNativeLanMan =
                                Encoding.ASCII.GetString(sessionSetupRequest.SmbData.NativeLanMan);
                        }
                        // in response:
                        session.Action = sessionSetupResponse.SmbParameters.Action;
                        if ((sessionSetupResponse.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) ==
                            SmbFlags2.SMB_FLAGS2_UNICODE)
                        {
                            session.ServerNativeOs =
                                Encoding.Unicode.GetString(sessionSetupResponse.SmbData.NativeOS);
                            session.ServerNativeLanMan =
                                Encoding.Unicode.GetString(sessionSetupResponse.SmbData.NativeLanMan);
                            session.ServerPrimaryDomain =
                                Encoding.Unicode.GetString(sessionSetupResponse.SmbData.PrimaryDomain);
                        }
                        else
                        {
                            session.ServerNativeOs =
                                Encoding.ASCII.GetString(sessionSetupResponse.SmbData.NativeOS);
                            session.ServerNativeLanMan =
                                Encoding.ASCII.GetString(sessionSetupResponse.SmbData.NativeLanMan);
                            session.ServerPrimaryDomain =
                                Encoding.ASCII.GetString(sessionSetupResponse.SmbData.PrimaryDomain);
                        }

                        if (connection.ShareLevelAccessControl == false)
                        {
                            connection.IsSigningActive = true;
                            connection.ConnectionSigningSessionKey = sessionSetupRequest.ImplicitNtlmSessionKey;
                            connection.ConnectionSigningChallengeResponse = sessionSetupRequest.SmbData.UnicodePassword;
                            AddOrUpdateConnection(connection);
                        }

                        // update:
                        this.AddOrUpdateSession(session);
                        #endregion
                        break;

                    case SmbCommand.SMB_COM_LOGOFF_ANDX:
                        #region SMB_COM_LOGOFF_ANDX
                        SmbLogoffAndxResponsePacket logoffResponse = response as SmbLogoffAndxResponsePacket;
                        if (logoffResponse == null)
                        {
                            break;
                        }
                        this.RemoveSession(connectionId, (ulong)logoffResponse.SmbHeader.Uid);
                        #endregion
                        break;
                    #endregion

                    #region treeconnect
                    case SmbCommand.SMB_COM_TREE_CONNECT:
                        #region SMB_COM_TREE_CONNECT
                        SmbTreeConnectRequestPacket treeConnectRequest =
                            request as SmbTreeConnectRequestPacket;
                        SmbTreeConnectResponsePacket treeConnectResponse =
                            response as SmbTreeConnectResponsePacket;
                        if (treeConnectRequest == null || treeConnectResponse == null)
                        {
                            break;
                        }
                        tree.ConnectionId = connectionId;
                        tree.SessionId = (ulong)treeConnectResponse.SmbHeader.Uid;
                        tree.TreeId = (ulong)treeConnectResponse.SmbHeader.Tid;
                        tree.ShareName = CifsMessageUtils.ToSmbString(treeConnectRequest.SmbData.Path, 0, false);
                        int index = tree.ShareName.LastIndexOf(@"\");
                        if (index > 0)
                        {
                            tree.Share = tree.ShareName.Substring(index + 1);
                        }
                        else
                        {
                            tree.Share = tree.ShareName;
                        }
                        this.AddOrUpdateTreeConnect(tree);
                        #endregion
                        break;

                    case SmbCommand.SMB_COM_TREE_CONNECT_ANDX:
                        #region SMB_COM_TREE_CONNECT_ANDX
                        SmbTreeConnectAndxRequestPacket treeConnectAndxRequest =
                            request as SmbTreeConnectAndxRequestPacket;
                        SmbTreeConnectAndxResponsePacket treeConnectAndxResponse =
                            response as SmbTreeConnectAndxResponsePacket;
                        if (treeConnectAndxRequest == null || treeConnectAndxResponse == null)
                        {
                            break;
                        }
                        tree.ConnectionId = connectionId;
                        tree.SessionId = (ulong)treeConnectAndxResponse.SmbHeader.Uid;
                        tree.TreeId = (ulong)treeConnectAndxResponse.SmbHeader.Tid;
                        if ((treeConnectAndxRequest.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) ==
                            SmbFlags2.SMB_FLAGS2_UNICODE)
                        {
                            tree.ShareName = Encoding.Unicode.GetString(treeConnectAndxRequest.SmbData.Path);
                        }
                        else
                        {
                            tree.ShareName = Encoding.ASCII.GetString(treeConnectAndxRequest.SmbData.Path);
                        }
                        int IndexOfShare = tree.ShareName.LastIndexOf(@"\");
                        if (IndexOfShare > 0)
                        {
                            tree.Share = tree.ShareName.Substring(IndexOfShare + 1);
                        }
                        else
                        {
                            tree.Share = tree.ShareName;
                        }
                        this.AddOrUpdateTreeConnect(tree);
                        #endregion
                        break;

                    case SmbCommand.SMB_COM_TREE_DISCONNECT:
                        #region SMB_COM_TREE_DISCONNECT
                        SmbTreeDisconnectResponsePacket treeDisconnectResponse =
                            response as SmbTreeDisconnectResponsePacket;
                        if (treeDisconnectResponse == null)
                        {
                            break;
                        }
                        this.RemoveTreeConnect(connectionId,
                            (ulong)treeDisconnectResponse.SmbHeader.Uid,
                            (ulong)treeDisconnectResponse.SmbHeader.Tid);
                        #endregion
                        break;
                    #endregion

                    #region openfile
                    case SmbCommand.SMB_COM_OPEN:
                        #region SMB_COM_OPEN
                        SmbOpenRequestPacket openRequest = request as SmbOpenRequestPacket;
                        SmbOpenResponsePacket openResponse = response as SmbOpenResponsePacket;
                        if (openRequest == null || openResponse == null)
                        {
                            break;
                        }
                        openFile.ConnectionId = connectionId;
                        openFile.SessionId = (ulong)openResponse.SmbHeader.Uid;
                        openFile.TreeConnectId = (ulong)openResponse.SmbHeader.Tid;
                        openFile.FileHandle = openResponse.SmbParameters.FID;
                        openFile.FileName = CifsMessageUtils.ToSmbString(openRequest.SmbData.FileName, 0, false);
                        this.AddOrUpdateOpenFile(openFile);
                        #endregion
                        break;

                    case SmbCommand.SMB_COM_CREATE:
                        #region SMB_COM_CREATE
                        SmbCreateRequestPacket createRequest = request as SmbCreateRequestPacket;
                        SmbCreateResponsePacket createResponse = response as SmbCreateResponsePacket;
                        if (createRequest == null || createResponse == null)
                        {
                            break;
                        }
                        openFile.ConnectionId = connectionId;
                        openFile.SessionId = (ulong)createResponse.SmbHeader.Uid;
                        openFile.TreeConnectId = (ulong)createResponse.SmbHeader.Tid;
                        openFile.FileHandle = createResponse.SmbParameters.FID;
                        openFile.FileName = CifsMessageUtils.ToSmbString(createRequest.SmbData.FileName, 0, false);
                        this.AddOrUpdateOpenFile(openFile);
                        #endregion
                        break;

                    case SmbCommand.SMB_COM_CREATE_TEMPORARY:
                        #region SMB_COM_CREATE_TEMPORARY
                        SmbCreateTemporaryRequestPacket createTemporaryRequest =
                            request as SmbCreateTemporaryRequestPacket;
                        SmbCreateTemporaryResponsePacket createTemporaryResponse =
                            response as SmbCreateTemporaryResponsePacket;
                        if (createTemporaryRequest == null || createTemporaryResponse == null)
                        {
                            break;
                        }
                        openFile.ConnectionId = connectionId;
                        openFile.SessionId = (ulong)createTemporaryResponse.SmbHeader.Uid;
                        openFile.TreeConnectId = (ulong)createTemporaryResponse.SmbHeader.Tid;
                        openFile.FileHandle = createTemporaryResponse.SmbParameters.FID;
                        openFile.FileName = CifsMessageUtils.ToSmbString(
                            createTemporaryResponse.SmbData.TemporaryFileName, 0, false);
                        this.AddOrUpdateOpenFile(openFile);
                        #endregion
                        break;

                    case SmbCommand.SMB_COM_CREATE_NEW:
                        #region SMB_COM_CREATE_NEW
                        SmbCreateNewRequestPacket createNewRequest = request as SmbCreateNewRequestPacket;
                        SmbCreateNewResponsePacket createNewResponse = response as SmbCreateNewResponsePacket;
                        if (createNewRequest == null || createNewResponse == null)
                        {
                            break;
                        }
                        openFile.ConnectionId = connectionId;
                        openFile.SessionId = (ulong)createNewResponse.SmbHeader.Uid;
                        openFile.TreeConnectId = (ulong)createNewResponse.SmbHeader.Tid;
                        openFile.FileHandle = createNewResponse.SmbParameters.FID;
                        openFile.FileName = CifsMessageUtils.ToSmbString(createNewRequest.SmbData.FileName, 0, false);
                        this.AddOrUpdateOpenFile(openFile);
                        #endregion
                        break;

                    case SmbCommand.SMB_COM_OPEN_ANDX:
                        #region SMB_COM_OPEN_ANDX
                        SmbOpenAndxRequestPacket openAndxRequest = request as SmbOpenAndxRequestPacket;
                        SmbOpenAndxResponsePacket openAndxResponse = response as SmbOpenAndxResponsePacket;
                        if (openAndxRequest == null || openAndxResponse == null)
                        {
                            break;
                        }
                        openFile.ConnectionId = connectionId;
                        openFile.SessionId = (ulong)openAndxResponse.SmbHeader.Uid;
                        openFile.TreeConnectId = (ulong)openAndxResponse.SmbHeader.Tid;
                        openFile.FileHandle = openAndxResponse.SmbParameters.FID;
                        if ((openAndxRequest.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) ==
                            SmbFlags2.SMB_FLAGS2_UNICODE)
                        {
                            openFile.FileName = Encoding.Unicode.GetString(openAndxRequest.SmbData.FileName);
                        }
                        else
                        {
                            openFile.FileName = Encoding.ASCII.GetString(openAndxRequest.SmbData.FileName);
                        }
                        this.AddOrUpdateOpenFile(openFile);
                        #endregion

                        //save FID for chained response like:
                        //treeConnect->openAndx->readAndx->close
                        //when "close", FID is need to close the open opened in openAndx.
                        if (openAndxResponse.AndxPacket != null)
                        {
                            //borrow smbHeader.Protocol to save FID for later process.
                            //smbHeader.Protocol also use a flag to differentiate a single packet from a
                            //batched andx packet.
                            //FID is ushort, impossible to impact smbHeader.Protocol's usage as
                            //a real packet header 0x424D53FF(0xFF, 'S', 'M', 'B')
                            SmbHeader andxHeader = openAndxResponse.AndxPacket.SmbHeader;
                            andxHeader.Protocol = openAndxResponse.SmbParameters.FID;
                            openAndxResponse.AndxPacket.SmbHeader = andxHeader;
                        }
                        break;

                    case SmbCommand.SMB_COM_NT_CREATE_ANDX:
                        #region SMB_COM_NT_CREATE_ANDX
                        SmbNtCreateAndxRequestPacket ntCreateAndxRequest =
                            request as SmbNtCreateAndxRequestPacket;
                        SmbNtCreateAndxResponsePacket ntCreateAndxResponse =
                            response as SmbNtCreateAndxResponsePacket;
                        if (ntCreateAndxRequest == null || ntCreateAndxResponse == null)
                        {
                            break;
                        }
                        openFile.ConnectionId = connectionId;
                        openFile.SessionId = (ulong)ntCreateAndxResponse.SmbHeader.Uid;
                        openFile.TreeConnectId = (ulong)ntCreateAndxResponse.SmbHeader.Tid;
                        openFile.FileHandle = ntCreateAndxResponse.SmbParameters.FID;
                        if ((ntCreateAndxRequest.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) ==
                            SmbFlags2.SMB_FLAGS2_UNICODE)
                        {
                            openFile.FileName = Encoding.Unicode.GetString(ntCreateAndxRequest.SmbData.FileName);
                        }
                        else
                        {
                            openFile.FileName = Encoding.ASCII.GetString(ntCreateAndxRequest.SmbData.FileName);
                        }
                        this.AddOrUpdateOpenFile(openFile);
                        #endregion
                        break;

                    case SmbCommand.SMB_COM_OPEN_PRINT_FILE:
                        #region SMB_COM_OPEN_PRINT_FILE
                        SmbOpenPrintFileRequestPacket openPrintFileRequest =
                            request as SmbOpenPrintFileRequestPacket;
                        SmbOpenPrintFileResponsePacket openPrintFileResponse =
                            response as SmbOpenPrintFileResponsePacket;
                        if (openPrintFileRequest == null || openPrintFileResponse == null)
                        {
                            break;
                        }
                        openFile.ConnectionId = connectionId;
                        openFile.SessionId = (ulong)openPrintFileResponse.SmbHeader.Uid;
                        openFile.TreeConnectId = (ulong)openPrintFileResponse.SmbHeader.Tid;
                        openFile.FileHandle = openPrintFileResponse.SmbParameters.FID;
                        openFile.FileName = CifsMessageUtils.ToSmbString(
                            openPrintFileRequest.SmbData.Identifier, 0, false);
                        this.AddOrUpdateOpenFile(openFile);
                        #endregion
                        break;

                    case SmbCommand.SMB_COM_TRANSACTION2:
                        #region Trans2Open2
                        SmbTrans2Open2RequestPacket trans2Open2Request =
                            request as SmbTrans2Open2RequestPacket;
                        SmbTrans2Open2FinalResponsePacket trans2Open2Response =
                            response as SmbTrans2Open2FinalResponsePacket;
                        if (trans2Open2Request != null && trans2Open2Response != null)
                        {
                            openFile.ConnectionId = connectionId;
                            openFile.SessionId = (ulong)trans2Open2Response.SmbHeader.Uid;
                            openFile.TreeConnectId = (ulong)trans2Open2Response.SmbHeader.Tid;
                            openFile.FileHandle = trans2Open2Response.Trans2Parameters.Fid;
                            if ((trans2Open2Request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) ==
                                SmbFlags2.SMB_FLAGS2_UNICODE)
                            {
                                openFile.FileName = Encoding.Unicode.GetString(
                                    trans2Open2Request.Trans2Parameters.FileName);
                            }
                            else
                            {
                                openFile.FileName = Encoding.ASCII.GetString(
                                    trans2Open2Request.Trans2Parameters.FileName);
                            }
                            this.AddOrUpdateOpenFile(openFile);
                            break;
                        }
                        #endregion

                        #region Trans2FindFirst2
                        SmbTrans2FindFirst2RequestPacket trans2FindFirst2Request =
                            request as SmbTrans2FindFirst2RequestPacket;
                        SmbTrans2FindFirst2FinalResponsePacket trans2FindFirst2Response =
                            response as SmbTrans2FindFirst2FinalResponsePacket;
                        if (trans2FindFirst2Request != null && trans2FindFirst2Response != null)
                        {
                            openSearch.ConnectionId = connectionId;
                            openSearch.SessionId = (ulong)trans2FindFirst2Response.SmbHeader.Uid;
                            openSearch.TreeConnectId = (ulong)trans2FindFirst2Response.SmbHeader.Tid;
                            openSearch.SearchID = trans2FindFirst2Response.Trans2Parameters.SID;
                            if ((trans2FindFirst2Request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) ==
                                SmbFlags2.SMB_FLAGS2_UNICODE)
                            {
                                openSearch.SearchName = Encoding.Unicode.GetString(
                                    trans2FindFirst2Request.Trans2Parameters.FileName);
                            }
                            else
                            {
                                openSearch.SearchName = Encoding.ASCII.GetString(
                                    trans2FindFirst2Request.Trans2Parameters.FileName);
                            }
                            this.AddOrUpdateOpenSearch(openSearch);
                            break;
                        }
                        #endregion
                        break;

                    case SmbCommand.SMB_COM_WRITE_AND_CLOSE:
                        #region SMB_COM_WRITE_AND_CLOSE
                        SmbWriteAndCloseRequestPacket writeAndCloseRequest =
                            request as SmbWriteAndCloseRequestPacket;
                        if (writeAndCloseRequest == null)
                        {
                            break;
                        }
                        this.RemoveOpenFile(connectionId, (ulong)response.SmbHeader.Uid,
                            (ulong)response.SmbHeader.Tid, writeAndCloseRequest.SmbParameters.FID);
                        #endregion
                        break;

                    case SmbCommand.SMB_COM_CLOSE:
                        #region SMB_COM_CLOSE
                        // Get FID from CLOSE request.
                        // If fail, then get FID from the Batched Request.
                        // If still fail, then Get FID from the Batched Response.
                        ushort closeFId = 0;
                        SmbCloseRequestPacket closeRequest = request as SmbCloseRequestPacket;
                        if (closeRequest != null)
                        {
                            //Neither SMB_PROTOCOL_IDENTIFIER, or SMB_PROTOCOL_ANDXPACKET, then must be a FID
                            if (response.SmbHeader.Protocol != CifsMessageUtils.SMB_PROTOCOL_IDENTIFIER
                                && response.SmbHeader.Protocol != CifsMessageUtils.SMB_PROTOCOL_ANDXPACKET)
                            {
                                closeFId = (ushort)response.SmbHeader.Protocol;
                            }
                            else
                            {
                                closeFId = closeRequest.SmbParameters.FID;
                            }
                            this.RemoveOpenFile(connectionId, (ulong)response.SmbHeader.Uid,
                                (ulong)response.SmbHeader.Tid, closeFId);
                        }

                        #endregion
                        break;
                    #endregion

                    #region opensearch
                    case SmbCommand.SMB_COM_FIND_CLOSE2:
                        #region SMB_COM_FIND_CLOSE2
                        SmbFindClose2RequestPacket findClose2Request =
                            request as SmbFindClose2RequestPacket;
                        if (findClose2Request == null)
                        {
                            break;
                        }
                        this.RemoveOpenSearch(connectionId, (ulong)response.SmbHeader.Uid,
                            (ulong)response.SmbHeader.Tid, findClose2Request.SmbParameters.SearchHandle);
                        #endregion
                        break;
                    #endregion

                    default:
                        // No Connection/Session/Tree/Open will be updated if other types of response.
                        break;
                }

                SmbBatchedRequestPacket smbBatchedRequest = request as SmbBatchedRequestPacket;
                SmbBatchedResponsePacket smbBatchedResponse = response as SmbBatchedResponsePacket;

                if (smbBatchedRequest != null && smbBatchedResponse != null)
                {
                    //pass the FID stored in the andxHeader.Protocol into response.AndxPacket
                    if (smbBatchedRequest.AndxPacket != null && smbBatchedResponse.AndxPacket != null
                        && response.SmbHeader.Protocol != CifsMessageUtils.SMB_PROTOCOL_ANDXPACKET
                        && response.SmbHeader.Protocol != CifsMessageUtils.SMB_PROTOCOL_IDENTIFIER)
                    {
                        SmbHeader andxHeader = smbBatchedResponse.AndxPacket.SmbHeader;
                        andxHeader.Protocol = smbBatchedResponse.SmbHeader.Protocol;
                        smbBatchedResponse.AndxPacket.SmbHeader = andxHeader;
                    }
                    this.ResponsePacketUpdateRoleContext(connection, smbBatchedRequest.AndxPacket,
                        smbBatchedResponse.AndxPacket);
                }
            }
            #endregion
        }
 /// <summary>
 /// to read the andx packet from the channel
 /// </summary>
 /// <param name="channel">the channel started with the SmbParameters of the andx.</param>
 /// <returns>the size in bytes of the SmbParameters, SmbData and andx if existed of the andx.</returns>
 internal int ReadAndxFromChannel(Channel channel)
 {
     int consumedLen = 0;
     if (this.AndxCommand != SmbCommand.SMB_COM_NO_ANDX_COMMAND)
     {
         SmbHeader andxHeader = this.SmbHeader;
         andxHeader.Protocol = CifsMessageUtils.SMB_PROTOCOL_ANDXPACKET;
         andxHeader.Command = this.AndxCommand;
         this.andxPacket = CifsMessageUtils.CreateSmbRequestPacket(andxHeader, channel);
         this.andxPacket.SmbHeader = andxHeader;
         consumedLen += this.andxPacket.ReadParametersFromChannel(channel);
         consumedLen += this.andxPacket.ReadDataFromChannel(channel);
         SmbBatchedRequestPacket batchedRequest = this.andxPacket as SmbBatchedRequestPacket;
         if (batchedRequest != null)
         {
             consumedLen += batchedRequest.ReadAndxFromChannel(channel);
         }
     }
     return consumedLen;
 }
        /// <summary>
        /// to decode stack packet from the received message bytes.
        /// the message bytes contains data without transport information
        /// </summary>
        /// <param name = "connection">the connection from which the message bytes are received. </param>
        /// <param name = "packetBytesWithoutTransport">the received message bytes to be decoded. </param>
        /// <param name = "consumedLength">the length of message bytes consumed by decoder. </param>
        /// <param name = "expectedLength">the length of message bytes the decoder expects to receive. </param>
        /// <returns>the stack packets decoded from the received message bytes. </returns>
        /// <exception cref="InvalidOperationException">
        /// thrown when packet security signature is invalid.
        /// </exception>
        private SmbPacket[] DecodePacketFromBytesWithoutTransport(
            SmbServerConnection connection, byte[] packetBytesWithoutTransport,
            out int consumedLength, out int expectedLength)
        {
            expectedLength = 0;
            consumedLength = 0;
            SmbPacket[] packets = new SmbPacket[0];

            int packetConsumedLength = 0;
            int packetExpectedLength = 0;

            // decode packets using cifs decorder.
            SmbPacket request = this.DecodeSmbRequestFromBytes(
                packetBytesWithoutTransport, out packetConsumedLength);

            // valid the signature
            if (request != null && request.SmbHeader.SecurityFeatures != 0
                && connection.GssApi != null && connection.GssApi.SessionKey != null)
            {
                byte[] bytesToValid = ArrayUtility.SubArray(packetBytesWithoutTransport, 0);

                // the signature offset is 14.
                byte[] zeroSignature = new byte[sizeof(ulong)];
                Array.Copy(zeroSignature, 0, bytesToValid, 14, zeroSignature.Length);

                // the signature offset is 14.
                zeroSignature = BitConverter.GetBytes((ulong)connection.ServerNextReceiveSequenceNumber);
                Array.Copy(zeroSignature, 0, bytesToValid, 14, zeroSignature.Length);

                byte[] signature = CifsMessageUtils.CreateSignature(bytesToValid, connection.GssApi.SessionKey);
                if (request.SmbHeader.SecurityFeatures != BitConverter.ToUInt64(signature, 0))
                {
                    throw new InvalidOperationException("packet security signature is invalid");
                }
            }

            // Use the decoded packet to UpdateRoleContext if it is not null and ContextUpdate is enabled:
            if (request != null)
            {
                if (this.context.IsUpdateContext)
                {
                    this.context.UpdateRoleContext(connection, request);
                }
                packets = new SmbPacket[] { request };
            }

            // update the length after decode packet.
            consumedLength += packetConsumedLength;
            expectedLength += packetExpectedLength;

            return packets;
        }
 /// <summary>
 /// update the sequence number of a connection.
 /// </summary>
 /// <param name="connectionId">the connection identity.</param>
 /// <param name="msg">the last request packet.</param>
 private void UpdateSequenceNumber(int connectionId, SmbPacket msg)
 {
     lock (this.contextCollection)
     {
         for (int i = this.contextCollection.ConnectionList.Count - 1; i >= 0; i--)
         {
             if (this.contextCollection.ConnectionList[i].ConnectionId == connectionId)
             {
                 (this.contextCollection.ConnectionList[i] as
                     CifsClientPerConnection).UpdateSequenceNumber(msg);
                 return;
             }
         }
     }
 }
 /// <summary>
 /// add request packet to the request list
 /// </summary>
 /// <param name="request">the request packet</param>
 internal void AddRequestPacket(SmbPacket request)
 {
     lock (this.requestList)
     {
         this.requestList[request.SmbHeader.Mid] = request;
     }
 }
        /// <summary>
        /// create the nt transaction packet
        /// </summary>
        /// <param name="request">the request packet</param>
        /// <param name="smbHeader">the smb header of response packet</param>
        /// <param name="channel">the channel contains the packet bytes</param>
        /// <returns>the response packet</returns>
        private SmbPacket CreateNtTransactionResponsePacket(SmbPacket request, SmbHeader smbHeader, Channel channel)
        {
            SmbPacket smbPacket = null;

            if (smbHeader.Status == 0 && channel.Peek<byte>(0) == 0 && channel.Peek<ushort>(1) == 0)
            {
                return smbPacket;
            }

            SmbNtTransactRequestPacket ntTransactRequest = request as SmbNtTransactRequestPacket;
            if (ntTransactRequest == null)
            {
                return smbPacket;
            }

            // find regular packet
            switch ((uint)ntTransactRequest.SmbParameters.Function)
            {
                case (uint)NtTransSubCommand.NT_TRANSACT_RENAME:
                    smbPacket = new SmbNtTransRenameResponsePacket();
                    break;

                case (uint)NtTransSubCommand.NT_TRANSACT_CREATE:
                    smbPacket = new SmbNtTransactCreateResponsePacket();
                    break;

                case (uint)NtTransSubCommand.NT_TRANSACT_IOCTL:

                    NT_TRANSACT_IOCTL_SETUP setup =
                       CifsMessageUtils.ToStuct<NT_TRANSACT_IOCTL_SETUP>(
                       CifsMessageUtils.ToBytesArray<ushort>(ntTransactRequest.SmbParameters.Setup));

                    switch ((NtTransFunctionCode)setup.FunctionCode)
                    {
                        case NtTransFunctionCode.FSCTL_SRV_ENUMERATE_SNAPSHOTS:
                            smbPacket = new SmbNtTransFsctlSrvEnumerateSnapshotsResponsePacket();
                            break;

                        case NtTransFunctionCode.FSCTL_SRV_REQUEST_RESUME_KEY:
                            smbPacket = new SmbNtTransFsctlSrvRequestResumeKeyResponsePacket();
                            break;

                        case NtTransFunctionCode.FSCTL_SRV_COPYCHUNK:
                            smbPacket = new SmbNtTransFsctlSrvCopyChunkResponsePacket();
                            break;

                        default:
                            smbPacket = new SmbNtTransactIoctlResponsePacket();
                            break;
                    }

                    break;

                case (uint)SmbNtTransSubCommand.NT_TRANSACT_QUERY_QUOTA:
                    smbPacket = new SmbNtTransQueryQuotaResponsePacket();
                    break;

                case (uint)SmbNtTransSubCommand.NT_TRANSACT_SET_QUOTA:
                    smbPacket = new SmbNtTransSetQuotaResponsePacket();
                    break;

                default:
                    break;
            }

            return smbPacket;
        }
        private SmbPacket CreateTransaction2ResponsePacket(SmbPacket request, SmbHeader smbHeader, Channel channel)
        {
            SmbPacket smbPacket = null;

            if (smbHeader.Status == 0 && channel.Peek<byte>(0) == 0 && channel.Peek<ushort>(1) == 0)
            {
                return smbPacket;
            }

            SmbTransaction2RequestPacket transaction2Request = request as SmbTransaction2RequestPacket;
            if (transaction2Request == null)
            {
                return smbPacket;
            }

            // if no setup command. break
            if (transaction2Request.SmbParameters.SetupCount == 0)
            {
                return smbPacket;
            }

            // decode packet using the setup command
            switch ((Trans2SubCommand)transaction2Request.SmbParameters.Setup[0])
            {
                case Trans2SubCommand.TRANS2_QUERY_FILE_INFORMATION:
                    SmbTrans2QueryFileInformationRequestPacket queryFileRequest =
                        transaction2Request as SmbTrans2QueryFileInformationRequestPacket;
                    if (queryFileRequest != null)
                    {
                        smbPacket = new SmbTrans2QueryFileInformationResponsePacket(
                            queryFileRequest.Trans2Parameters.InformationLevel);
                    }
                    break;

                case Trans2SubCommand.TRANS2_QUERY_PATH_INFORMATION:
                    SmbTrans2QueryPathInformationRequestPacket queryPathRequest =
                       transaction2Request as SmbTrans2QueryPathInformationRequestPacket;
                    if (queryPathRequest != null)
                    {
                        smbPacket = new SmbTrans2QueryPathInformationResponsePacket(
                            queryPathRequest.Trans2Parameters.InformationLevel);
                    }
                    break;

                case Trans2SubCommand.TRANS2_SET_FILE_INFORMATION:
                    smbPacket = new SmbTrans2SetFileInformationResponsePacket();
                    break;

                case Trans2SubCommand.TRANS2_SET_PATH_INFORMATION:
                    smbPacket = new SmbTrans2SetPathInformationResponsePacket();
                    break;

                case Trans2SubCommand.TRANS2_QUERY_FS_INFORMATION:
                    SmbTrans2QueryFsInformationRequestPacket queryFsRequest =
                        transaction2Request as SmbTrans2QueryFsInformationRequestPacket;
                    if (queryFsRequest != null)
                    {
                        smbPacket = new SmbTrans2QueryFsInformationResponsePacket(
                            queryFsRequest.Trans2Parameters.InformationLevel);
                    }
                    break;

                case Trans2SubCommand.TRANS2_SET_FS_INFORMATION:
                    smbPacket = new SmbTrans2SetFsInformationResponsePacket();
                    break;

                case Trans2SubCommand.TRANS2_FIND_FIRST2:
                    SmbTrans2FindFirst2RequestPacket first2Request =
                       transaction2Request as SmbTrans2FindFirst2RequestPacket;
                    if (first2Request != null)
                    {
                        smbPacket = new SmbTrans2FindFirst2ResponsePacket(first2Request.Trans2Parameters.InformationLevel,
                            (first2Request.Trans2Parameters.Flags & Trans2FindFlags.SMB_FIND_RETURN_RESUME_KEYS)
                            == Trans2FindFlags.SMB_FIND_RETURN_RESUME_KEYS);
                    }
                    break;

                case Trans2SubCommand.TRANS2_FIND_NEXT2:
                    SmbTrans2FindNext2RequestPacket next2Request =
                       transaction2Request as SmbTrans2FindNext2RequestPacket;
                    if (next2Request != null)
                    {
                        smbPacket = new SmbTrans2FindNext2ResponsePacket(next2Request.Trans2Parameters.InformationLevel,
                            (next2Request.Trans2Parameters.Flags & Trans2FindFlags.SMB_FIND_RETURN_RESUME_KEYS)
                            == Trans2FindFlags.SMB_FIND_RETURN_RESUME_KEYS);
                    }
                    break;

                case Trans2SubCommand.TRANS2_GET_DFS_REFERRAL:
                    smbPacket = new SmbTrans2GetDfsReferralResponsePacket();
                    break;

                default:
                    break;
            }

            return smbPacket;
        }
        protected override SmbPacket CreateSmbResponsePacket(
            SmbPacket request,
            SmbHeader smbHeader,
            Channel channel)
        {
            SmbPacket smbPacket = null;

            // error packet
            SmbStatus packetStatus = (SmbStatus)smbHeader.Status;

            // error packet
            if (packetStatus != SmbStatus.STATUS_SUCCESS &&
                    packetStatus != SmbStatus.STATUS_MORE_PROCESSING_REQUIRED &&
                    packetStatus != SmbStatus.STATUS_BUFFER_OVERFLOW)
            {
                smbPacket = new SmbErrorResponsePacket();
                smbPacket.SmbHeader = smbHeader;

                return smbPacket;
            }

            // success packet
            switch (smbHeader.Command)
            {
                case SmbCommand.SMB_COM_NEGOTIATE:
                    if (smbClient.Capability.IsSupportsExtendedSecurity)
                    {
                        smbPacket = new SmbNegotiateResponsePacket();
                    }
                    else
                    {
                        smbPacket = new SmbNegotiateImplicitNtlmResponsePacket();
                    }
                    break;

                case SmbCommand.SMB_COM_SESSION_SETUP_ANDX:
                    if (smbClient.Capability.IsSupportsExtendedSecurity)
                    {
                        smbPacket = new SmbSessionSetupAndxResponsePacket();
                    }
                    else
                    {
                        smbPacket = new SmbSessionSetupImplicitNtlmAndxResponsePacket();
                    }
                    break;

                case SmbCommand.SMB_COM_TREE_CONNECT_ANDX:
                    smbPacket = new SmbTreeConnectAndxResponsePacket();
                    break;

                case SmbCommand.SMB_COM_TREE_DISCONNECT:
                    smbPacket = new SmbTreeDisconnectResponsePacket();
                    break;

                case SmbCommand.SMB_COM_LOGOFF_ANDX:
                    smbPacket = new SmbLogoffAndxResponsePacket();
                    break;

                case SmbCommand.SMB_COM_NT_CREATE_ANDX:
                    smbPacket = new SmbNtCreateAndxResponsePacket();
                    break;

                case SmbCommand.SMB_COM_CLOSE:
                    smbPacket = new SmbCloseResponsePacket();
                    break;

                case SmbCommand.SMB_COM_OPEN_ANDX:
                    smbPacket = new SmbOpenAndxResponsePacket();
                    break;

                case SmbCommand.SMB_COM_WRITE_ANDX:
                    smbPacket = new SmbWriteAndxResponsePacket();
                    break;

                case SmbCommand.SMB_COM_READ_ANDX:
                    smbPacket = new SmbReadAndxResponsePacket();
                    break;

                case SmbCommand.SMB_COM_TRANSACTION:
                    smbPacket = this.CreateTransactionResponsePacket(request, smbHeader, channel);

                    break;

                case SmbCommand.SMB_COM_TRANSACTION2:
                    smbPacket = this.CreateTransaction2ResponsePacket(request, smbHeader, channel);

                    break;

                case SmbCommand.SMB_COM_NT_TRANSACT:
                    smbPacket = this.CreateNtTransactionResponsePacket(request, smbHeader, channel);

                    break;

                default:
                    break;

            }
            if (smbPacket != null)
            {
                smbPacket.SmbHeader = smbHeader;
                return smbPacket;
            }

            return base.CreateSmbResponsePacket(request, smbHeader, channel);
        }
        /// <summary>
        /// decode the batched request packet
        /// </summary>
        /// <param name="channel">the channel of bytes to read</param>
        /// <param name="request">the request of the response.</param>
        /// <param name="smbBatchedResponse">the batched response</param>
        /// <returns>the consumed length of batched response packet</returns>
        protected override int DecodeBatchedRequest(
            Channel channel,
            SmbPacket request, SmbBatchedResponsePacket smbBatchedResponse)
        {
            int result = base.DecodeBatchedRequest(channel, request, smbBatchedResponse);

            for (SmbBatchedResponsePacket currentPacket = smbBatchedResponse;
                currentPacket != null && currentPacket.AndxPacket != null;
                currentPacket = currentPacket.AndxPacket as SmbBatchedResponsePacket)
            {
                SmbPacket andxPacket = currentPacket.AndxPacket;

                // create the smb packet
                object smbParameters = ObjectUtility.GetFieldValue(currentPacket, "smbParameters");
                if (smbParameters != null)
                {
                    SmbHeader smbHeader = smbBatchedResponse.SmbHeader;
                    smbHeader.Command = (SmbCommand)ObjectUtility.GetFieldValue(smbParameters, "AndXCommand");
                    andxPacket = CreateSmbResponsePacket(null, smbHeader, null);
                }

                // convert from cifs packet to smb packet
                if (andxPacket != null)
                {
                    Type smbPacketType = andxPacket.GetType();
                    andxPacket = ObjectUtility.CreateInstance(
                        smbPacketType.Module.FullyQualifiedName,
                        smbPacketType.FullName,
                        new object[] { currentPacket.AndxPacket }) as SmbPacket;
                }

                currentPacket.AndxPacket = andxPacket;
            }

            return result;
        }
        /// <summary>
        /// add a request into the table of OutstandingRequests.
        /// </summary>
        /// <param name="packet">the Outstanding Request.</param>
        /// <returns>false:the packet is not REQUEST or it is Cancel packet or the MessageId already exists in the table.
        /// otherwise true.</returns>
        internal bool AddOutstandingRequest(SmbPacket packet)
        {
            ulong mid = (ulong)(packet.SmbHeader.Mid);

            lock (this.RequestList)
            {
                if (this.RequestList.ContainsKey(mid))
                {
                    return false;
                }
                else
                {
                    this.RequestList.Add(mid, packet);
                    return true;
                }
            }
        }
        /// <summary>
        /// update the sequence number.
        /// </summary>
        /// <param name="msg">the last request packet.</param>
        /// <exception cref="System.InvalidOperationException">the msg should be request.</exception>
        public void UpdateSequenceNumber(SmbPacket msg)
        {
            // only request can be used to UpdateSequenceNumber:
            if (msg.PacketType != SmbPacketType.SingleRequest
                && msg.PacketType != SmbPacketType.BatchedRequest)
            {
                throw new InvalidOperationException("the packet used to UpdateSequenceNumber should be request.");
            }

            // if the message is not signed, return.
            if (!msg.IsSignRequired)
            {
                return;
            }

            // update client sequence number
            if (msg.SmbHeader.Command == SmbCommand.SMB_COM_NT_CANCEL)
            {
                this.ClientNextSendSequenceNumber++;
            }
            else
            {
                this.clientResponseSequenceNumberList[msg.SmbHeader.Mid] = this.ClientNextSendSequenceNumber + 1;
                this.ClientNextSendSequenceNumber += 2;
            }
        }
        /// <summary>
        /// remove the sequence number.
        /// </summary>
        /// <param name="msg">the last response packet.</param>
        /// <exception cref="System.InvalidOperationException">the msg should be response.</exception>
        public void RemoveSequenceNumber(SmbPacket msg)
        {
            // only response can be used to RemoveSequenceNumber:
            if (msg.PacketType != SmbPacketType.SingleResponse
                && msg.PacketType != SmbPacketType.BatchedResponse)
            {
                throw new InvalidOperationException("the packet used to RemoveSequenceNumber should be response.");
            }

            if (this.ClientResponseSequenceNumberList.ContainsKey(msg.SmbHeader.Mid))
            {
                this.ClientResponseSequenceNumberList.Remove(msg.SmbHeader.Mid);
            }
        }
 protected virtual void UpdateRoleContext(CifsClientPerConnection connection, SmbPacket packet)
 {
     // request packet:
     if ((packet.PacketType == SmbPacketType.BatchedRequest
         || packet.PacketType == SmbPacketType.SingleRequest)
         // Skip over the OpLock Break Notification request sent from server.
         && packet.SmbHeader.Protocol != CifsMessageUtils.SMB_PROTOCOL_IDENTIFIER_ASYNC
         && packet.SmbHeader.Mid != CifsMessageUtils.INVALID_MID)
     {
         RequestPacketUpdateRoleContext(connection, packet, false);
     }
     // response packet:
     else if (packet.PacketType == SmbPacketType.BatchedResponse
         || packet.PacketType == SmbPacketType.SingleResponse)
     {
         SmbPacket request = this.GetOutstandingRequest(connection.ConnectionId, (ulong)packet.SmbHeader.Mid);
         ResponsePacketUpdateRoleContext(connection, request, packet);
         if (connection.IsSigningActive && packet.IsSignRequired)
         {
             packet.IsSignatureCorrect = CifsMessageUtils.VerifySignature(
                 packet,
                 connection.ConnectionSigningSessionKey,
                 (uint)connection.ClientResponseSequenceNumberList[packet.SmbHeader.Mid],
                 connection.ConnectionSigningChallengeResponse);
         }
         ResponsePacketUpdateRoleContextRegular(connection, packet);
     }
     else
     {
         // Do nothing if neither request nor response.
         // No exception is thrown here because UpdateRoleContext is not responsible for checking the
         // invalidation of the packet.
     }
 }
        /// <summary>
        /// createt the transactions packet
        /// </summary>
        /// <param name="request">the request packet</param>
        /// <param name="smbHeader">the smb header of response packet</param>
        /// <param name="channel">the channel contains the packet bytes</param>
        /// <returns>the response packet</returns>
        private SmbPacket CreateTransactionResponsePacket(SmbPacket request, SmbHeader smbHeader, Channel channel)
        {
            SmbPacket smbPacket = null;

            if (smbHeader.Status == 0 && channel.Peek<byte>(0) == 0 && channel.Peek<ushort>(1) == 0)
            {
                return smbPacket;
            }

            SmbTransactionRequestPacket transactionRequest = request as SmbTransactionRequestPacket;
            if (transactionRequest == null)
            {
                return smbPacket;
            }
            switch (smbClient.Capability.TransactionSubCommand)
            {
                case TransSubCommandExtended.TRANS_EXT_MAILSLOT_WRITE:
                    smbPacket = new SmbTransMailslotWriteResponsePacket();
                    break;

                case TransSubCommandExtended.TRANS_EXT_RAP:
                    smbPacket = new SmbTransRapResponsePacket();
                    break;

                default:
                    break;

            }

            // the packet is find
            if (smbPacket != null)
            {
                return smbPacket;
            }

            // if no setup command. break
            if (transactionRequest.SmbParameters.SetupCount == 0)
            {
                return smbPacket;
            }

            // decode packet using the setup command
            switch ((TransSubCommand)transactionRequest.SmbParameters.Setup[0])
            {
                case TransSubCommand.TRANS_SET_NMPIPE_STATE:
                    smbPacket = new SmbTransSetNmpipeStateResponsePacket();
                    break;

                case TransSubCommand.TRANS_QUERY_NMPIPE_STATE:
                    smbPacket = new SmbTransQueryNmpipeStateResponsePacket();
                    break;

                case TransSubCommand.TRANS_RAW_READ_NMPIPE:
                    smbPacket = new SmbTransRawReadNmpipeResponsePacket();
                    break;

                case TransSubCommand.TRANS_QUERY_NMPIPE_INFO:
                    smbPacket = new SmbTransQueryNmpipeInfoResponsePacket();
                    break;

                case TransSubCommand.TRANS_PEEK_NMPIPE:
                    smbPacket = new SmbTransPeekNmpipeResponsePacket();
                    break;

                case TransSubCommand.TRANS_TRANSACT_NMPIPE:
                    smbPacket = new SmbTransTransactNmpipeResponsePacket();
                    break;

                case TransSubCommand.TRANS_READ_NMPIPE:
                    smbPacket = new SmbTransReadNmpipeResponsePacket();
                    break;

                case TransSubCommand.TRANS_WRITE_NMPIPE:
                    smbPacket = new SmbTransWriteNmpipeResponsePacket();
                    break;

                case TransSubCommand.TRANS_WAIT_NMPIPE:
                    smbPacket = new SmbTransWaitNmpipeResponsePacket();
                    break;

                case TransSubCommand.TRANS_CALL_NMPIPE:
                    smbPacket = new SmbTransCallNmpipeResponsePacket();
                    break;

                default:
                    break;
            }

            return smbPacket;
        }
 /// <summary>
 /// add a request into the table of OutstandingRequests.
 /// </summary>
 /// <param name="connectionId">the connection identity.</param>
 /// <param name="packet">the Outstanding Request.</param>
 public void AddOutstandingRequest(int connectionId, SmbPacket packet)
 {
     if (packet == null)
     {
         return;
     }
     lock (this.contextCollection)
     {
         for (int i = this.contextCollection.ConnectionList.Count - 1; i >= 0; i--)
         {
             if (this.contextCollection.ConnectionList[i].ConnectionId == connectionId)
             {
                 (this.contextCollection.ConnectionList[i] as
                     CifsClientPerConnection).AddOutstandingRequest(packet);
                 return;
             }
         }
     }
 }
        /// <summary>
        /// this function will be invoked every time a packet is sent or received. all logics about 
        /// Client' states will be implemented here.
        /// </summary>
        /// <param name="connection">the connection object.</param>
        /// <param name="packet">the sent or received packet in stack transport.</param>
        protected override void UpdateRoleContext(CifsClientPerConnection connection, SmbPacket packet)
        {
            // Do nothing if no connection is found or the packet is not SmbPacket:
            if (connection == null || packet == null)
            {
                return;
            }

            // request packet:
            if (packet.PacketType == SmbPacketType.BatchedRequest
                || packet.PacketType == SmbPacketType.SingleRequest)
            {
                RequestPacketUpdateRoleContext(connection, packet, false);
            }
            // response packet:
            else if (packet.PacketType == SmbPacketType.BatchedResponse
                || packet.PacketType == SmbPacketType.SingleResponse)
            {
                if (!this.SmbUpdateContextWithResponsePacket(connection as SmbClientConnection, packet))
                {
                    SmbPacket request = this.GetOutstandingRequest(connection.ConnectionId, (ulong)packet.SmbHeader.Mid);
                    ResponsePacketUpdateRoleContext(connection, request, packet);
                }
                ResponsePacketUpdateRoleContextRegular(connection, packet);
            }
            else
            {
                // Do nothing if neither request nor response.
                // No exception is thrown here because UpdateRoleContext is not responsible for checking the
                // invalidation of the packet.
            }
        }
        /// <summary>
        /// Send packet to a specific connected client
        /// </summary>
        /// <param name="connection">connection to remote client</param>
        /// <param name="packet">the smb packet</param>
        /// <exception cref="ArgumentNullException">smbPacket</exception>
        /// <exception cref="ArgumentNullException">endpoint</exception>
        /// <exception cref="InvalidOperationException">
        /// The transport is null for not started. Please invoke Start() first
        /// </exception>
        public virtual void SendPacket(SmbPacket packet, SmbServerConnection connection)
        {
            if (packet == null)
            {
                throw new ArgumentNullException("packet");
            }

            if (connection == null)
            {
                throw new ArgumentNullException("connection");
            }

            if (this.transport == null)
            {
                throw new InvalidOperationException(
                    "The transport is null for not started. Please invoke Start() first.");
            }

            SmbPacket smbPacket = packet as SmbPacket;
            if (smbPacket != null && this.context.IsUpdateContext)
            {
                this.context.UpdateRoleContext(connection, smbPacket);
            }

            switch(this.transportType)
            {
                case TransportType.TCP:
                    // send packet through the direct tcp
                    this.transport.SendPacket(connection.Identity, new SmbDirectTcpPacket(packet));

                    break;

                case TransportType.NetBIOS:
                    // send packet through netbios over Tcp
                    this.transport.SendPacket(connection.Identity, smbPacket);

                    break;

                default:
                    break;
            }
        }
        /// <summary>
        /// Send raw frame, which has been customized by upper layer modules. 
        /// </summary>
        /// <param name = "smbPacket">SmbPacket is the base class of all the SM2 packets. </param>
        /// <exception cref="ArgumentNullException">smbPacket</exception>
        /// <exception cref="InvalidOperationException">
        /// The transport is null for not connected to server. Please invoke Connect() first.
        /// </exception>
        public virtual void SendPacket(SmbPacket smbPacket)
        {
            if (smbPacket == null)
            {
                throw new ArgumentNullException("smbPacket");
            }

            if (this.transport == null)
            {
                throw new InvalidOperationException(
                    "The transport is null for not connected to server. Please invoke Connect() first.");
            }

            if (this.cifsClient.IsContextUpdateEnabled)
            {
                this.cifsClient.Context.UpdateRoleContext(this.ConnectionId, smbPacket);
            }

            switch (this.capability.TransportType)
            {
                case TransportType.TCP:
                    // send packet through the direct tcp
                    this.transport.SendPacket(new SmbDirectTcpPacket(smbPacket));

                    break;

                case TransportType.NetBIOS:
                    // send packet through netbios over Tcp
                    this.transport.SendPacket(smbPacket);

                    break;

                default:
                    break;
            }
        }
 /// <summary>
 /// remove the request packet according to the response packet
 /// </summary>
 /// <param name="response">the response packet</param>
 internal void RemoveRequestPacket(SmbPacket response)
 {
     lock (this.requestList)
     {
         if (this.requestList.ContainsKey(response.SmbHeader.Mid))
         {
             this.requestList.Remove(response.SmbHeader.Mid);
         }
     }
 }
        /// <summary>
        /// update the context with request packet
        /// </summary>
        /// <param name="connection">the connection of endpoint</param>
        /// <param name="packet">the packet to update the context</param>
        private void RequestPacketUpdateRoleContext(SmbServerConnection connection, SmbPacket packet)
        {
            connection.AddRequestPacket(packet);

            // update the message id
            connection.MessageId = packet.SmbHeader.Mid;

            // update the process id
            connection.ProcessId = (uint)(packet.SmbHeader.PidHigh << 16);
            connection.ProcessId += packet.SmbHeader.PidLow;

            // update the message sign sequence number
            if (packet.SmbHeader.SecurityFeatures != 0
                && connection.GssApi != null && connection.GssApi.SessionKey != null)
            {
                if (packet.SmbHeader.Command == SmbCommand.SMB_COM_NT_CANCEL)
                {
                    connection.ServerNextReceiveSequenceNumber++;
                }
                else
                {
                    ServerSendSequenceNumberKey key = new ServerSendSequenceNumberKey();

                    key.PidHigh = packet.SmbHeader.PidHigh;
                    key.PidLow = packet.SmbHeader.PidLow;
                    key.Mid = packet.SmbHeader.Mid;

                    connection.ServerSendSequenceNumber[key] = connection.ServerNextReceiveSequenceNumber + 1;
                    connection.ServerNextReceiveSequenceNumber += 2;
                }
            }

            // process each special command
            switch (packet.SmbHeader.Command)
            {
                case SmbCommand.SMB_COM_NEGOTIATE:
                    SmbNegotiateRequestPacket request = packet as SmbNegotiateRequestPacket;
                    byte[] dialects = request.SmbData.Dialects;

                    List<string> negotiateDialects = new List<string>();

                    for (int i = 0; i < dialects.Length; i++)
                    {
                        if (dialects[i] == 0x02)
                        {
                            continue;
                        }

                        string dialect = "";

                        for (; i < dialects.Length && dialects[i] != 0x00; i++)
                        {
                            dialect += (char)dialects[i];
                        }

                        negotiateDialects.Add(dialect);
                    }

                    connection.NegotiatedDialects = negotiateDialects.ToArray();

                    break;

                case SmbCommand.SMB_COM_TREE_CONNECT_ANDX:

                    // down-case the packet
                    Cifs.SmbTreeConnectAndxRequestPacket treeconnect = packet as Cifs.SmbTreeConnectAndxRequestPacket;

                    // get the specified session.
                    SmbServerSession treeconnectSession = connection.GetSession((ushort)treeconnect.SmbHeader.Uid);
                    if (treeconnectSession == null)
                    {
                        return;
                    }

                    // Calculate the one-way hash
                    byte[] sessionKey = FileServiceUtils.ProtectSessionKey(treeconnectSession.SessionKey);

                    // update the session key state.
                    treeconnectSession.SessionKeyState = SessionKeyStateValue.Available;

                    // if server does not support SMB_EXTENDED_SIGNATURES, return.
                    if (SmbClientTreeConnect.TreeConnectAndxExtendedSignatures !=
                        (treeconnect.SmbParameters.Flags & SmbClientTreeConnect.TreeConnectAndxExtendedSignatures))
                    {
                        return;
                    }

                    treeconnectSession.SessionKey = sessionKey;

                    break;

                default:
                    return;
            }

            return;
        }
        /// <summary>
        /// to decode stack packet from the received message bytes.
        /// the message bytes contains data without transport information
        /// </summary>
        /// <param name = "endpoint">the endpoint from which the message bytes are received. </param>
        /// <param name = "packetBytesWithoutTransport">the received message bytes to be decoded. </param>
        /// <param name = "consumedLength">the length of message bytes consumed by decoder. </param>
        /// <param name = "expectedLength">the length of message bytes the decoder expects to receive. </param>
        /// <returns>the stack packets decoded from the received message bytes. </returns>
        private SmbPacket[] DecodePacketFromBytesWithoutTransport(
            int endpoint, byte[] packetBytesWithoutTransport, out int consumedLength, out int expectedLength)
        {
            expectedLength = 0;
            consumedLength = 0;
            SmbPacket[] packets = new SmbPacket[0];

            int packetConsumedLength = 0;
            int packetExpectedLength = 0;

            // decode packets using cifs decorder.
            SmbPacket response = this.DecodeSmbResponseFromBytes(
                (int)endpoint, packetBytesWithoutTransport, out packetConsumedLength);

            // Use the decoded packet to UpdateRoleContext if it is not null and ContextUpdate is enabled:
            if (response != null)
            {
                if (this.IsContextUpdateEnabled)
                {
                    this.clientContext.UpdateRoleContext((int)endpoint, response);
                }
                packets = new SmbPacket[] { response };
            }

            // update the length after decode packet.
            consumedLength += packetConsumedLength;
            expectedLength += packetExpectedLength;

            return packets;
        }
        /// <summary>
        /// decode packet from bytes
        /// </summary>
        /// <param name="connectId">the connection identity.</param>
        /// <param name="messageBytes">bytes contains packet</param>
        /// <param name="consumedLength">the bytes length which are consumed when decode.</param>
        /// <returns>the decoded packet from the bytes array. if failed, return null.</returns>
        protected SmbPacket DecodeSmbResponseFromBytes(
            int connectId,
            byte[] messageBytes,
            out int consumedLength)
        {
            consumedLength = 0;
            SmbPacket smbRequest  = null;
            SmbPacket smbResponse = null;

            using (MemoryStream memoryStream = new MemoryStream(messageBytes, true))
            {
                using (Channel channel = new Channel(null, memoryStream))
                {
                    // read raw response:
                    Collection <SmbPacket> outstandingRequests = this.clientContext.GetOutstandingRequests(connectId);
                    if (outstandingRequests != null && outstandingRequests.Count > 0)
                    {
                        SmbReadRawRequestPacket readRawRequest = outstandingRequests[0] as SmbReadRawRequestPacket;
                        if (readRawRequest != null)
                        {
                            SmbReadRawResponsePacket readRawResponse = this.CreateSmbResponsePacket(
                                readRawRequest, readRawRequest.SmbHeader, channel) as SmbReadRawResponsePacket;
                            if (readRawResponse != null)
                            {
                                byte[] rawData = new byte[messageBytes.Length];
                                Array.Copy(messageBytes, rawData, rawData.Length);
                                readRawResponse.RawData = rawData;
                                consumedLength          = rawData.Length;
                                return(readRawResponse);
                            }
                            else
                            {
                                // discard the none-parsable data silently:
                                consumedLength = messageBytes.Length;
                                return(null);
                            }
                        }
                        else
                        {
                            // No SmbReadRawResponsePacket sent, so the response should not be SmbReadRawResponsePacket.
                            // and do nothing here.
                        }
                    }

                    // read smb header and new SmbPacket:
                    if (channel.Stream.Position < channel.Stream.Length &&
                        messageBytes.Length >= CifsMessageUtils.GetSize <SmbHeader>(new SmbHeader()))
                    {
                        SmbHeader smbHeader = channel.Read <SmbHeader>();
                        smbRequest      = this.clientContext.GetOutstandingRequest(connectId, smbHeader.Mid);
                        smbResponse     = this.CreateSmbResponsePacket(smbRequest, smbHeader, channel);
                        consumedLength += smbResponse.HeaderSize;
                    }
                    else
                    {
                        // The data in the channel is less than the size of SmbHeader. consume nothing and return null:
                        consumedLength = 0;
                        return(null);
                    }

                    // read SmbParameters:
                    consumedLength += smbResponse.ReadParametersFromChannel(channel);

                    // read SmbData:
                    consumedLength += smbResponse.ReadDataFromChannel(channel);

                    // read andx:
                    SmbBatchedResponsePacket smbBatchedResponse = smbResponse as SmbBatchedResponsePacket;
                    if (smbRequest != null && smbBatchedResponse != null)
                    {
                        consumedLength += DecodeBatchedRequest(channel, smbRequest, smbBatchedResponse);
                    }

                    // handle the difference of protocol implementation:
                    SmbWriteAndCloseResponsePacket writeAndCloseResponse = smbResponse as SmbWriteAndCloseResponsePacket;
                    if (writeAndCloseResponse != null)
                    {
                        if (this.clientConfig.IsWriteAndCloseResponseExtraPadding)
                        {
                            // Windows NT Server appends three NULL bytes to this message, following the ByteCount field.
                            // These three bytes are not message data and can safely be discarded.
                            const int PaddingLength = 3;
                            writeAndCloseResponse.PaddingBytes = channel.ReadBytes(PaddingLength);
                            consumedLength += PaddingLength;
                        }
                    }
                }
            }
            return(smbResponse);
        }
        private bool SmbUpdateContextWithResponsePacket(SmbClientConnection connection, SmbPacket response)
        {
            if (response == null)
            {
                return false;
            }

            int connectionId = connection.ConnectionId;

            SmbHeader smbHeader = response.SmbHeader;

            // only process the response packet.
            if (response.PacketType != SmbPacketType.BatchedResponse
                && response.PacketType != SmbPacketType.SingleResponse)
            {
                return false;
            }

            // packet status
            SmbStatus packetStatus = (SmbStatus)smbHeader.Status;

            // filter error packet
            if (packetStatus != SmbStatus.STATUS_SUCCESS &&
                    packetStatus != SmbStatus.STATUS_MORE_PROCESSING_REQUIRED &&
                    packetStatus != SmbStatus.STATUS_BUFFER_OVERFLOW)
            {
                return false;
            }

            // process each special command
            switch (smbHeader.Command)
            {
                #region Negotiate Response

                case SmbCommand.SMB_COM_NEGOTIATE:

                    // implicit ntlm, decode using cifs sdk.
                    if (!smbClient.Capability.IsSupportsExtendedSecurity)
                    {
                        return false;
                    }

                    // down cast to negotiate response packet.
                    SmbNegotiateResponsePacket negotiate = response as SmbNegotiateResponsePacket;

                    // set negotiate flag
                    connection.NegotiateSent = true;

                    #region update security mode

                    SecurityModes securityModes = negotiate.SmbParameters.SecurityMode;

                    if (SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_ENABLED
                        == (securityModes & SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_ENABLED))
                    {
                        connection.ServerSigningState = SignState.ENABLED;
                    }
                    else if (SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED
                        == (securityModes & SecurityModes.NEGOTIATE_SECURITY_SIGNATURES_REQUIRED))
                    {
                        connection.ServerSigningState = SignState.REQUIRED;
                    }
                    else
                    {
                        connection.ServerSigningState = SignState.DISABLED;
                    }

                    if (SecurityModes.NEGOTIATE_USER_SECURITY
                        == (securityModes & SecurityModes.NEGOTIATE_USER_SECURITY))
                    {
                        connection.UsesSharePasswords = false;
                    }
                    else
                    {
                        connection.UsesSharePasswords = true;
                    }

                    if (SecurityModes.NEGOTIATE_ENCRYPT_PASSWORDS
                        == (securityModes & SecurityModes.NEGOTIATE_ENCRYPT_PASSWORDS))
                    {
                        connection.IsClientEncryptPasswords = true;
                    }
                    else
                    {
                        connection.IsClientEncryptPasswords = false;
                    }

                    // update IsSignActive using the combination of the client's
                    // MessageSigningPolicy and the connection's ServerSigningState
                    smbClient.Context.UpdateSigningActive(connection);

                    #endregion

                    #region update server capabilities

                    connection.ServerCapabilities = (Capabilities)negotiate.SmbParameters.Capabilities;

                    if (Capabilities.CAP_INFOLEVEL_PASSTHRU
                        == (connection.ServerCapabilities & Capabilities.CAP_INFOLEVEL_PASSTHRU))
                    {
                        smbClient.Capability.IsUsePathThrough = true;
                    }

                    #endregion

                    #region update maxbuffersize

                    connection.MaxBufferSize = negotiate.SmbParameters.MaxBufferSize;

                    #endregion

                    this.AddOrUpdateConnection(connection);

                    break;

                #endregion

                #region Session Setup Response

                case SmbCommand.SMB_COM_SESSION_SETUP_ANDX:

                    // implicit ntlm, decode using cifs sdk.
                    if (!smbClient.Capability.IsSupportsExtendedSecurity)
                    {
                        return false;
                    }

                    // the session to operation on.
                    SmbClientSession session = null;

                    // down-case the packet
                    SmbSessionSetupAndxResponsePacket packet = response as SmbSessionSetupAndxResponsePacket;

                    // if session exists, use it.
                    if (this.GetSession(connectionId, smbHeader.Uid) != null)
                    {
                        session = new SmbClientSession(this.GetSession(connectionId, smbHeader.Uid));
                    }
                    else
                    {
                        session = new SmbClientSession();
                    }

                    // if success, update context and session key.
                    if (packetStatus == SmbStatus.STATUS_SUCCESS)
                    {
                        // if spng, the SessionKey is null and the SecurityBlob from server contains data
                        // in this situation, need to initialize the SecurityBlob of server to generate the SessionKey
                        if (connection.GssApi.SessionKey == null
                            && packet.SecurityBlob != null && packet.SecurityBlob.Length > 0)
                        {
                            connection.GssApi.Initialize(packet.SecurityBlob);
                        }

                        // get session key and store in the context
                        session.SessionKey = connection.GssApi.SessionKey;

                        // reset the gss api of connection
                        connection.GssApi = null;

                        // reset the securityblob when success
                        packet.SecurityBlob = null;
                    }

                    // update the security blob from server
                    connection.SecurityBlob = packet.SecurityBlob;
                    this.AddOrUpdateConnection(connection);

                    // update session
                    session.SessionUid = smbHeader.Uid;
                    session.ConnectionId = connectionId;

                    this.AddOrUpdateSession(session);

                    break;

                #endregion

                default:
                    return false;
            }

            return true;
        }
        /// <summary>
        /// Expect a request. If user is not interested in the packet, please call DefaultSendResponse().
        /// </summary>
        /// <param name="timeout">timeout</param>
        /// <param name="connection">the connection between server and client</param>
        /// <param name="session">the session between server and client</param>
        /// <param name="treeConnect">the tree connect between server and client</param>
        /// <param name="open">the file open between server and client</param>
        /// <param name="requestPacket">the request</param>
        public override void ExpectRequest(
            TimeSpan timeout,
            out IFileServiceServerConnection connection,
            out IFileServiceServerSession session,
            out IFileServiceServerTreeConnect treeConnect,
            out IFileServiceServerOpen open,
            out SmbFamilyPacket requestPacket)
        {
            CifsServerPerConnection cifsConnection;
            SmbPacket request = this.cifsServer.ExpectPacket(timeout, out cifsConnection);

            connection    = cifsConnection;
            requestPacket = request;
            session       = null;
            treeConnect   = null;
            open          = null;

            if (request != null)
            {
                session = cifsConnection.GetSession(request.SmbHeader.Uid);
                if (session != null)
                {
                    treeConnect = (session as CifsServerPerSession).GetTreeConnect(request.SmbHeader.Tid);
                    if (treeConnect != null)
                    {
                        ushort fid = 0;
                        SmbTransactionRequestPacket            transactionRequest = request as SmbTransactionRequestPacket;
                        SmbNtTransactIoctlRequestPacket        ioctlRequest       = request as SmbNtTransactIoctlRequestPacket;
                        SmbNtTransactNotifyChangeRequestPacket notifyChange       = request as SmbNtTransactNotifyChangeRequestPacket;

                        if (transactionRequest != null)
                        {
                            //SubCommand(2bytes), FID(2bytes)
                            fid = transactionRequest.SmbParameters.Setup[1];
                        }

                        else if (ioctlRequest != null)
                        {
                            //FunctionCode(4bytes), FID(2bytes), IsFctl(1bytes), IsFlags(1bytes)
                            fid = ioctlRequest.SmbParameters.Setup[2];
                        }
                        else if (notifyChange != null)
                        {
                            //CompletionFilter(4bytes), FID(2bytes), WatchTree(1bytes), Reserved(1bytes)
                            fid = notifyChange.SmbParameters.Setup[2];
                        }
                        else
                        {
                            Type         packetType = request.GetType();
                            PropertyInfo pi         = packetType.GetProperty(
                                "Trans2Parameters", BindingFlags.Instance | BindingFlags.Public);

                            if (pi == null)
                            {
                                pi = packetType.GetProperty(
                                    "NtTransParameters", BindingFlags.Instance | BindingFlags.Public);
                            }
                            if (pi == null)
                            {
                                pi = packetType.GetProperty(
                                    "SmbParameters", BindingFlags.Instance | BindingFlags.Public);
                            }
                            if (pi != null)
                            {
                                object    smbParameters = pi.GetValue(request, null);
                                FieldInfo fi            = smbParameters.GetType().GetField(
                                    "FID",
                                    BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
                                if (fi != null)
                                {
                                    fid = (ushort)fi.GetValue(smbParameters);
                                }
                            }
                        }

                        if (fid > 0)
                        {
                            open = (treeConnect as CifsServerPerTreeConnect).GetOpen(fid);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// update the context of smb server
        /// </summary>
        /// <param name="connection">the connection of the client</param>
        /// <param name="packet">the packet to update the context</param>
        internal void UpdateRoleContext(SmbServerConnection connection, SmbPacket packet)
        {
            if (connection == null)
            {
                return;
            }

            // packet status
            SmbStatus packetStatus = (SmbStatus)packet.SmbHeader.Status;

            // filter error packet
            if (packetStatus != SmbStatus.STATUS_SUCCESS &&
                    packetStatus != SmbStatus.STATUS_MORE_PROCESSING_REQUIRED &&
                    packetStatus != SmbStatus.STATUS_BUFFER_OVERFLOW)
            {
                return;
            }

            // process the response packet.
            if (packet.PacketType == SmbPacketType.BatchedResponse
                || packet.PacketType == SmbPacketType.SingleResponse)
            {
                ResponsePacketUpdateRoleContext(connection, packet);
                return;
            }

            // process the request packet.
            if (packet.PacketType == SmbPacketType.BatchedRequest
                || packet.PacketType == SmbPacketType.SingleRequest)
            {
                RequestPacketUpdateRoleContext(connection, packet);
                return;
            }
        }
 /// <summary>
 /// the transport 
 /// </summary>
 /// <param name = "packet">the packet to send through TCP </param>
 public SmbDirectTcpPacket(SmbPacket packet)
 {
     this.packet = packet;
 }
        /// <summary>
        /// update the context with response packet
        /// </summary>
        /// <param name="connection">the connection of endpoint</param>
        /// <param name="packet">the packet to update the context</param>
        private void ResponsePacketUpdateRoleContext(SmbServerConnection connection, SmbPacket packet)
        {
            SmbHeader smbHeader = packet.SmbHeader;

            SmbPacket requestPacket = connection.GetRequestPacket(smbHeader.Mid);
            if (requestPacket == null)
            {
                return;
            }

            switch (smbHeader.Command)
            {
                case SmbCommand.SMB_COM_SESSION_SETUP_ANDX:
                    if (smbHeader.Uid == 0)
                    {
                        break;
                    }
                    else
                    {
                        SmbServerSession session = new SmbServerSession();
                        session.Uid = smbHeader.Uid;
                        session.AuthenticationState = SessionState.Complete;
                        session.Connection = connection;
                        session.SessionKey = connection.GssApi.SessionKey;

                        connection.AddSession(session);
                    }

                    break;

                case SmbCommand.SMB_COM_LOGOFF_ANDX:
                    if (requestPacket.SmbHeader.Uid == 0)
                    {
                        break;
                    }
                    else
                    {
                        connection.RemoveSession(connection.GetSession(requestPacket.SmbHeader.Uid));
                    }

                    break;

                case SmbCommand.SMB_COM_TREE_CONNECT_ANDX:
                    {
                        SmbTreeConnectAndxRequestPacket request = requestPacket as SmbTreeConnectAndxRequestPacket;

                        SmbServerTreeConnect treeconnect = new SmbServerTreeConnect();
                        treeconnect.TreeId = smbHeader.Tid;
                        treeconnect.Session = connection.GetSession(smbHeader.Uid);
                        if (treeconnect.Session == null)
                        {
                            break;
                        }
                        if ((request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) != 0)
                        {
                            treeconnect.Path = Encoding.Unicode.GetString(request.SmbData.Path);
                        }
                        else
                        {
                            treeconnect.Path = Encoding.ASCII.GetString(request.SmbData.Path);
                        }
                        treeconnect.Path = treeconnect.Path.TrimEnd('\0');
                        treeconnect.Session.AddTreeConnect(treeconnect);
                    }

                    break;

                case SmbCommand.SMB_COM_TREE_DISCONNECT:
                    if (requestPacket.SmbHeader.Uid != 0)
                    {
                        SmbServerSession session = connection.GetSession(requestPacket.SmbHeader.Uid);
                        if (session == null)
                        {
                            break;
                        }
                        session.RemoveTreeConnect(session.GetTreeConnect(requestPacket.SmbHeader.Tid));
                    }

                    break;

                case SmbCommand.SMB_COM_NT_CREATE_ANDX:
                    {
                        SmbNtCreateAndxResponsePacket response = packet as SmbNtCreateAndxResponsePacket;
                        SmbNtCreateAndxRequestPacket request = requestPacket as SmbNtCreateAndxRequestPacket;

                        SmbServerOpen open = new SmbServerOpen();
                        open.SmbFid = response.SmbParameters.FID;
                        open.PathName = SmbMessageUtils.GetString(request.SmbData.FileName,
                            SmbFlags2.SMB_FLAGS2_UNICODE == (request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE));
                        open.PathName = open.PathName.TrimEnd('\0');
                        open.Session = connection.GetSession(smbHeader.Uid);
                        open.TreeConnect = connection.GetTreeConnect(smbHeader.Tid);
                        if (open.TreeConnect == null)
                        {
                            break;
                        }
                        open.TreeConnect.AddOpen(open);
                    }

                    break;

                case SmbCommand.SMB_COM_OPEN_ANDX:
                    {
                        SmbOpenAndxResponsePacket response = packet as SmbOpenAndxResponsePacket;
                        SmbOpenAndxRequestPacket request = requestPacket as SmbOpenAndxRequestPacket;

                        SmbServerOpen open = new SmbServerOpen();
                        open.SmbFid = response.SmbParameters.FID;
                        open.PathName = SmbMessageUtils.GetString(request.SmbData.FileName,
                            SmbFlags2.SMB_FLAGS2_UNICODE == (request.SmbHeader.Flags2 & SmbFlags2.SMB_FLAGS2_UNICODE));
                        open.Session = connection.GetSession(smbHeader.Uid);
                        open.TreeConnect = connection.GetTreeConnect(smbHeader.Tid);
                        if (open.TreeConnect == null)
                        {
                            break;
                        }
                        open.TreeConnect.AddOpen(open);
                    }

                    break;

                case SmbCommand.SMB_COM_CLOSE:
                    {
                        SmbCloseRequestPacket closeRequest = requestPacket as SmbCloseRequestPacket;

                        SmbServerTreeConnect treeconnect = connection.GetTreeConnect(requestPacket.SmbHeader.Tid);
                        if (treeconnect == null)
                        {
                            break;
                        }

                        treeconnect.RemoveOpen(treeconnect.GetOpen(closeRequest.SmbParameters.FID));
                    }

                    break;

                default:
                    break;
            }

            connection.RemoveRequestPacket(packet);
        }
        /// <summary>
        /// this function will be invoked every time a packet is sent or received. all logics about 
        /// Client' states will be implemented here.
        /// request packet update the context
        /// </summary>
        /// <param name="connection">the connection object.</param>
        /// <param name="packet">the sent or received packet in stack transport.</param>
        /// <param name="isAndxPacket">the packet is andx packet or not.</param>
        protected virtual void RequestPacketUpdateRoleContext(CifsClientPerConnection connection, SmbPacket packet, bool isAndxPacket)
        {
            int connectionId = connection.ConnectionId;

            if (packet == null)
            {
                return;
            }

            #region To update Connection/Session/Tree/Open with request
            switch (packet.SmbHeader.Command)
            {
                case SmbCommand.SMB_COM_NEGOTIATE:
                    connection.NegotiateSent = true;
                    this.AddOrUpdateConnection(connection);
                    break;

                default:
                    // No Connection/Session/Tree/Open will be updated for other requests.
                    break;
            }
            #endregion

            #region AddOutstandingRequest
            if (!isAndxPacket
                && packet.SmbHeader.Command != SmbCommand.SMB_COM_TRANSACTION_SECONDARY
                && packet.SmbHeader.Command != SmbCommand.SMB_COM_TRANSACTION2_SECONDARY
                && packet.SmbHeader.Command != SmbCommand.SMB_COM_NT_TRANSACT_SECONDARY
                && packet.SmbHeader.Command != SmbCommand.SMB_COM_NT_CANCEL)
            {
                this.AddOutstandingRequest(connectionId, packet);
            }
            else
            {
                // do nothing for requests of Andx, SECONDARY and CANCEL.
            }
            #endregion

            #region UpdateSequenceNumber
            if (!isAndxPacket)
            {
                this.UpdateSequenceNumber(connectionId, packet);
            }

            SmbBatchedRequestPacket batchedPacket = packet as SmbBatchedRequestPacket;
            if (batchedPacket != null)
            {
                RequestPacketUpdateRoleContext(connection, batchedPacket.AndxPacket, true);
            }
            #endregion
        }