public void PrepareCreate(
            ModelDialectRevision maxSmbVersionClientSupported,
            ReplayModelClientSupportPersistent isClientSupportPersistent,
            ReplayModelDurableHandle modelDurableHandle,
            ReplayModelShareType shareType,
            ReplayModelRequestedOplockLevel requestedOplockLevel,
            ReplayModelLeaseState leaseState)
        {
            InitializeMainChannel(maxSmbVersionClientSupported, clientGuidMainChannel, shareType, out treeIdMainChannel, false, isClientSupportPersistent == ReplayModelClientSupportPersistent.ClientSupportPersistent);

            Smb2CreateContextRequest[]  contexts;
            RequestedOplockLevel_Values oplockLevel;
            LeaseStateValues            requestLeaseState;

            FillParameters(leaseState, requestedOplockLevel, modelDurableHandle, createGuidMainChannel,
                           leaseKeyMainChannel, out requestLeaseState, out oplockLevel, out contexts);

            Smb2CreateContextResponse[] serverCreateContexts;
            smb2ClientMainChannel.Create(
                treeIdMainChannel,
                fileNameMainChannel,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileIdMainChannel,
                out serverCreateContexts,
                oplockLevel,
                contexts
                );

            ReplayModelDurableHandle preparedHandle = ConvertHandle(serverCreateContexts);

            Site.Assert.IsTrue(modelDurableHandle == preparedHandle, "Prepared handle should be {0}, actual is {1}", modelDurableHandle, preparedHandle);

            prepared = true;
        }
