/// <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.
            }
        }
        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
        }
 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>
        /// 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
        }
 /// <summary>
 /// if the connection identified by connectionId has been existed in connectionList, 
 /// this connection will be updated into the connectionList. otherwise, this connection
 /// will be added into the connectionList.
 /// </summary>
 /// <param name="connection">the connection to be added or updated.</param>
 public void AddOrUpdateConnection(CifsClientPerConnection connection)
 {
     if (connection == null)
     {
         return;
     }
     lock (this.contextCollection)
     {
         for (int i = this.contextCollection.ConnectionList.Count - 1; i >= 0; i--)
         {
             if (this.contextCollection.ConnectionList[i].ConnectionId == connection.ConnectionId)
             {
                 // update the connection:
                 this.contextCollection.ConnectionList[i] = connection;
                 return;
             }
         }
         // add the connection:
         connection.GlobalIndex = this.contextCollection.NextConnectionGlobalIndex;
         this.contextCollection.ConnectionList.Add(connection);
         this.contextCollection.NextConnectionGlobalIndex += 1;
     }
 }
        /// <summary>
        /// Deep copy constructor.
        /// if need to copy the connection instance, you must call the Clone method.
        /// its sub class inherit from this, and need to provide more features.
        /// </summary>
        public CifsClientPerConnection(CifsClientPerConnection connection)
            : base(connection)
        {
            lock (connection)
            {
                // common ADM:
                this.SelectedDialect = connection.SelectedDialect;
                this.IsSigningActive = connection.IsSigningActive;
                if (connection.ConnectionSigningSessionKey != null)
                {
                    this.ConnectionSigningSessionKey = new byte[connection.ConnectionSigningSessionKey.Length];
                    Array.Copy(connection.ConnectionSigningSessionKey, this.ConnectionSigningSessionKey,
                        connection.ConnectionSigningSessionKey.Length);
                }
                if (connection.ConnectionSigningChallengeResponse != null)
                {
                    this.ConnectionSigningChallengeResponse = new byte[
                        connection.ConnectionSigningChallengeResponse.Length];
                    Array.Copy(connection.ConnectionSigningChallengeResponse, this.ConnectionSigningChallengeResponse,
                        connection.ConnectionSigningChallengeResponse.Length);
                }

                // client ADM:
                this.ShareLevelAccessControl = connection.ShareLevelAccessControl;
                this.ServerChallengeResponse = connection.ServerChallengeResponse;
                this.ServerSigningState = connection.ServerSigningState;
                this.ClientNextSendSequenceNumber = connection.ClientNextSendSequenceNumber;
                if (connection.ClientResponseSequenceNumberList != null)
                {
                    this.ClientResponseSequenceNumberList = new Dictionary<ushort, ulong>();
                    foreach (KeyValuePair<ushort, ulong> obj in connection.ClientResponseSequenceNumberList)
                    {
                        this.ClientResponseSequenceNumberList.Add(obj.Key, obj.Value);
                    }
                }
                if (connection.NTLMEncryptionKey != null)
                {
                    this.NTLMEncryptionKey = new byte[connection.NTLMEncryptionKey.Length];
                    Array.Copy(connection.NTLMEncryptionKey, this.NTLMEncryptionKey,
                        connection.NTLMEncryptionKey.Length);
                }
                this.ServerCapabilities = connection.ServerCapabilities;
                this.NegotiateSent = connection.NegotiateSent;
                this.MaxBufferSize = connection.MaxBufferSize;
                this.SessionID = connection.SessionID;
                if (connection.OpLockTable != null)
                {
                    this.OpLockTable = new Dictionary<ushort, byte>();
                    foreach (KeyValuePair<ushort, byte> obj in connection.OpLockTable)
                    {
                        this.OpLockTable.Add(obj.Key, obj.Value);
                    }
                }

                // negotiate response:
                this.SecurityMode = connection.SecurityMode;
                this.MaxMpxCount = connection.MaxMpxCount;
                this.MaxNumberVcs = connection.MaxNumberVcs;
                this.MaxRawSize = connection.MaxRawSize;
                this.SessionKey = connection.SessionKey;
                this.SystemTime = connection.SystemTime;
                this.ServerTimeZone = connection.ServerTimeZone;
                this.Challenge = connection.Challenge;
                if (connection.DomainName != null)
                {
                    this.DomainName = new byte[connection.DomainName.Length];
                    Array.Copy(connection.DomainName, this.DomainName, connection.DomainName.Length);
                }

                // stack sdk design:
                this.ServerNetbiosName = string.Empty;
                this.ClientNetbiosName = string.Empty;
                this.ConnectionState = StackTransportState.Init;
                this.pendingResponseList = new Dictionary<ulong, SmbPacket>();
                this.SessionTable = new Collection<Session>();
                this.nextMessageId = 1;

                // stack sdk design:
                this.ServerNetbiosName = connection.ServerNetbiosName;
                this.ClientNetbiosName = connection.ClientNetbiosName;
                this.ConnectionState = connection.ConnectionState;
                if (connection.pendingResponseList != null)
                {
                    this.pendingResponseList = new Dictionary<ulong, SmbPacket>();
                    foreach (KeyValuePair<ulong, SmbPacket> pair in connection.pendingResponseList)
                    {
                        this.pendingResponseList.Add(pair.Key, pair.Value.Clone() as SmbPacket);
                    }
                }
                if (connection.sessionTable != null)
                {
                    this.sessionTable = new Collection<Session>();
                    foreach (CifsClientPerSession session in connection.sessionTable)
                    {
                        this.sessionTable.Add(session.Clone());
                    }
                }
                this.nextMessageId = connection.nextMessageId;
            }
        }
        /// <summary>
        /// to set up Netbios session with server, and add the connection into context.
        /// </summary>
        /// <param name="server">the server NetBios Name.</param>
        /// <param name="client">the local NetBios Name.</param>
        /// <returns>the Identity of the connection. if connected, is the session number 
        /// of the Netbios session; otherwise -1.</returns>
        /// <exception cref="System.ArgumentNullException">the server and client must not be null.</exception>
        /// <exception cref="System.InvalidOperationException"> failed to connect for Netbios error. </exception>
        public int Connect(string server, string client)
        {
            if (server == null)
            {
                throw new ArgumentNullException("server");
            }

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

            NetbiosTransportConfig transportConfig = new NetbiosTransportConfig();
            transportConfig.Type = StackTransportType.Netbios;
            transportConfig.Role = Role.Client;
            transportConfig.BufferSize = this.ptfConfig.NcbBufferSize;
            transportConfig.MaxSessions = this.ptfConfig.NcbMaxSessions;
            transportConfig.MaxNames = this.ptfConfig.NcbMaxNames;
            transportConfig.RemoteNetbiosName = server;
            transportConfig.LocalNetbiosName = client;

            this.transport = new TransportStack(transportConfig, this.decoder.DecodePacket);

            this.connectionId = (int)this.transport.Connect();

            CifsClientPerConnection connection = new CifsClientPerConnection();
            connection.ConnectionId = this.connectionId;
            connection.ConnectionState = StackTransportState.ConnectionEstablished;
            connection.ServerNetbiosName = server;
            connection.ClientNetbiosName = client;
            this.context.AddOrUpdateConnection(connection);

            return this.connectionId;
        }