Пример #2
0
 public ModelReplayCreateRequest(ModelReplayChannel channel,
                                 ReplayModelSwitchChannelType switchChannelType,
                                 ReplayModelChannelSequenceType channelSequence,
                                 ReplayModelDurableHandle modelDurableHandle,
                                 ReplayModelRequestedOplockLevel requestedOplockLevel,
                                 ReplayModelFileName fileName,
                                 ReplayModelCreateGuid createGuid,
                                 ReplayModelFileAttributes fileAttributes,
                                 ReplayModelCreateDisposition createDisposition,
                                 ReplayModelLeaseState leaseState,
                                 ReplayModelSetReplayFlag isSetReplayFlag,
                                 ReplayModelLeaseKey leaseKey)
     : base(0)
 {
     this.channel              = channel;
     this.switchChannelType    = switchChannelType;
     this.channelSequence      = channelSequence;
     this.modelDurableHandle   = modelDurableHandle;
     this.requestedOplockLevel = requestedOplockLevel;
     this.fileName             = fileName;
     this.createGuid           = createGuid;
     this.fileAttributes       = fileAttributes;
     this.createDisposition    = createDisposition;
     this.leaseState           = leaseState;
     this.isSetReplayFlag      = isSetReplayFlag;
     this.leaseKey             = leaseKey;
 }
 public ModelReplayCreateRequest(ModelReplayChannel channel,
     ReplayModelSwitchChannelType switchChannelType,
     ReplayModelChannelSequenceType channelSequence,
     ReplayModelDurableHandle modelDurableHandle,
     ReplayModelRequestedOplockLevel requestedOplockLevel,
     ReplayModelFileName fileName,
     ReplayModelCreateGuid createGuid,
     ReplayModelFileAttributes fileAttributes,
     ReplayModelCreateDisposition createDisposition,
     ReplayModelLeaseState leaseState,
     ReplayModelSetReplayFlag isSetReplayFlag,
     ReplayModelLeaseKey leaseKey)
     : base(0)
 {
     this.channel = channel;
     this.switchChannelType = switchChannelType;
     this.channelSequence = channelSequence;
     this.modelDurableHandle = modelDurableHandle;
     this.requestedOplockLevel = requestedOplockLevel;
     this.fileName = fileName;
     this.createGuid = createGuid;
     this.fileAttributes = fileAttributes;
     this.createDisposition = createDisposition;
     this.leaseState = leaseState;
     this.isSetReplayFlag = isSetReplayFlag;
     this.leaseKey = leaseKey;
 }
        public void CreateRequest(
            ModelDialectRevision maxSmbVersionClientSupported,
            ReplayModelShareType shareType,
            ReplayModelClientSupportPersistent isClientSupportPersistent,
            ReplayModelSwitchChannelType switchChannelType,
            ReplayModelChannelSequenceType channelSequence,
            ReplayModelSetReplayFlag isSetReplayFlag,
            ReplayModelDurableHandle modelDurableHandle,
            ReplayModelRequestedOplockLevel requestedOplockLevel,
            ReplayModelLeaseState leaseState,
            ReplayModelFileName fileName,
            ReplayModelCreateGuid createGuid,
            ReplayModelFileAttributes fileAttributes,
            ReplayModelCreateDisposition createDisposition,
            ReplayModelLeaseKey leaseKey)
        {
            Smb2FunctionalClient client = null;

            switch (switchChannelType)
            {
            case ReplayModelSwitchChannelType.MainChannel:
            {
                if (smb2ClientMainChannel == null)
                {
                    InitializeMainChannel(maxSmbVersionClientSupported, clientGuidMainChannel, shareType,
                                          out treeIdMainChannel, false,
                                          isClientSupportPersistent == ReplayModelClientSupportPersistent.ClientSupportPersistent);
                }
                break;
            }

            case ReplayModelSwitchChannelType.ReconnectMainChannel:
            {
                Site.Assume.IsNotNull(smb2ClientMainChannel, "Main channel is expected to exist.");
                smb2ClientMainChannel.Disconnect();
                smb2ClientMainChannel = null;
                InitializeMainChannel(maxSmbVersionClientSupported, clientGuidMainChannel, shareType,
                                      out treeIdMainChannel, true,
                                      isClientSupportPersistent == ReplayModelClientSupportPersistent.ClientSupportPersistent);
                break;
            }

            default:     //AlternativeChannelWithMainChannel, AlternativeChannelWithDisconnectMainChannel, MainChannelWithAlternativeChannel
            {
                InitializeAlternativeChannel(
                    clientGuidMainChannel,
                    treeIdMainChannel,
                    isClientSupportPersistent == ReplayModelClientSupportPersistent.ClientSupportPersistent);

                if (switchChannelType == ReplayModelSwitchChannelType.AlternativeChannelWithDisconnectMainChannel)
                {
                    smb2ClientMainChannel.Disconnect();
                    smb2ClientMainChannel = null;
                }
                break;
            }
            }

            if (switchChannelType == ReplayModelSwitchChannelType.AlternativeChannelWithDisconnectMainChannel ||
                switchChannelType == ReplayModelSwitchChannelType.AlternativeChannelWithMainChannel)
            {
                client = smb2ClientAlternativeChannel;
            }
            else
            {
                client = smb2ClientMainChannel;
            }

            Smb2CreateContextRequest[]  contexts;
            RequestedOplockLevel_Values oplockLevel;
            LeaseStateValues            requestLeaseState;

            FillParameters(leaseState,
                           requestedOplockLevel,
                           modelDurableHandle,
                           createGuid == ReplayModelCreateGuid.DefaultCreateGuid ? createGuidMainChannel : Guid.NewGuid(),
                           leaseKey == ReplayModelLeaseKey.DefaultLeaseKey ? leaseKeyMainChannel : Guid.NewGuid(),
                           out requestLeaseState,
                           out oplockLevel,
                           out contexts);

            FillChannelSequence(client, channelSequence);

            Smb2CreateContextResponse[] serverCreateContexts;
            ulong createRequestId;

            client.CreateRequest(
                treeIdMainChannel,
                fileName == ReplayModelFileName.DefaultFileName ? fileNameMainChannel : Guid.NewGuid().ToString(),
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                (isSetReplayFlag == ReplayModelSetReplayFlag.WithReplayFlag ? Packet_Header_Flags_Values.FLAGS_REPLAY_OPERATION : Packet_Header_Flags_Values.NONE) | (testConfig.SendSignedRequest ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE),
                out createRequestId,
                oplockLevel,
                contexts,
                createDisposition: createDisposition == ReplayModelCreateDisposition.DefaultCreateDisposition ? CreateDisposition_Values.FILE_OPEN_IF : CreateDisposition_Values.FILE_OVERWRITE_IF,
                fileAttributes: fileAttributes == ReplayModelFileAttributes.DefaultFileAttributes ? File_Attributes.NONE : File_Attributes.FILE_ATTRIBUTE_TEMPORARY
                );

            uint status = client.CreateResponse(
                createRequestId,
                out fileIdMainChannel,
                out serverCreateContexts,
                checker: (header, response) =>
            {
            }
                );

            CreateResponse(
                (ModelSmb2Status)status,
                ConvertHandle(serverCreateContexts),
                replayConfig);
        }
        private void FillParameters(ReplayModelLeaseState leaseState,
                                    ReplayModelRequestedOplockLevel requestedOplockLevel,
                                    ReplayModelDurableHandle modelDurableHandle,
                                    Guid createGuid,
                                    Guid leaseKey,
                                    out LeaseStateValues requestLeaseState,
                                    out RequestedOplockLevel_Values oplockLevel,
                                    out Smb2CreateContextRequest[] contexts)
        {
            #region Fill lease state
            switch (leaseState)
            {
            case ReplayModelLeaseState.LeaseStateNotIncludeH:
                requestLeaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING;
                break;

            case ReplayModelLeaseState.LeaseStateIncludeH:
                requestLeaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING;
                break;

            default:
                requestLeaseState = LeaseStateValues.SMB2_LEASE_NONE;
                break;
            }
            #endregion

            #region Fill oplockLevel and lease context
            contexts = new Smb2CreateContextRequest[] { };
            switch (requestedOplockLevel)
            {
            case ReplayModelRequestedOplockLevel.OplockLevelLeaseV1:
                testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE);

                oplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE;
                contexts    = new Smb2CreateContextRequest[]
                {
                    new Smb2CreateRequestLease
                    {
                        LeaseKey   = leaseKey,
                        LeaseState = requestLeaseState,
                        LeaseFlags = (uint)LeaseFlagsValues.NONE
                    }
                };
                break;

            case ReplayModelRequestedOplockLevel.OplockLevelLeaseV2:
                testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE_V2);

                oplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE;
                contexts    = new Smb2CreateContextRequest[]
                {
                    new Smb2CreateRequestLeaseV2
                    {
                        LeaseKey   = leaseKey,
                        LeaseState = requestLeaseState,
                        LeaseFlags = (uint)LeaseFlagsValues.NONE
                    }
                };
                break;

            case ReplayModelRequestedOplockLevel.OplockLevelBatch:
                oplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_BATCH;
                break;

            case ReplayModelRequestedOplockLevel.OplockLevelII:
                oplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_II;
                break;

            default:
                oplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE;
                break;
            }
            #endregion

            #region Fill handle context
            switch (modelDurableHandle)
            {
            case ReplayModelDurableHandle.DurableHandleV1:
                testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_REQUEST);

                contexts = Smb2Utility.Append <Smb2CreateContextRequest>(contexts,
                                                                         new Smb2CreateDurableHandleRequest
                {
                });
                break;

            case ReplayModelDurableHandle.DurableHandleV2:
                testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2);

                contexts = Smb2Utility.Append <Smb2CreateContextRequest>(contexts,
                                                                         new Smb2CreateDurableHandleRequestV2
                {
                    CreateGuid = createGuid,
                    Timeout    = 120 * 1000,
                });
                break;

            case ReplayModelDurableHandle.DurableHandleV2Persistent:
                testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2);

                contexts = Smb2Utility.Append <Smb2CreateContextRequest>(contexts,
                                                                         new Smb2CreateDurableHandleRequestV2
                {
                    CreateGuid = createGuid,
                    Flags      = CREATE_DURABLE_HANDLE_REQUEST_V2_Flags.DHANDLE_FLAG_PERSISTENT,
                    Timeout    = 120 * 1000,
                });
                break;

            default:
                break;
            }
            #endregion
        }
 /// <summary>
 /// Parameterless constructor
 /// </summary>
 public ReplayOpen()
 {
     ConnectionIsNotNull = true;
     IsDurable = false;
     IsPersistent = false;
     OutstandingRequestCount = 0;
     OutstandingPreRequestCount = 0;
     Lease = null;
     CreateGuidIsNotNull = false;
     OplockLevel = ReplayModelRequestedOplockLevel.OplockLevelNone;
     OplockStateIsHeld = false;
 }
        public static void CreateRequest(
            ModelDialectRevision maxSmbVersionClientSupported,
            ReplayModelShareType shareType,
            ReplayModelClientSupportPersistent clientPersistentCapability,
            ReplayModelSwitchChannelType switchChannelType,
            ReplayModelChannelSequenceType channelSequence,
            ReplayModelSetReplayFlag isSetReplayFlag,
            ReplayModelDurableHandle modelDurableHandle,
            ReplayModelRequestedOplockLevel requestedOplockLevel,
            ReplayModelLeaseState leaseState,
            ReplayModelFileName fileName,
            ReplayModelCreateGuid createGuid,
            ReplayModelFileAttributes fileAttributes,
            ReplayModelCreateDisposition createDisposition,
            ReplayModelLeaseKey leaseKey)
        {
            Condition.IsTrue(State == ModelState.Connected || State == ModelState.Initialized);
            Condition.IsNull(Request);

            Combination.NWise(2, maxSmbVersionClientSupported, shareType, clientPersistentCapability, switchChannelType, channelSequence, isSetReplayFlag, modelDurableHandle,
                requestedOplockLevel, leaseState, fileName, createGuid, fileAttributes, createDisposition, leaseKey);

            Combination.Isolated(channelSequence == ReplayModelChannelSequenceType.InvalidChannelSequence);
            Combination.Isolated(channelSequence == ReplayModelChannelSequenceType.ChannelSequenceBoundaryValid);

            //No lease for non durable handle 
            Condition.IfThen(modelDurableHandle == ReplayModelDurableHandle.NormalHandle,
                requestedOplockLevel != ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 &&
                requestedOplockLevel != ReplayModelRequestedOplockLevel.OplockLevelLeaseV2);

            //No lease state or lease key(default) if not requesting lease
            Condition.IfThen(
                requestedOplockLevel != ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 &&
                requestedOplockLevel != ReplayModelRequestedOplockLevel.OplockLevelLeaseV2,
                leaseState == ReplayModelLeaseState.LeaseStateIsNone && leaseKey == ReplayModelLeaseKey.DefaultLeaseKey);

            //Ensure valid lease state if requesting lease
            Condition.IfThen(
                requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 ||
                requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV2,
                leaseState != ReplayModelLeaseState.LeaseStateIsNone);

            if (State == ModelState.Initialized)
            {
                Condition.IsTrue(switchChannelType == ReplayModelSwitchChannelType.MainChannel);

                DialectRevision negotiateDialect = ModelHelper.DetermineNegotiateDialect(maxSmbVersionClientSupported,
                    Config.MaxSmbVersionSupported);

                MainChannel = new ModelReplayChannel(negotiateDialect, shareType,
                    clientPersistentCapability == ReplayModelClientSupportPersistent.ClientSupportPersistent);
            }
            else // There's already an open exist
            {
                //Open eixsts
                Condition.IsTrue(Open != null);

                // Ensure same dialect
                Condition.IsTrue(ModelUtility.GetDialectRevision(maxSmbVersionClientSupported) == MainChannel.Connection_NegotiateDialect);

                // Ensure connect to same share
                Condition.IsTrue(shareType == MainChannel.Connection_Session_TreeConnect_Share_IsCA);

                switch (switchChannelType)
                {
                    case ReplayModelSwitchChannelType.MainChannel:
                    {
                        Condition.IsTrue((clientPersistentCapability ==
                                          ReplayModelClientSupportPersistent.ClientSupportPersistent) ==
                                         MainChannel.Connection_ClientCapabilities_SupportPersistent);
                        break;
                    }
                    case ReplayModelSwitchChannelType.ReconnectMainChannel:
                    {
                        MainChannel.Connection_ClientCapabilities_SupportPersistent =
                            (clientPersistentCapability == ReplayModelClientSupportPersistent.ClientSupportPersistent);
                        break;
                    }
                    case ReplayModelSwitchChannelType.AlternativeChannelWithDisconnectMainChannel:
                    case ReplayModelSwitchChannelType.AlternativeChannelWithMainChannel:
                    case ReplayModelSwitchChannelType.MainChannelWithAlternativeChannel:
                    {
                        AlternativeChannel = new ModelReplayChannel(MainChannel.Connection_NegotiateDialect, shareType,
                            clientPersistentCapability == ReplayModelClientSupportPersistent.ClientSupportPersistent);
                        break;
                    }
                }

                #region Handle state changes when there's connection lost or reconnection
                if (switchChannelType == ReplayModelSwitchChannelType.AlternativeChannelWithDisconnectMainChannel ||
                    switchChannelType == ReplayModelSwitchChannelType.ReconnectMainChannel)
                {
                    bool isPreserved = false;

                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.7.1: The server MUST iterate over the Session.OpenTable and determine whether each Open is to be preserved for reconnect." +
                        " If any of the following conditions is satisfied, it indicates that the Open is to be preserved for reconnect");
                    ModelHelper.Log(
                        LogType.TestInfo,
                        "Open.OplockLevel is {0}, Open.OplockState is {1}, Open.IsDurable {2}", Open.OplockLevel,
                        Open.OplockStateIsHeld ? "Held" : "not Held", Open.IsDurable);
                    if (Open.Lease != null)
                    {
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "LeaseState is {0}", Open.Lease.LeaseState);
                    }

                    if (switchChannelType == ReplayModelSwitchChannelType.AlternativeChannelWithDisconnectMainChannel)
                    {
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "TD does not states the open is preserved when multi channels exist.");
                        isPreserved = true;
                    }
                    else if (Open.OplockLevel == ReplayModelRequestedOplockLevel.OplockLevelBatch &&
                             Open.OplockStateIsHeld &&
                             Open.IsDurable) // Open.OplockLevel is equal to SMB2_OPLOCK_LEVEL_BATCH
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "Open.OplockLevel is equal to SMB2_OPLOCK_LEVEL_BATCH and Open.OplockState is equal to Held, and Open.IsDurable is TRUE");

                        isPreserved = true;

                        ModelHelper.Log(
                            LogType.TestInfo,
                            "Open is to be preserved for reconnect");
                    }
                    else if (((Open.OplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 ||
                               Open.OplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV2) && 
                              Open.Lease != null &&
                              Open.Lease.LeaseState == ReplayModelLeaseState.LeaseStateIncludeH &&
                              Open.OplockStateIsHeld &&
                              Open.IsDurable)) // Open.OplockLevel is equal to SMB2_OPLOCK_LEVEL_LEASE and contains SMB2_LEASE_HANDLE_CACHING
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "Open.OplockLevel is equal to SMB2_OPLOCK_LEVEL_LEASE, Lease.LeaseState contains SMB2_LEASE_HANDLE_CACHING," +
                            " Open.OplockState is equal to Held, and Open.IsDurable is TRUE.");

                        isPreserved = true;

                        ModelHelper.Log(
                            LogType.TestInfo,
                            "Open is to be preserved for reconnect");
                    }
                    // "The server supports leasing and Open.IsResilient is TRUE" covered by resilient model

                    if (isPreserved)
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "If the Open is to be preserved for reconnect, perform the following actions:");
                        ModelHelper.Log(
                            LogType.Requirement,
                            "Set Open.Connection to NULL");
                        //Skip requirement for resilient handle which covered by resilient model

                        Open.ConnectionIsNotNull = false;
                    }
                    else
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "If the Open is not to be preserved for reconnect, the server MUST close the Open as specified in section 3.3.4.17");

                        LastOpen = Open;
                        Open = null;

                        ModelHelper.Log(
                            LogType.TestInfo,
                            "Open is set to NULL");
                    }
                }
                #endregion

            }

            ModelReplayChannel channel = GetChannel(switchChannelType);

            ModelReplayCreateRequest replayCreateRequest = 
                new ModelReplayCreateRequest(channel, switchChannelType, channelSequence, modelDurableHandle, requestedOplockLevel, fileName,
                    createGuid, fileAttributes, createDisposition, leaseState, isSetReplayFlag, leaseKey);

            Request = replayCreateRequest;
            State = ModelState.Connected;
        }
        public static void PrepareCreate(
            ModelDialectRevision maxSmbVersionClientSupported,
            ReplayModelClientSupportPersistent clientPersistentCapability,
            ReplayModelDurableHandle modelDurableHandle,
            ReplayModelShareType shareType,
            ReplayModelRequestedOplockLevel requestedOplockLevel,
            ReplayModelLeaseState leaseState)
        {
            Condition.IsNull(MainChannel);

            DialectRevision negotiateDialect = ModelHelper.DetermineNegotiateDialect(maxSmbVersionClientSupported,
                Config.MaxSmbVersionSupported);

            Combination.NWise(2, maxSmbVersionClientSupported, clientPersistentCapability, modelDurableHandle, shareType,
                requestedOplockLevel, leaseState);

            //No lease state if no lease requested
            Condition.IfThen(requestedOplockLevel != ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 && 
                requestedOplockLevel != ReplayModelRequestedOplockLevel.OplockLevelLeaseV2,
                leaseState == ReplayModelLeaseState.LeaseStateIsNone);

            //Do not set lease state to none if requesting a lease
            Condition.IfThen(requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 || 
                requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV2,
                leaseState != ReplayModelLeaseState.LeaseStateIsNone);

            MainChannel = new ModelReplayChannel(negotiateDialect, shareType, 
                clientPersistentCapability == ReplayModelClientSupportPersistent.ClientSupportPersistent);

            if (Config.TreeConnect_Share_Type_Include_STYPE_CLUSTER_SOFS &&
                requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelBatch)
            {
                // Replay will always use 3.x family
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.9: If Connection.Dialect belongs to the SMB 3.x dialect family TreeConnect.Share.Type" +
                    " includes STYPE_CLUSTER_SOFS and the RequestedOplockLevel is SMB2_OPLOCK_LEVEL_BATCH," +
                    " the server MUST set RequestedOplockLevel to SMB2_OPLOCK_LEVEL_II");

                requestedOplockLevel = ReplayModelRequestedOplockLevel.OplockLevelII;
            }

            Open = new ReplayOpen();

            if (requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV1)
            {
                // Replay will always use 3.x family
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.9: If Connection.Dialect is \"2.100\" or belongs to the \"3.x\" dialect family, and the DataLength field equals 0x20," +
                    " the server MUST attempt to acquire a lease on the open from the underlying object store as described in section 3.3.5.9.8");
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.9.8: The server MUST set Open.OplockState to Held");

                Open.Lease = new ReplayLease(leaseState);
                Open.OplockStateIsHeld = true;
            }

            if (requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV2)
            {
                // Replay will always use 3.x family
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.9: If Connection.Dialect belongs to the \"3.x\" dialect family, and the DataLength field equals 0x34," +
                    " the server MUST attempt to acquire a lease on the open from the underlying object store, as described in section 3.3.5.9.11");
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.9.11: The server MUST set Open.OplockState to Held");

                Open.Lease = new ReplayLease(leaseState);
                Open.OplockStateIsHeld = true;
            }

            Open.OplockLevel = requestedOplockLevel;
            State = ModelState.Connected;

            switch (modelDurableHandle)
            {
                case ReplayModelDurableHandle.DurableHandleV1:
                {
                    if (requestedOplockLevel != ReplayModelRequestedOplockLevel.OplockLevelBatch &&
                        !((requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 ||
                           requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV2) && 
                          leaseState == ReplayModelLeaseState.LeaseStateIncludeH))
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "3.3.5.9.6: If the RequestedOplockLevel field in the create request is not set to SMB2_OPLOCK_LEVEL_BATCH and" +
                            " the create request does not include an SMB2_CREATE_REQUEST_LEASE create context with a LeaseState field that includes the SMB2_LEASE_HANDLE_CACHING bit value," +
                            " the server MUST ignore this create context and skip this section.");
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "Create context is ignored and skipped due to above conditions");
                        ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    }
                    else
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "3.3.5.9.6: In the \"Successful Open Initialization\" phase, the server MUST set Open.IsDurable to TRUE." +
                            " This permits the client to use Open.DurableFileId to request a reopen of the file on a subsequent request as specified in section 3.3.5.9.7." +
                            " The server MUST also set Open.DurableOwner to a security descriptor accessible only by the user represented by Open.Session.SecurityContext.");

                        Open.IsDurable = true;

                        ModelHelper.Log(LogType.TestInfo, "Open.IsDurable is set to TRUE");
                    }
                    break;
                }
                case ReplayModelDurableHandle.DurableHandleV2:
                case ReplayModelDurableHandle.DurableHandleV2Persistent:
                {
                    if (modelDurableHandle == ReplayModelDurableHandle.DurableHandleV2 &&
                        requestedOplockLevel != ReplayModelRequestedOplockLevel.OplockLevelBatch &&
                        !((requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 ||
                           requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV2) &&
                          leaseState == ReplayModelLeaseState.LeaseStateIncludeH))
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "3.3.5.9.10: If the SMB2_DHANDLE_FLAG_PERSISTENT bit is not set in the Flags field of this create context," +
                            " if RequestedOplockLevel in the create request is not set to SMB2_OPLOCK_LEVEL_BATCH, and if the create request does not include" +
                            " a SMB2_CREATE_REQUEST_LEASE or SMB2_CREATE_REQUEST_LEASE_V2 create context with a LeaseState field that includes SMB2_LEASE_HANDLE_CACHING," +
                            " the server MUST ignore this create context and skip this section");
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "Create context is ignored and skipped due to above conditions");
                        ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    }
                    else
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "3.3.5.9.10: The server MUST set Open.CreateGuid to the CreateGuid in SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2.");

                        Open.CreateGuidIsNotNull = true;

                        ModelHelper.Log(
                            LogType.Requirement,
                            "3.3.5.9.10: In the \"Successful Open Initialization\" phase, the server MUST set Open.IsDurable to TRUE." +
                            " The server MUST also set Open.DurableOwner to a security descriptor accessible only by the user represented by Open.Session.SecurityContext.");

                        Open.IsDurable = true;

                        ModelHelper.Log(LogType.TestInfo, "Open.IsDurable is set to TRUE");

                        if (modelDurableHandle == ReplayModelDurableHandle.DurableHandleV2Persistent &&
                            shareType == ReplayModelShareType.CAShare &&
                            clientPersistentCapability == ReplayModelClientSupportPersistent.ClientSupportPersistent) //assume connection dialect always 3.x
                        {
                            ModelHelper.Log(
                                LogType.Requirement,
                                "3.3.5.9.10: If the SMB2_DHANDLE_FLAG_PERSISTENT bit is set in the Flags field of the request, TreeConnect.Share.IsCA is TRUE," +
                                " and Connection.ServerCapabilities includes SMB2_GLOBAL_CAP_PERSISTENT_HANDLES, the server MUST set Open.IsPersistent to TRUE");

                            Open.IsPersistent = true;

                            ModelHelper.Log(LogType.TestInfo, "Open.IsPersistent is set to TRUE");
                        }
                    }
                    break;
                }
                case ReplayModelDurableHandle.NormalHandle:
                {
                    //Do nothing for NormalHandle
                    break;
                }
                default:
                    break;
            }
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="modelDurableHandle">Type of durable handle for this open</param>
        /// <param name="isPersistent">Indicate if the open is persistent</param>
        /// <param name="oplockLevel">Indicate the oplock level</param>
        public ReplayOpen(ReplayModelDurableHandle modelDurableHandle, bool isPersistent, ReplayModelRequestedOplockLevel oplockLevel)
        {
            ConnectionIsNotNull = true;

            if (modelDurableHandle != ReplayModelDurableHandle.NormalHandle)
            {
                IsDurable = true;

                if (modelDurableHandle == ReplayModelDurableHandle.DurableHandleV2Persistent)
                {
                    IsPersistent = isPersistent;
                }
            }

            OutstandingRequestCount = 0;
            OutstandingPreRequestCount = 0;
            Lease = null;
            CreateGuidIsNotNull = false;
            OplockLevel = oplockLevel;
        }
        public void CreateRequest(
            ModelDialectRevision maxSmbVersionClientSupported,
            ReplayModelShareType shareType,
            ReplayModelClientSupportPersistent isClientSupportPersistent,
            ReplayModelSwitchChannelType switchChannelType,
            ReplayModelChannelSequenceType channelSequence,
            ReplayModelSetReplayFlag isSetReplayFlag,
            ReplayModelDurableHandle modelDurableHandle,
            ReplayModelRequestedOplockLevel requestedOplockLevel,
            ReplayModelLeaseState leaseState,
            ReplayModelFileName fileName,
            ReplayModelCreateGuid createGuid,
            ReplayModelFileAttributes fileAttributes,
            ReplayModelCreateDisposition createDisposition,
            ReplayModelLeaseKey leaseKey)
        {
            Smb2FunctionalClient client = null;

            switch (switchChannelType)
            {
                case ReplayModelSwitchChannelType.MainChannel:
                {
                    if (smb2ClientMainChannel == null)
                    {
                        InitializeMainChannel(maxSmbVersionClientSupported, clientGuidMainChannel, shareType,
                            out treeIdMainChannel, false,
                            isClientSupportPersistent == ReplayModelClientSupportPersistent.ClientSupportPersistent);
                    }
                    break;
                }
                case ReplayModelSwitchChannelType.ReconnectMainChannel:
                {
                    Site.Assume.IsNotNull(smb2ClientMainChannel, "Main channel is expected to exist.");
                    smb2ClientMainChannel.Disconnect();
                    smb2ClientMainChannel = null;
                    InitializeMainChannel(maxSmbVersionClientSupported, clientGuidMainChannel, shareType,
                        out treeIdMainChannel, true,
                        isClientSupportPersistent == ReplayModelClientSupportPersistent.ClientSupportPersistent);
                    break;
                }
                default: //AlternativeChannelWithMainChannel, AlternativeChannelWithDisconnectMainChannel, MainChannelWithAlternativeChannel
                {
                    InitializeAlternativeChannel(
                        clientGuidMainChannel,
                        treeIdMainChannel,
                        isClientSupportPersistent == ReplayModelClientSupportPersistent.ClientSupportPersistent);

                    if (switchChannelType == ReplayModelSwitchChannelType.AlternativeChannelWithDisconnectMainChannel)
                    {
                        smb2ClientMainChannel.Disconnect();
                        smb2ClientMainChannel = null;
                    }
                    break;
                }
            }

            if (switchChannelType == ReplayModelSwitchChannelType.AlternativeChannelWithDisconnectMainChannel ||
                switchChannelType == ReplayModelSwitchChannelType.AlternativeChannelWithMainChannel)
            {
                client = smb2ClientAlternativeChannel;
            }
            else
            {
                client = smb2ClientMainChannel;
            }

            Smb2CreateContextRequest[] contexts;
            RequestedOplockLevel_Values oplockLevel;
            LeaseStateValues requestLeaseState;

            FillParameters(leaseState,
                requestedOplockLevel,
                modelDurableHandle,
                createGuid == ReplayModelCreateGuid.DefaultCreateGuid ? createGuidMainChannel : Guid.NewGuid(),
                leaseKey == ReplayModelLeaseKey.DefaultLeaseKey ? leaseKeyMainChannel : Guid.NewGuid(),
                out requestLeaseState,
                out oplockLevel,
                out contexts);

            FillChannelSequence(client, channelSequence);

            Smb2CreateContextResponse[] serverCreateContexts;
            ulong createRequestId;
            client.CreateRequest(
                    treeIdMainChannel,
                    fileName == ReplayModelFileName.DefaultFileName ? fileNameMainChannel : Guid.NewGuid().ToString(),
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    (isSetReplayFlag == ReplayModelSetReplayFlag.WithReplayFlag ? Packet_Header_Flags_Values.FLAGS_REPLAY_OPERATION : Packet_Header_Flags_Values.NONE) | (testConfig.SendSignedRequest ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE),
                    out createRequestId,
                    oplockLevel,
                    contexts,
                    createDisposition: createDisposition == ReplayModelCreateDisposition.DefaultCreateDisposition ? CreateDisposition_Values.FILE_OPEN_IF : CreateDisposition_Values.FILE_OVERWRITE_IF,
                    fileAttributes: fileAttributes == ReplayModelFileAttributes.DefaultFileAttributes ? File_Attributes.NONE : File_Attributes.FILE_ATTRIBUTE_TEMPORARY
                 );

            uint status = client.CreateResponse(
                    createRequestId,
                    out fileIdMainChannel,
                    out serverCreateContexts,
                    checker: (header, response) =>
                    {
                    }
                 );

            CreateResponse(
                (ModelSmb2Status)status,
                ConvertHandle(serverCreateContexts),
                replayConfig);
        }
        private void FillParameters(ReplayModelLeaseState leaseState, 
            ReplayModelRequestedOplockLevel requestedOplockLevel,
            ReplayModelDurableHandle modelDurableHandle,
            Guid createGuid,
            Guid leaseKey,
            out LeaseStateValues requestLeaseState,
            out RequestedOplockLevel_Values oplockLevel,
            out Smb2CreateContextRequest[] contexts)
        {
            #region Fill lease state
            switch (leaseState)
            {
                case ReplayModelLeaseState.LeaseStateNotIncludeH:
                    requestLeaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING;
                    break;
                case ReplayModelLeaseState.LeaseStateIncludeH:
                    requestLeaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING;
                    break;
                default:
                    requestLeaseState = LeaseStateValues.SMB2_LEASE_NONE;
                    break;
            }
            #endregion

            #region Fill oplockLevel and lease context
            contexts = new Smb2CreateContextRequest[] { };
            switch (requestedOplockLevel)
            {
                case ReplayModelRequestedOplockLevel.OplockLevelLeaseV1:
                    testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE);

                    oplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE;
                    contexts = new Smb2CreateContextRequest[]
                    {
                        new Smb2CreateRequestLease
                        {
                            LeaseKey = leaseKey,
                            LeaseState = requestLeaseState,
                            LeaseFlags = (uint)LeaseFlagsValues.NONE
                        }
                    };
                    break;
                case ReplayModelRequestedOplockLevel.OplockLevelLeaseV2:
                    testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE_V2);

                    oplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE;
                    contexts = new Smb2CreateContextRequest[]
                    {
                        new Smb2CreateRequestLeaseV2
                        {
                            LeaseKey = leaseKey,
                            LeaseState = requestLeaseState,
                            LeaseFlags = (uint)LeaseFlagsValues.NONE
                        }
                    };
                    break;
                case ReplayModelRequestedOplockLevel.OplockLevelBatch:
                    oplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_BATCH;
                    break;
                case ReplayModelRequestedOplockLevel.OplockLevelII:
                    oplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_II;
                    break;
                default:
                    oplockLevel = RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE;
                    break;
            }
            #endregion

            #region Fill handle context
            switch (modelDurableHandle)
            {
                case ReplayModelDurableHandle.DurableHandleV1:
                    testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_REQUEST);

                    contexts = Smb2Utility.Append<Smb2CreateContextRequest>(contexts,
                            new Smb2CreateDurableHandleRequest
                            {
                            });
                    break;
                case ReplayModelDurableHandle.DurableHandleV2:
                    testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2);

                    contexts = Smb2Utility.Append<Smb2CreateContextRequest>(contexts,
                            new Smb2CreateDurableHandleRequestV2
                            {
                                CreateGuid = createGuid,
                                Timeout = 120 * 1000,
                            });
                    break;
                case ReplayModelDurableHandle.DurableHandleV2Persistent:
                    testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2);

                    contexts = Smb2Utility.Append<Smb2CreateContextRequest>(contexts,
                            new Smb2CreateDurableHandleRequestV2
                            {
                                CreateGuid = createGuid,
                                Flags = CREATE_DURABLE_HANDLE_REQUEST_V2_Flags.DHANDLE_FLAG_PERSISTENT,
                                Timeout = 120 * 1000,
                            });
                    break;
                default:
                    break;
            }
            #endregion
        }
        public void PrepareCreate(
            ModelDialectRevision maxSmbVersionClientSupported,
            ReplayModelClientSupportPersistent isClientSupportPersistent,
            ReplayModelDurableHandle modelDurableHandle,
            ReplayModelShareType shareType,
            ReplayModelRequestedOplockLevel requestedOplockLevel,
            ReplayModelLeaseState leaseState)
        {
            InitializeMainChannel(maxSmbVersionClientSupported, clientGuidMainChannel, shareType, out treeIdMainChannel, false, isClientSupportPersistent == ReplayModelClientSupportPersistent.ClientSupportPersistent);

            Smb2CreateContextRequest[] contexts;
            RequestedOplockLevel_Values oplockLevel;
            LeaseStateValues requestLeaseState;

            FillParameters(leaseState, requestedOplockLevel, modelDurableHandle, createGuidMainChannel,
                leaseKeyMainChannel, out requestLeaseState, out oplockLevel, out contexts);

            Smb2CreateContextResponse[] serverCreateContexts;
            smb2ClientMainChannel.Create(
                treeIdMainChannel,
                fileNameMainChannel,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileIdMainChannel,
                out serverCreateContexts,
                oplockLevel,
                contexts
            );

            ReplayModelDurableHandle preparedHandle = ConvertHandle(serverCreateContexts);
            Site.Assert.IsTrue(modelDurableHandle == preparedHandle, "Prepared handle should be {0}, actual is {1}", modelDurableHandle, preparedHandle);

            prepared = true;
        }