예제 #8
0
        /// <summary>
        /// Deep copy constructor.
        /// if need to copy the connection instance, you must call the Clone method.
        /// its sub class inherit from this, and need to provide more features.
        /// </summary>
        public CifsClientPerConnection(CifsClientPerConnection connection)
            : base(connection)
        {
            lock (connection)
            {
                // common ADM:
                this.SelectedDialect = connection.SelectedDialect;
                this.IsSigningActive = connection.IsSigningActive;
                if (connection.ConnectionSigningSessionKey != null)
                {
                    this.ConnectionSigningSessionKey = new byte[connection.ConnectionSigningSessionKey.Length];
                    Array.Copy(connection.ConnectionSigningSessionKey, this.ConnectionSigningSessionKey,
                               connection.ConnectionSigningSessionKey.Length);
                }
                if (connection.ConnectionSigningChallengeResponse != null)
                {
                    this.ConnectionSigningChallengeResponse = new byte[
                        connection.ConnectionSigningChallengeResponse.Length];
                    Array.Copy(connection.ConnectionSigningChallengeResponse, this.ConnectionSigningChallengeResponse,
                               connection.ConnectionSigningChallengeResponse.Length);
                }

                // client ADM:
                this.ShareLevelAccessControl      = connection.ShareLevelAccessControl;
                this.ServerChallengeResponse      = connection.ServerChallengeResponse;
                this.ServerSigningState           = connection.ServerSigningState;
                this.ClientNextSendSequenceNumber = connection.ClientNextSendSequenceNumber;
                if (connection.ClientResponseSequenceNumberList != null)
                {
                    this.ClientResponseSequenceNumberList = new Dictionary <ushort, ulong>();
                    foreach (KeyValuePair <ushort, ulong> obj in connection.ClientResponseSequenceNumberList)
                    {
                        this.ClientResponseSequenceNumberList.Add(obj.Key, obj.Value);
                    }
                }
                if (connection.NTLMEncryptionKey != null)
                {
                    this.NTLMEncryptionKey = new byte[connection.NTLMEncryptionKey.Length];
                    Array.Copy(connection.NTLMEncryptionKey, this.NTLMEncryptionKey,
                               connection.NTLMEncryptionKey.Length);
                }
                this.ServerCapabilities = connection.ServerCapabilities;
                this.NegotiateSent      = connection.NegotiateSent;
                this.MaxBufferSize      = connection.MaxBufferSize;
                this.SessionID          = connection.SessionID;
                if (connection.OpLockTable != null)
                {
                    this.OpLockTable = new Dictionary <ushort, byte>();
                    foreach (KeyValuePair <ushort, byte> obj in connection.OpLockTable)
                    {
                        this.OpLockTable.Add(obj.Key, obj.Value);
                    }
                }

                // negotiate response:
                this.SecurityMode   = connection.SecurityMode;
                this.MaxMpxCount    = connection.MaxMpxCount;
                this.MaxNumberVcs   = connection.MaxNumberVcs;
                this.MaxRawSize     = connection.MaxRawSize;
                this.SessionKey     = connection.SessionKey;
                this.SystemTime     = connection.SystemTime;
                this.ServerTimeZone = connection.ServerTimeZone;
                this.Challenge      = connection.Challenge;
                if (connection.DomainName != null)
                {
                    this.DomainName = new byte[connection.DomainName.Length];
                    Array.Copy(connection.DomainName, this.DomainName, connection.DomainName.Length);
                }

                // stack sdk design:
                this.ServerNetbiosName   = string.Empty;
                this.ClientNetbiosName   = string.Empty;
                this.ConnectionState     = StackTransportState.Init;
                this.pendingResponseList = new Dictionary <ulong, SmbPacket>();
                this.SessionTable        = new Collection <Session>();
                this.nextMessageId       = 1;

                // stack sdk design:
                this.ServerNetbiosName = connection.ServerNetbiosName;
                this.ClientNetbiosName = connection.ClientNetbiosName;
                this.ConnectionState   = connection.ConnectionState;
                if (connection.pendingResponseList != null)
                {
                    this.pendingResponseList = new Dictionary <ulong, SmbPacket>();
                    foreach (KeyValuePair <ulong, SmbPacket> pair in connection.pendingResponseList)
                    {
                        this.pendingResponseList.Add(pair.Key, pair.Value.Clone() as SmbPacket);
                    }
                }
                if (connection.sessionTable != null)
                {
                    this.sessionTable = new Collection <Session>();
                    foreach (CifsClientPerSession session in connection.sessionTable)
                    {
                        this.sessionTable.Add(session.Clone());
                    }
                }
                this.nextMessageId = connection.nextMessageId;
            }
        }