public void DurableHandleV1_WithLeaseV1_WithoutHandleCaching() { /// 1. Client requests a durable handle with LeaseV1 context, SMB2_LEASE_HANDLE_CACHING bit is not set in LeaseState. /// 2. Durable Handle is not granted. #region Check Applicability TestConfig.CheckDialect(DialectRevision.Smb21); TestConfig.CheckCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING); TestConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_REQUEST, CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE); #endregion string content = Smb2Utility.CreateRandomString(testConfig.WriteBufferLengthInKb); fileName = "DurableHandleV1_WithLeaseV1_WithoutHandleCaching" + Guid.NewGuid() + ".txt"; durableHandleUncSharePath = Smb2Utility.GetUncPath(testConfig.SutComputerName, testConfig.BasicFileShare); BaseTestSite.Log.Add( LogEntryKind.Comment, "Client connects to server and opens file with a durable handle, SMB2_LEASE_HANDLE_CACHING bit is not set in LeaseState."); uint treeIdBeforeDisconnection; Connect(DialectRevision.Smb21, clientBeforeDisconnection, clientGuid, testConfig.AccountCredential, ConnectShareType.BasicShareWithoutAssert, out treeIdBeforeDisconnection, null); Guid leaseKey = Guid.NewGuid(); // SMB2_LEASE_HANDLE_CACHING bit is not set in LeaseState LeaseStateValues leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING; FILEID fileIdBeforeDisconnection; Smb2CreateContextResponse[] serverCreateContexts = null; clientBeforeDisconnection.Create( treeIdBeforeDisconnection, fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdBeforeDisconnection, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleRequest { DurableRequest = Guid.Empty, }, new Smb2CreateRequestLease { LeaseKey = leaseKey, LeaseState = leaseState, } }, shareAccess: ShareAccess_Values.NONE, checker: (header, response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "{0} should be successful, actually server returns {1}.", header.Command, Smb2Status.GetStatusCode(header.Status)); // Durable Handle should not be granted. CheckCreateContextResponsesNotExist(serverCreateContexts, new DefaultDurableHandleResponseChecker(BaseTestSite)); }); clientBeforeDisconnection.TreeDisconnect(treeIdBeforeDisconnection); clientBeforeDisconnection.LogOff(); clientBeforeDisconnection.Disconnect(); }
/// <summary> /// Attempt to trigger LeaseBreakNotification from a separate client /// </summary> /// <param name="client">Client to trigger LeaseBreakNotification</param> /// <param name="requestDialect">Negotiate dialects</param> /// <param name="serverName">Name of file server to access</param> /// <param name="isDirectory">True value indicating to open a directory, false for a file</param> /// <param name="requestedLeaseState">LeaseState when open the directory or file</param> /// <param name="accessMask">AccessMask when open the directory or file</param> private void TriggerBreakFromClient( Smb2FunctionalClient client, DialectRevision[] requestDialect, string serverName, bool isDirectory, LeaseStateValues requestedLeaseState, AccessMask accessMask) { BaseTestSite.Log.Add(LogEntryKind.Debug, "AfterFailover: Attempt to access same file/directory to trigger LeaseBreakNotification from a separate client with LeaseState {0} and AccessMask {1}", requestedLeaseState, accessMask); #region Negotiate status = client.Negotiate( requestDialect, TestConfig.IsSMB1NegotiateEnabled, capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES, checker: (Packet_Header header, NEGOTIATE_Response response) => { TestConfig.CheckNegotiateDialect(DialectRevision.Smb30, response); }); #endregion #region SESSION_SETUP status = client.SessionSetup( TestConfig.DefaultSecurityPackage, serverName, TestConfig.AccountCredential, TestConfig.UseServerGssToken); #endregion #region TREE_CONNECT to share uint treeId; status = client.TreeConnect(uncSharePath, out treeId); #endregion #region CREATE Smb2CreateContextResponse[] serverCreateContexts; FILEID fileId; status = client.Create( treeId, // To break lease on directory, create a new child item isDirectory ? testDirectory + @"\child.txt" : fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileId, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateRequestLeaseV2 { LeaseKey = Guid.NewGuid(), LeaseState = requestedLeaseState } }, accessMask: accessMask, shareAccess: ShareAccess_Values.NONE, checker: (header, response) => { }); #endregion BaseTestSite.Log.Add( LogEntryKind.Debug, "AfterFailover: Finish triggering a LeaseBreakNotification from a separate client."); }
/// <summary> /// Initializes a new instance of the DefaultLeaseResponseChecker class with specified TestSite, LeaseKey and LeaseState. /// </summary> /// <param name="TestSite">The TestSite used to provide logging, assertions, and SUT adapters.</param> /// <param name="leaseKey">The expected LeaseKey value in the response.</param> /// <param name="leaseState">The expected LeaseState value in the response.</param> /// <param name="leaseFlag">The expected LeaseFlag value in the response.</param> public DefaultLeaseResponseChecker(ITestSite TestSite, Guid leaseKey, LeaseStateValues leaseState, LeaseFlagsValues leaseFlag) : base(TestSite, typeof(Smb2CreateResponseLease)) { this.leaseKey = leaseKey; this.leaseState = leaseState; this.leaseFlag = leaseFlag; }
/// <summary> /// Get lease context according to leasekey and leasestate /// </summary> private Smb2CreateContextRequest[] GetLeaseContext( OplockLeaseType oplockLeaseType, Guid leaseKey, LeaseStateValues leaseState) { Smb2CreateContextRequest[] leaseContext = new Smb2CreateContextRequest[] { }; if (oplockLeaseType == OplockLeaseType.LeaseV1) { testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE); leaseContext = leaseContext.Append( new Smb2CreateRequestLease { LeaseKey = leaseKey, LeaseState = leaseState }); } if (oplockLeaseType == OplockLeaseType.LeaseV2) { testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE_V2); leaseContext = leaseContext.Append( new Smb2CreateRequestLeaseV2 { LeaseKey = leaseKey, LeaseState = leaseState }); } return(leaseContext); }
/// <summary> /// Initializes a new instance of the DefaultLeaseV2ResponseChecker class with specified TestSite, LeaseKey, LeaseState and ParentLeaseKey. /// </summary> /// <param name="TestSite">The TestSite used to provide logging, assertions, and SUT adapters.</param> /// <param name="leaseKey">The expected LeaseKey value in the response.</param> /// <param name="leaseState">The expected LeaseState value in the response.</param> /// <param name="leaseFlag">The expected LeaseFlag value in the response.</param> /// <param name="parentLeaseKey">The expected ParentLeaseKey value in the response. Default value indicates not checking this field.</param> public DefaultLeaseV2ResponseChecker(ITestSite TestSite, Guid leaseKey, LeaseStateValues leaseState, LeaseFlagsValues leaseFlag, Guid parentLeaseKey = default(Guid)) : base(TestSite, typeof(Smb2CreateResponseLeaseV2)) { this.leaseKey = leaseKey; this.leaseState = leaseState; this.leaseFlag = leaseFlag; this.parentLeaseKey = parentLeaseKey; }
/// <summary> /// Trigger LeaseBreak from a separate client /// </summary> /// <param name="client">Smb2FunctionalClient object that attempt to access file/directory to trigger lease break</param> /// <param name="requestDialect">Dialect in request</param> /// <param name="isDirectory">Set true if access a directory, otherwise set false</param> /// <param name="requestedLeaseState">Lease state that client will request</param> /// <param name="accessMask">Access mask that client is used to access file/directory</param> private void TriggerBreakFromClient( Smb2FunctionalClient client, DialectRevision[] requestDialect, bool isDirectory, LeaseStateValues requestedLeaseState, AccessMask accessMask) { BaseTestSite.Log.Add( LogEntryKind.Debug, "Below steps will trigger a lease break by accessing same file/directory from a separate client with LeaseState {0} and AccessMask {1}", requestedLeaseState, accessMask); #region Negotiate status = client.Negotiate( requestDialect, TestConfig.IsSMB1NegotiateEnabled, capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES); #endregion #region SESSION_SETUP status = client.SessionSetup( TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken); #endregion #region TREE_CONNECT to share uint treeId; status = client.TreeConnect(uncSharePath, out treeId); #endregion #region CREATE FILEID fileId; Smb2CreateContextResponse[] serverCreateContexts; status = client.Create( treeId, isDirectory ? testDirectory : fileName, isDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileId, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateRequestLeaseV2 { LeaseKey = Guid.NewGuid(), LeaseState = requestedLeaseState } }, accessMask: accessMask); #endregion status = client.Close(treeId, fileId); BaseTestSite.Log.Add( LogEntryKind.Debug, "Finish triggering lease break."); }
/// <summary> /// One client requests a lease /// </summary> /// <param name="leaseStateType">Type of the LeaseState in the requested lease context</param> public void RequestLease(ModelLeaseStateType leaseStateType) { Smb2CreateContextResponse[] responses; FILEID fileId; LeaseStateValues leaseState = LeaseStateValues.SMB2_LEASE_NONE; switch (leaseStateType) { case ModelLeaseStateType.Lease_None: leaseState = LeaseStateValues.SMB2_LEASE_NONE; break; case ModelLeaseStateType.Lease_R: leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING; break; case ModelLeaseStateType.Lease_RH: leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING; break; case ModelLeaseStateType.Lease_RW: leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING; break; case ModelLeaseStateType.Lease_RWH: leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING; break; default: break; } leaseClient.Create( treeIdLease, fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileId, out responses, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateRequestLease() { LeaseKey = Guid.NewGuid(), LeaseState = leaseState } }); grantedLeaseState = ((Smb2CreateResponseLease)responses[0]).LeaseState; HandleResult(); }
/// <summary> /// Reset all member variables before running next test case /// </summary> public override void Reset() { if (oplockClient != null) { oplockClient.Disconnect(); oplockClient = null; } if (leaseClient != null) { leaseClient.Disconnect(); leaseClient = null; } fileName = null; breakType = ModelBreakType.NoBreak; treeIdOplock = 0; treeIdLease = 0; alreadyRequested = false; grantedLeaseState = LeaseStateValues.SMB2_LEASE_NONE; grantedOplockLevel = OplockLevel_Values.OPLOCK_LEVEL_NONE; base.Reset(); }
/// <summary> /// Initialize all fields to the default values. /// </summary> private void Initialize() { Flags = testConfig.SendSignedRequest ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE; Dialect = DialectRevision.Smb2Unknown; MessageId = 0; GrantedCredit = 0; SessionKey = null; ServerGssToken = null; unchecked { TreeId = (uint)-1; } SessionId = 0; ParentDirectory = null; File = null; FileId = FILEID.Zero; IsDirectory = false; Locks = null; LockSequence = 0; LeaseState = LeaseStateValues.SMB2_LEASE_NONE; CreateContexts = null; OperationMessageId = 0; Client = new Smb2Client(Timeout); Client.DisableVerifySignature = this.testConfig.DisableVerifySignature; }
/// <summary> /// Test AppInstanceId with leasing /// </summary> /// <param name="isDirectory">Set true if test lease on directory, otherwise set false</param> /// <param name="requestedLeaseState">Lease state that client will request</param> /// <param name="accessMask">Access mask that client is used to access file/directory</param> /// <param name="accessMaskToTriggerBreak">Access mask that a separate client is used to access file/directory to trigger LeaseBreak</param> private void AppInstanceIdTestWithLeasing(bool isDirectory, LeaseStateValues requestedLeaseState, AccessMask accessMask, AccessMask accessMaskToTriggerBreak) { testDirectory = CreateTestDirectory(uncSharePath); #region InitialOpen: Connect to server via Nic1 and create an open with AppInstanceId and leasing BaseTestSite.Log.Add( LogEntryKind.TestStep, "InitialOpen: Connect to share via Nic1."); FILEID fileIdForInitialOpen; uint treeIdForInitialOpen; ConnectShare(TestConfig.SutIPAddress, TestConfig.ClientNic1IPAddress, clientForInitialOpen, out treeIdForInitialOpen); #region Create an open with AppInstanceId and leasing BaseTestSite.Log.Add(LogEntryKind.TestStep, "InitialOpen: Create an open with AppInstanceId and leasing."); appInstanceId = Guid.NewGuid(); Smb2CreateContextResponse[] serverCreateContexts; status = clientForInitialOpen.Create( treeIdForInitialOpen, isDirectory ? testDirectory : fileName, isDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdForInitialOpen, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleRequestV2 { CreateGuid = Guid.NewGuid(), }, new Smb2CreateRequestLeaseV2 { LeaseKey = Guid.NewGuid(), LeaseState = requestedLeaseState, }, new Smb2CreateAppInstanceId { AppInstanceId = appInstanceId } }, accessMask: accessMask, shareAccess: ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE); #endregion if (!isDirectory) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "InitialOpen: Write contents to file."); status = clientForInitialOpen.Write(treeIdForInitialOpen, fileIdForInitialOpen, contentWrite); } #endregion #region ReOpen: Connect to server via Nic2 and create an open with same AppInstanceId but without leasing BaseTestSite.Log.Add( LogEntryKind.TestStep, "ReOpen: Connect to same share via Nic2."); FILEID fileIdForReOpen; uint treeIdForReOpen; clientForReOpen.Smb2Client.LeaseBreakNotificationReceived += new Action <Packet_Header, LEASE_BREAK_Notification_Packet>(this.OnLeaseBreakNotificationReceived); ConnectShare(TestConfig.SutIPAddress, TestConfig.ClientNic2IPAddress, clientForReOpen, out treeIdForReOpen); #region Create an open with AppInstanceId but without leasing BaseTestSite.Log.Add(LogEntryKind.TestStep, "ReOpen: Create an open with AppInstanceId but without leasing."); status = clientForReOpen.Create( treeIdForReOpen, isDirectory ? testDirectory : fileName, isDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdForReOpen, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleRequestV2 { CreateGuid = Guid.NewGuid(), }, new Smb2CreateAppInstanceId { // Use the same application instance id to force the server close all files // And will clear previous lease AppInstanceId = appInstanceId } }, accessMask: AccessMask.GENERIC_READ); #endregion if (!isDirectory) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "ReOpen: Read the contents written by InitialOpen."); status = clientForReOpen.Read(treeIdForReOpen, fileIdForReOpen, 0, (uint)contentWrite.Length, out contentRead); BaseTestSite.Assert.IsTrue( contentRead.Equals(contentWrite), "The written content should equal to read content."); } #endregion #region ReOpen: Access same file/directory from a separate client and expect SUCCESS if (!isDirectory) { Smb2FunctionalClient separateClient = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client3: Connect to same server."); separateClient.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress, TestConfig.ClientNic2IPAddress); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client3: Trigger a Lease Break."); TriggerBreakFromClient(separateClient, TestConfig.RequestDialects, isDirectory, LeaseStateValues.SMB2_LEASE_NONE, accessMaskToTriggerBreak); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client3: Disconnect from the server."); separateClient.Disconnect(); } else { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client3: Attempt to create an empty file to trigger lease break."); sutProtocolController.CreateFile(Path.Combine(Smb2Utility.GetUncPath(TestConfig.SutComputerName, TestConfig.BasicFileShare), testDirectory), CurrentTestCaseName, string.Empty); } Thread.Sleep(500); BaseTestSite.Assert.AreNotEqual( true, isLeaseBreakReceived, "No LeaseBreak is expected to be received"); #endregion #region Client tear down BaseTestSite.Log.Add(LogEntryKind.TestStep, "ReOpen: Close file."); status = clientForReOpen.Close(treeIdForReOpen, fileIdForReOpen); BaseTestSite.Log.Add(LogEntryKind.TestStep, "ReOpen: Disconnect from the share."); status = clientForReOpen.TreeDisconnect(treeIdForReOpen); BaseTestSite.Log.Add(LogEntryKind.TestStep, "ReOpen: Log Off."); status = clientForReOpen.LogOff(); #endregion }
public Smb2LeaseBreakNotificationPacket CreateLeaseBreakNotificationResponse( Smb2Endpoint endpoint, LEASE_BREAK_Notification_Packet_Flags_Values flags, byte[] leaseKey, LeaseStateValues currentLeaseState, LeaseStateValues newLeaseState ) { Smb2LeaseBreakNotificationPacket packet = new Smb2LeaseBreakNotificationPacket(); packet.Header.Flags = Packet_Header_Flags_Values.FLAGS_SERVER_TO_REDIR; packet.Header.Command = Smb2Command.OPLOCK_BREAK; packet.Header.MessageId = ulong.MaxValue; packet.Header.ProtocolId = Smb2Consts.Smb2ProtocolId; packet.Header.Signature = new byte[Smb2Consts.SignatureSize]; packet.Header.StructureSize = Packet_Header_StructureSize_Values.V1; packet.Endpoint = endpoint; packet.PayLoad.AccessMaskHint = LEASE_BREAK_Notification_Packet_AccessMaskHint_Values.V1; packet.PayLoad.BreakReason = LEASE_BREAK_Notification_Packet_BreakReason_Values.V1; packet.PayLoad.CurrentLeaseState = currentLeaseState; packet.PayLoad.Flags = LEASE_BREAK_Notification_Packet_Flags_Values.SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED; packet.PayLoad.LeaseKey = leaseKey; packet.PayLoad.NewLeaseState = newLeaseState; packet.PayLoad.Reserved = LEASE_BREAK_Notification_Packet_Reserved_Values.V1; packet.PayLoad.ShareMaskHint = LEASE_BREAK_Notification_Packet_ShareMaskHint_Values.V1; packet.PayLoad.StructureSize = LEASE_BREAK_Notification_Packet_StructureSize_Values.V1; packet.Sign(); return packet; }
public void DurableHandleV2_Reconnect_WithDifferentDurableOwner() { /// 1. Client requests a durable handle V2 with LeaseV1 context /// 2. Client disconnects /// 3. Client reconnects the durable handle V2 with a different durable owner, and expects that server will return STATUS_ACCESS_DENIED. #region Check Applicability TestConfig.CheckDialect(DialectRevision.Smb30); TestConfig.CheckCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING); TestConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2, CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2, CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE); #endregion string content = Smb2Utility.CreateRandomString(testConfig.WriteBufferLengthInKb); Guid clientGuid = Guid.NewGuid(); durableHandleUncSharePath = Smb2Utility.GetUncPath(testConfig.SutComputerName, testConfig.BasicFileShare); string fileName = GetTestFileName(durableHandleUncSharePath); #region client connect to server BaseTestSite.Log.Add( LogEntryKind.Comment, "Client connects to server and opens file with a durable handle"); uint treeIdBeforeDisconnection; Connect(DialectRevision.Smb30, clientBeforeDisconnection, clientGuid, testConfig.AccountCredential, ConnectShareType.BasicShareWithoutAssert, out treeIdBeforeDisconnection, null); Guid createGuid = Guid.NewGuid(); Guid leaseKey = Guid.NewGuid(); LeaseStateValues leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING; FILEID fileIdBeforeDisconnection; Smb2CreateContextResponse[] serverCreateContexts = null; status = clientBeforeDisconnection.Create( treeIdBeforeDisconnection, fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdBeforeDisconnection, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleRequestV2 { CreateGuid = createGuid, }, new Smb2CreateRequestLeaseV2 { LeaseKey = leaseKey, LeaseState = leaseState, } }, shareAccess: ShareAccess_Values.NONE, checker: (header, response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "{0} should be successful, actually server returns {1}.", header.Command, Smb2Status.GetStatusCode(header.Status)); CheckCreateContextResponses(serverCreateContexts, new DefaultDurableHandleV2ResponseChecker(BaseTestSite, 0, uint.MaxValue)); }); status = clientBeforeDisconnection.Write(treeIdBeforeDisconnection, fileIdBeforeDisconnection, content); #endregion clientBeforeDisconnection.Disconnect(); #region client reconnect to server BaseTestSite.Log.Add( LogEntryKind.Comment, "Client opens the same file and reconnects the durable handle"); uint treeIdAfterDisconnection; Connect(DialectRevision.Smb30, clientAfterDisconnection, clientGuid, testConfig.NonAdminAccountCredential, ConnectShareType.BasicShareWithoutAssert, out treeIdAfterDisconnection, clientBeforeDisconnection); FILEID fileIdAfterDisconnection; clientAfterDisconnection.Create( treeIdAfterDisconnection, fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdAfterDisconnection, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleReconnectV2 { CreateGuid = createGuid, FileId = new FILEID { Persistent = fileIdBeforeDisconnection.Persistent } }, new Smb2CreateRequestLeaseV2 { LeaseKey = leaseKey, LeaseState = leaseState, } }, shareAccess: ShareAccess_Values.NONE, checker: (header, response) => { BaseTestSite.Assert.AreNotEqual( Smb2Status.STATUS_SUCCESS, header.Status, "{0} should not be successful if the DurableOwner is different, actually server returns {1}.", header.Command, Smb2Status.GetStatusCode(header.Status)); BaseTestSite.CaptureRequirementIfAreEqual( Smb2Status.STATUS_ACCESS_DENIED, header.Status, RequirementCategory.STATUS_ACCESS_DENIED.Id, RequirementCategory.STATUS_ACCESS_DENIED.Description); }); #endregion clientAfterDisconnection.TreeDisconnect(treeIdAfterDisconnection); clientAfterDisconnection.LogOff(); clientAfterDisconnection.Disconnect(); }
/// <summary> /// Create an open from client, this include NEGOTIATE and SESSION_SETUP with server, TREE_CONNECT to the share and CREATE an open to file/directory /// </summary> /// <param name="client">Client used to take the operation</param> /// <param name="clientGuid">Client GUID for negotiation</param> /// <param name="targetName">File/directory name for the open</param> /// <param name="isDirectory">Set true if create open to a directory, set false if create open to a file</param> /// <param name="accessMask">Desired access when create the open</param> /// <param name="treeId">Out param for tree id used to connect to the share</param> /// <param name="fileId">Out param for file id that is associated with the open</param> /// <param name="shareAccess">Optional param for share access when create the open</param> /// <returns>Status value returned from CREATE request</returns> private uint CreateOpenFromClient(Smb2FunctionalClient client, Guid clientGuid, string targetName, bool isDirectory, LeaseStateValues requestLeaseState, AccessMask accessMask, out uint treeId, out FILEID fileId, ShareAccess_Values shareAccess = ShareAccess_Values.FILE_SHARE_DELETE | ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE) { #region Negotiate BaseTestSite.Log.Add( LogEntryKind.TestStep, "Client {0} sends NEGOTIATE request with the following capabilities: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES.", clientGuid.ToString()); client.Negotiate( TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled, capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES, clientGuid: clientGuid, checker: (Packet_Header header, NEGOTIATE_Response response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "Negotiation is expected success, actually server returns {0}", Smb2Status.GetStatusCode(header.Status)); TestConfig.CheckNegotiateDialect(DialectRevision.Smb30, response); TestConfig.CheckNegotiateCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING, response); }); #endregion #region SESSION_SETUP BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client {0} sends SESSION_SETUP request.", clientGuid.ToString()); status = client.SessionSetup( TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken); #endregion #region TREE_CONNECT to share BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client {0} sends TREE_CONNECT request.", clientGuid.ToString()); status = client.TreeConnect(uncSharePath, out treeId); #endregion #region CREATE Smb2CreateContextResponse[] serverCreateContexts; CreateOptions_Values createOptions; if (isDirectory) { createOptions = CreateOptions_Values.FILE_DIRECTORY_FILE; } else { createOptions = CreateOptions_Values.FILE_NON_DIRECTORY_FILE; } // Include FILE_DELETE_ON_CLOSE if accessMask has DELETE if ((accessMask & AccessMask.DELETE) == AccessMask.DELETE) { createOptions = createOptions | CreateOptions_Values.FILE_DELETE_ON_CLOSE; } BaseTestSite.Log.Add( LogEntryKind.TestStep, "Client {0} sends CREATE request with the lease state in SMB2_CREATE_REQUEST_LEASE_V2 set to {1}.", clientGuid.ToString(), requestLeaseState); status = client.Create( treeId, targetName, createOptions, out fileId, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateRequestLeaseV2 { LeaseKey = clientGuid, LeaseState = requestLeaseState } }, accessMask: accessMask, shareAccess: shareAccess, checker: (header, response) => { }); return status; #endregion }
/// <summary> /// Get lease context according to leasekey and leasestate /// </summary> private Smb2CreateContextRequest[] GetLeaseContext( OplockLeaseType oplockLeaseType, Guid leaseKey, LeaseStateValues leaseState) { Smb2CreateContextRequest[] leaseContext = new Smb2CreateContextRequest[] { }; if (oplockLeaseType == OplockLeaseType.LeaseV1) { testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE); leaseContext = leaseContext.Append( new Smb2CreateRequestLease { LeaseKey = leaseKey, LeaseState = leaseState }); } if (oplockLeaseType == OplockLeaseType.LeaseV2) { testConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE_V2); leaseContext = leaseContext.Append( new Smb2CreateRequestLeaseV2 { LeaseKey = leaseKey, LeaseState = leaseState }); } return leaseContext; }
private Smb2CreateRequestLeaseV2 createLeaseV2RequestContext(Guid leaseKey = new Guid(), LeaseStateValues leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING, Guid parentLeaseKey = new Guid(), LeaseFlagsValues leaseFlag = LeaseFlagsValues.SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET) { return(new Smb2CreateRequestLeaseV2 { LeaseKey = leaseKey == Guid.Empty ? Guid.NewGuid() : leaseKey, LeaseState = leaseState, ParentLeaseKey = parentLeaseKey == Guid.Empty ? Guid.NewGuid() : parentLeaseKey, LeaseFlags = (uint)leaseFlag }); }
private void DirecotryLeasing( DialectRevision[] requestDialect, DialectRevision expectedDialect, LeaseStateValues leaseState, LeaseBreakAckType leaseBreakAckType = LeaseBreakAckType.None) { #region Check Applicability TestConfig.CheckDialect(DialectRevision.Smb30); TestConfig.CheckCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING); TestConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE_V2); #endregion BaseTestSite.Log.Add( LogEntryKind.Comment, @"Start to create a directory on share \\{0}\{1} with lease state {2}", TestConfig.SutComputerName, TestConfig.BasicFileShare, leaseState); string testDirectory = CreateTestDirectory(TestConfig.SutComputerName, TestConfig.BasicFileShare); client.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress); #region Negotiate BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start the client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT"); Capabilities_Values capabilities = Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES; status = client.Negotiate( requestDialect, TestConfig.IsSMB1NegotiateEnabled, capabilityValue: capabilities, checker: (Packet_Header header, NEGOTIATE_Response response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "Negotiation should succeed, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status)); TestConfig.CheckNegotiateDialect(expectedDialect, response); if (expectedDialect >= DialectRevision.Smb30) { TestConfig.CheckNegotiateCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING, response); } }); #endregion #region SESSION_SETUP status = client.SessionSetup( TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken); #endregion #region TREE_CONNECT to share string uncSharePath = Smb2Utility.GetUncPath(TestConfig.SutComputerName, TestConfig.BasicFileShare); uint treeId; status = client.TreeConnect(uncSharePath, out treeId); #endregion #region CREATE FILEID fileId; Smb2CreateContextResponse[] serverCreateContexts; BaseTestSite.Log.Add( LogEntryKind.TestStep, "Client sends CREATE request for the directory with the LeaseState set to {0} in SMB2_CREATE_REQUEST_LEASE_V2.", leaseState); status = client.Create( treeId, testDirectory, CreateOptions_Values.FILE_DIRECTORY_FILE, out fileId, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateRequestLeaseV2 { LeaseKey = Guid.NewGuid(), LeaseState = leaseState } }, checker: (Packet_Header header, CREATE_Response response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "CREATE should succeed, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status)); if (expectedDialect == DialectRevision.Smb2002 || expectedDialect == DialectRevision.Smb21) { BaseTestSite.Assert.AreEqual( OplockLevel_Values.OPLOCK_LEVEL_NONE, response.OplockLevel, "The expected oplock level is OPLOCK_LEVEL_NONE."); } }); #endregion if (expectedDialect >= DialectRevision.Smb30) { // Break the lease with creating another file in the directory sutProtocolController.CreateFile(Path.Combine(Smb2Utility.GetUncPath(TestConfig.SutComputerName, TestConfig.BasicFileShare), testDirectory), CurrentTestCaseName, string.Empty); // Wait until LEASE_BREAK_Notification is received BaseTestSite.Assert.IsTrue( // Wait 5 seconds for notification arrival notificationReceived.WaitOne(SMB2TestConfig.WAIT_TIMEOUT_IN_MILLISECONDS), "LeaseBreakNotification should be raised."); if (receivedLeaseBreakNotify.Flags == LEASE_BREAK_Notification_Packet_Flags_Values.SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) { BaseTestSite.Log.Add( LogEntryKind.Debug, "Server requires an LEASE_BREAK_ACK on this LEASE_BREAK_NOTIFY"); #region LEASE_BREAK_ACK switch (leaseBreakAckType) { case LeaseBreakAckType.None: status = client.LeaseBreakAcknowledgment(treeId, receivedLeaseBreakNotify.LeaseKey, receivedLeaseBreakNotify.NewLeaseState); break; case LeaseBreakAckType.InvalidLeaseState: LeaseStateValues newLeaseState = LeaseStateValues.SMB2_LEASE_WRITE_CACHING; BaseTestSite.Log.Add( LogEntryKind.Comment, "Client attempts to send LEASE_BREAK_ACK with an invalid LeaseState {0} on this LEASE_BREAK_NOTIFY", newLeaseState); status = client.LeaseBreakAcknowledgment( treeId, receivedLeaseBreakNotify.LeaseKey, newLeaseState, checker: (header, response) => { BaseTestSite.Assert.AreNotEqual( Smb2Status.STATUS_SUCCESS, header.Status, "LEASE_BREAK_ACK with invalid LeaseState is not expected to SUCCESS, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status)); BaseTestSite.CaptureRequirementIfAreEqual( Smb2Status.STATUS_REQUEST_NOT_ACCEPTED, header.Status, RequirementCategory.STATUS_REQUEST_NOT_ACCEPTED.Id, RequirementCategory.STATUS_REQUEST_NOT_ACCEPTED.Description); }); break; case LeaseBreakAckType.InvalidLeaseKey: Guid invalidLeaseKey = Guid.NewGuid(); BaseTestSite.Log.Add( LogEntryKind.Debug, "Client attempts to send LEASE_BREAK_ACK with an invalid LeaseKey {0} on this LEASE_BREAK_NOTIFY", invalidLeaseKey); status = client.LeaseBreakAcknowledgment( treeId, invalidLeaseKey, receivedLeaseBreakNotify.NewLeaseState, checker: (header, response) => { BaseTestSite.Assert.AreNotEqual( Smb2Status.STATUS_SUCCESS, header.Status, "LEASE_BREAK_ACK with invalid LeaseKey is not expected to SUCCESS, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status)); BaseTestSite.CaptureRequirementIfAreEqual( Smb2Status.STATUS_OBJECT_NAME_NOT_FOUND, header.Status, RequirementCategory.STATUS_OBJECT_NAME_NOT_FOUND.Id, RequirementCategory.STATUS_OBJECT_NAME_NOT_FOUND.Description); }); break; case LeaseBreakAckType.InvalidClientGuid: BaseTestSite.Log.Add(LogEntryKind.Debug, "Initialize a new different client to attempts to send LEASE_BREAK_ACK"); Smb2FunctionalClient newClient = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite); newClient.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress); #region Negotiate status = newClient.Negotiate( requestDialect, TestConfig.IsSMB1NegotiateEnabled, capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES); #endregion #region SESSION_SETUP status = newClient.SessionSetup( TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken); #endregion #region TREE_CONNECT to share uint newTreeId; status = newClient.TreeConnect(uncSharePath, out newTreeId); #endregion status = newClient.LeaseBreakAcknowledgment( newTreeId, receivedLeaseBreakNotify.LeaseKey, receivedLeaseBreakNotify.NewLeaseState, checker: (header, response) => { BaseTestSite.Assert.AreNotEqual( Smb2Status.STATUS_SUCCESS, header.Status, "LEASE_BREAK_ACK is not expected to SUCCESS when the open is closed, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status)); BaseTestSite.CaptureRequirementIfAreEqual( Smb2Status.STATUS_OBJECT_NAME_NOT_FOUND, header.Status, RequirementCategory.STATUS_OBJECT_NAME_NOT_FOUND.Id, RequirementCategory.STATUS_OBJECT_NAME_NOT_FOUND.Description); }); status = newClient.TreeDisconnect(newTreeId); status = newClient.LogOff(); BaseTestSite.Log.Add( LogEntryKind.Comment, "Initialize a new different client to attempts to send LEASE_BREAK_ACK"); break; default: throw new InvalidOperationException("Unexpected LeaseBreakAckType " + leaseBreakAckType); } #endregion } else { BaseTestSite.Log.Add( LogEntryKind.Debug, "Server does not require an LEASE_BREAK_ACK on this LEASE_BREAK_NOTIFY"); } } BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the client by sending the following requests: TREE_DISCONNECT; LOG_OFF"); #region TREE_DISCONNECT status = client.TreeDisconnect(treeId); #endregion #region LOGOFF status = client.LogOff(); #endregion BaseTestSite.Log.Add( LogEntryKind.Comment, @"Complete creating a directory on share \\{0}\{1} with lease state {2}", TestConfig.SutComputerName, TestConfig.BasicFileShare, leaseState); }
/// <summary> /// One client requests a lease /// </summary> /// <param name="leaseStateType">Type of the LeaseState in the requested lease context</param> public void RequestLease(ModelLeaseStateType leaseStateType) { Smb2CreateContextResponse[] responses; FILEID fileId; LeaseStateValues leaseState = LeaseStateValues.SMB2_LEASE_NONE; switch (leaseStateType) { case ModelLeaseStateType.Lease_None: leaseState = LeaseStateValues.SMB2_LEASE_NONE; break; case ModelLeaseStateType.Lease_R: leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING; break; case ModelLeaseStateType.Lease_RH: leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING; break; case ModelLeaseStateType.Lease_RW: leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING; break; case ModelLeaseStateType.Lease_RWH: leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING; break; default: break; } leaseClient.Create( treeIdLease, fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileId, out responses, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateRequestLease() { LeaseKey = Guid.NewGuid(), LeaseState = leaseState } }); if (responses == null) { throw new Exception("There is no Smb2CreateContextResponse in response data!"); } if (responses.Length == 0 || responses[0] is not Smb2CreateResponseLease) { throw new Exception("There is no SMB2_CREATE_RESPONSE_LEASE create context in response data!"); } grantedLeaseState = ((Smb2CreateResponseLease)responses[0]).LeaseState; HandleResult(); }
private void DurableHandleV1_Reconnect_WithLeaseV1(bool sameFileName) { #region Check Applicability TestConfig.CheckDialect(DialectRevision.Smb21); TestConfig.CheckCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING); TestConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_REQUEST, CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_RECONNECT, CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE); #endregion string content = Smb2Utility.CreateRandomString(testConfig.WriteBufferLengthInKb); durableHandleUncSharePath = Smb2Utility.GetUncPath(testConfig.SutComputerName, testConfig.BasicFileShare); string fileName = GetTestFileName(durableHandleUncSharePath); #region client connect to server BaseTestSite.Log.Add( LogEntryKind.Comment, "Client connects to server and opens file with a durable handle"); uint treeIdBeforeDisconnection; Connect(DialectRevision.Smb21, clientBeforeDisconnection, clientGuid, testConfig.AccountCredential, ConnectShareType.BasicShareWithoutAssert, out treeIdBeforeDisconnection, null); Guid leaseKey = Guid.NewGuid(); LeaseStateValues leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING; FILEID fileIdBeforeDisconnection; Smb2CreateContextResponse[] serverCreateContexts = null; clientBeforeDisconnection.Create( treeIdBeforeDisconnection, fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdBeforeDisconnection, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleRequest { DurableRequest = Guid.Empty, }, new Smb2CreateRequestLease { LeaseKey = leaseKey, LeaseState = leaseState, } }, shareAccess: ShareAccess_Values.NONE, checker: (header, response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "{0} should be successful, actually server returns {1}.", header.Command, Smb2Status.GetStatusCode(header.Status)); CheckCreateContextResponses(serverCreateContexts, new DefaultDurableHandleResponseChecker(BaseTestSite)); }); clientBeforeDisconnection.Write(treeIdBeforeDisconnection, fileIdBeforeDisconnection, content); #endregion BaseTestSite.Log.Add( LogEntryKind.TestStep, "The client with clientGuid {0} sends DISCONNECT request.", clientGuid.ToString()); clientBeforeDisconnection.Disconnect(); #region client reconnect to server BaseTestSite.Log.Add( LogEntryKind.Comment, "Client opens the same file and reconnects the durable handle"); uint treeIdAfterDisconnection; Connect(DialectRevision.Smb21, clientAfterDisconnection, clientGuid, testConfig.AccountCredential, ConnectShareType.BasicShareWithoutAssert, out treeIdAfterDisconnection, clientBeforeDisconnection); FILEID fileIdAfterDisconnection; uint status = clientAfterDisconnection.Create( treeIdAfterDisconnection, sameFileName ? fileName : GetTestFileName(durableHandleUncSharePath), CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdAfterDisconnection, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleReconnect { Data = new FILEID { Persistent = fileIdBeforeDisconnection.Persistent } }, new Smb2CreateRequestLease { LeaseKey = leaseKey, LeaseState = leaseState, } }, shareAccess: ShareAccess_Values.NONE, checker: (header, response) => {}); if (sameFileName) { BaseTestSite.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Reconnect a durable handle should be successful"); string readContent; clientAfterDisconnection.Read(treeIdAfterDisconnection, fileIdAfterDisconnection, 0, (uint)content.Length, out readContent); BaseTestSite.Assert.IsTrue( content.Equals(readContent), "The written content is expected to be equal to read content."); clientAfterDisconnection.Close(treeIdAfterDisconnection, fileIdAfterDisconnection); } else { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_INVALID_PARAMETER, status, "If Open.Lease is not NULL and Open.FileName does not match the file name specified in the Buffer field of the SMB2 CREATE request, " + "the server MUST fail the request with STATUS_INVALID_PARAMETER."); } clientAfterDisconnection.TreeDisconnect(treeIdAfterDisconnection); clientAfterDisconnection.LogOff(); clientAfterDisconnection.Disconnect(); #endregion }
/// <summary> /// Test AppInstanceId with leasing /// </summary> /// <param name="isDirectory">Set true if test lease on directory, otherwise set false</param> /// <param name="requestedLeaseState">Lease state that client will request</param> /// <param name="accessMask">Access mask that client is used to access file/directory</param> /// <param name="accessMaskToTriggerBreak">Access mask that a separate client is used to access file/directory to trigger LeaseBreak</param> private void AppInstanceIdTestWithLeasing(bool isDirectory, LeaseStateValues requestedLeaseState, AccessMask accessMask, AccessMask accessMaskToTriggerBreak) { testDirectory = CreateTestDirectory(uncSharePath); #region InitialOpen: Connect to server via Nic1 and create an open with AppInstanceId and leasing BaseTestSite.Log.Add( LogEntryKind.TestStep, "InitialOpen: Connect to share via Nic1."); FILEID fileIdForInitialOpen; uint treeIdForInitialOpen; ConnectShare(TestConfig.SutIPAddress, TestConfig.ClientNic1IPAddress, clientForInitialOpen, out treeIdForInitialOpen); #region Create an open with AppInstanceId and leasing BaseTestSite.Log.Add(LogEntryKind.TestStep, "InitialOpen: Create an open with AppInstanceId and leasing."); appInstanceId = Guid.NewGuid(); Smb2CreateContextResponse[] serverCreateContexts; status = clientForInitialOpen.Create( treeIdForInitialOpen, isDirectory ? testDirectory : fileName, isDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdForInitialOpen, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleRequestV2 { CreateGuid = Guid.NewGuid(), }, new Smb2CreateRequestLeaseV2 { LeaseKey = Guid.NewGuid(), LeaseState = requestedLeaseState, }, new Smb2CreateAppInstanceId { AppInstanceId = appInstanceId } }, accessMask: accessMask, shareAccess: ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE); #endregion if (!isDirectory) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "InitialOpen: Write contents to file."); status = clientForInitialOpen.Write(treeIdForInitialOpen, fileIdForInitialOpen, contentWrite); } #endregion #region ReOpen: Connect to server via Nic2 and create an open with same AppInstanceId but without leasing BaseTestSite.Log.Add( LogEntryKind.TestStep, "ReOpen: Connect to same share via Nic2."); FILEID fileIdForReOpen; uint treeIdForReOpen; clientForReOpen.Smb2Client.LeaseBreakNotificationReceived += new Action<Packet_Header, LEASE_BREAK_Notification_Packet>(this.OnLeaseBreakNotificationReceived); ConnectShare(TestConfig.SutIPAddress, TestConfig.ClientNic2IPAddress, clientForReOpen, out treeIdForReOpen); #region Create an open with AppInstanceId but without leasing BaseTestSite.Log.Add(LogEntryKind.TestStep, "ReOpen: Create an open with AppInstanceId but without leasing."); status = clientForReOpen.Create( treeIdForReOpen, isDirectory ? testDirectory : fileName, isDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdForReOpen, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleRequestV2 { CreateGuid = Guid.NewGuid(), }, new Smb2CreateAppInstanceId { // Use the same application instance id to force the server close all files // And will clear previous lease AppInstanceId = appInstanceId } }, accessMask: AccessMask.GENERIC_READ); #endregion if (!isDirectory) { BaseTestSite.Log.Add(LogEntryKind.TestStep, "ReOpen: Read the contents written by InitialOpen."); status = clientForReOpen.Read(treeIdForReOpen, fileIdForReOpen, 0, (uint)contentWrite.Length, out contentRead); BaseTestSite.Assert.IsTrue( contentRead.Equals(contentWrite), "The written content should equal to read content."); } #endregion #region ReOpen: Access same file/directory from a separate client and expect SUCCESS if (!isDirectory) { Smb2FunctionalClient separateClient = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client3: Connect to same server."); separateClient.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress, TestConfig.ClientNic2IPAddress); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client3: Trigger a Lease Break."); TriggerBreakFromClient(separateClient, TestConfig.RequestDialects, isDirectory, LeaseStateValues.SMB2_LEASE_NONE, accessMaskToTriggerBreak); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client3: Disconnect from the server."); separateClient.Disconnect(); } else { BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client3: Attempt to create an empty file to trigger lease break."); sutProtocolController.CreateFile(Path.Combine(Smb2Utility.GetUncPath(TestConfig.SutComputerName, TestConfig.BasicFileShare), testDirectory), CurrentTestCaseName, string.Empty); } Thread.Sleep(500); BaseTestSite.Assert.AreNotEqual( true, isLeaseBreakReceived, "No LeaseBreak is expected to be received"); #endregion #region Client tear down BaseTestSite.Log.Add(LogEntryKind.TestStep, "ReOpen: Close file."); status = clientForReOpen.Close(treeIdForReOpen, fileIdForReOpen); BaseTestSite.Log.Add(LogEntryKind.TestStep, "ReOpen: Disconnect from the share."); status = clientForReOpen.TreeDisconnect(treeIdForReOpen); BaseTestSite.Log.Add(LogEntryKind.TestStep, "ReOpen: Log Off."); status = clientForReOpen.LogOff(); #endregion }
private void DirecotryLeasing(LeaseStateValues leaseState) { DirecotryLeasing(TestConfig.RequestDialects, TestConfig.MaxSmbVersionSupported, leaseState); }
private void DirecotryLeasing( DialectRevision[] requestDialect, DialectRevision expectedDialect, LeaseStateValues leaseState, LeaseBreakAckType leaseBreakAckType = LeaseBreakAckType.None) { #region Check Applicability TestConfig.CheckDialect(DialectRevision.Smb30); TestConfig.CheckCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING); TestConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE_V2); #endregion BaseTestSite.Log.Add( LogEntryKind.Comment, @"Start to create a directory on share \\{0}\{1} with lease state {2}", TestConfig.SutComputerName, TestConfig.BasicFileShare, leaseState); string testDirectory = CreateTestDirectory(TestConfig.SutComputerName, TestConfig.BasicFileShare); client.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress); #region Negotiate BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start the client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT"); Capabilities_Values capabilities = Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES; status = client.Negotiate( requestDialect, TestConfig.IsSMB1NegotiateEnabled, capabilityValue: capabilities, checker: (Packet_Header header, NEGOTIATE_Response response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "Negotiation should succeed, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status)); TestConfig.CheckNegotiateDialect(expectedDialect, response); if (expectedDialect >= DialectRevision.Smb30) TestConfig.CheckNegotiateCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING, response); }); #endregion #region SESSION_SETUP status = client.SessionSetup( TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken); #endregion #region TREE_CONNECT to share string uncSharePath = Smb2Utility.GetUncPath(TestConfig.SutComputerName, TestConfig.BasicFileShare); uint treeId; status = client.TreeConnect(uncSharePath, out treeId); #endregion #region CREATE FILEID fileId; Smb2CreateContextResponse[] serverCreateContexts; BaseTestSite.Log.Add( LogEntryKind.TestStep, "Client sends CREATE request for the directory with the LeaseState set to {0} in SMB2_CREATE_REQUEST_LEASE_V2.", leaseState); status = client.Create( treeId, testDirectory, CreateOptions_Values.FILE_DIRECTORY_FILE, out fileId, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateRequestLeaseV2 { LeaseKey = Guid.NewGuid(), LeaseState = leaseState } }, checker: (Packet_Header header, CREATE_Response response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "CREATE should succeed, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status)); if (expectedDialect == DialectRevision.Smb2002 || expectedDialect == DialectRevision.Smb21) { BaseTestSite.Assert.AreEqual( OplockLevel_Values.OPLOCK_LEVEL_NONE, response.OplockLevel, "The expected oplock level is OPLOCK_LEVEL_NONE."); } }); #endregion if (expectedDialect >= DialectRevision.Smb30) { // Break the lease with creating another file in the directory sutProtocolController.CreateFile(Path.Combine(Smb2Utility.GetUncPath(TestConfig.SutComputerName, TestConfig.BasicFileShare), testDirectory), CurrentTestCaseName, string.Empty); // Wait until LEASE_BREAK_Notification is received BaseTestSite.Assert.IsTrue( // Wait for notification arrival notificationReceived.WaitOne(TestConfig.WaitTimeoutInMilliseconds), "LeaseBreakNotification should be raised."); if (receivedLeaseBreakNotify.Flags == LEASE_BREAK_Notification_Packet_Flags_Values.SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) { BaseTestSite.Log.Add( LogEntryKind.Debug, "Server requires an LEASE_BREAK_ACK on this LEASE_BREAK_NOTIFY"); #region LEASE_BREAK_ACK switch (leaseBreakAckType) { case LeaseBreakAckType.None: status = client.LeaseBreakAcknowledgment(treeId, receivedLeaseBreakNotify.LeaseKey, receivedLeaseBreakNotify.NewLeaseState); break; case LeaseBreakAckType.InvalidLeaseState: LeaseStateValues newLeaseState = LeaseStateValues.SMB2_LEASE_WRITE_CACHING; BaseTestSite.Log.Add( LogEntryKind.Comment, "Client attempts to send LEASE_BREAK_ACK with an invalid LeaseState {0} on this LEASE_BREAK_NOTIFY", newLeaseState); status = client.LeaseBreakAcknowledgment( treeId, receivedLeaseBreakNotify.LeaseKey, newLeaseState, checker: (header, response) => { BaseTestSite.Assert.AreNotEqual( Smb2Status.STATUS_SUCCESS, header.Status, "LEASE_BREAK_ACK with invalid LeaseState is not expected to SUCCESS, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status)); BaseTestSite.CaptureRequirementIfAreEqual( Smb2Status.STATUS_REQUEST_NOT_ACCEPTED, header.Status, RequirementCategory.STATUS_REQUEST_NOT_ACCEPTED.Id, RequirementCategory.STATUS_REQUEST_NOT_ACCEPTED.Description); }); break; case LeaseBreakAckType.InvalidLeaseKey: Guid invalidLeaseKey = Guid.NewGuid(); BaseTestSite.Log.Add( LogEntryKind.Debug, "Client attempts to send LEASE_BREAK_ACK with an invalid LeaseKey {0} on this LEASE_BREAK_NOTIFY", invalidLeaseKey); status = client.LeaseBreakAcknowledgment( treeId, invalidLeaseKey, receivedLeaseBreakNotify.NewLeaseState, checker: (header, response) => { BaseTestSite.Assert.AreNotEqual( Smb2Status.STATUS_SUCCESS, header.Status, "LEASE_BREAK_ACK with invalid LeaseKey is not expected to SUCCESS, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status)); BaseTestSite.CaptureRequirementIfAreEqual( Smb2Status.STATUS_OBJECT_NAME_NOT_FOUND, header.Status, RequirementCategory.STATUS_OBJECT_NAME_NOT_FOUND.Id, RequirementCategory.STATUS_OBJECT_NAME_NOT_FOUND.Description); }); break; case LeaseBreakAckType.InvalidClientGuid: BaseTestSite.Log.Add(LogEntryKind.Debug, "Initialize a new different client to attempts to send LEASE_BREAK_ACK"); Smb2FunctionalClient newClient = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite); newClient.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress); #region Negotiate status = newClient.Negotiate( requestDialect, TestConfig.IsSMB1NegotiateEnabled, capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES); #endregion #region SESSION_SETUP status = newClient.SessionSetup( TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken); #endregion #region TREE_CONNECT to share uint newTreeId; status = newClient.TreeConnect(uncSharePath, out newTreeId); #endregion status = newClient.LeaseBreakAcknowledgment( newTreeId, receivedLeaseBreakNotify.LeaseKey, receivedLeaseBreakNotify.NewLeaseState, checker: (header, response) => { BaseTestSite.Assert.AreNotEqual( Smb2Status.STATUS_SUCCESS, header.Status, "LEASE_BREAK_ACK is not expected to SUCCESS when the open is closed, actually server returns {0}.", Smb2Status.GetStatusCode(header.Status)); BaseTestSite.CaptureRequirementIfAreEqual( Smb2Status.STATUS_OBJECT_NAME_NOT_FOUND, header.Status, RequirementCategory.STATUS_OBJECT_NAME_NOT_FOUND.Id, RequirementCategory.STATUS_OBJECT_NAME_NOT_FOUND.Description); }); status = newClient.TreeDisconnect(newTreeId); status = newClient.LogOff(); BaseTestSite.Log.Add( LogEntryKind.Comment, "Initialize a new different client to attempts to send LEASE_BREAK_ACK"); break; default: throw new InvalidOperationException("Unexpected LeaseBreakAckType " + leaseBreakAckType); } #endregion } else { BaseTestSite.Log.Add( LogEntryKind.Debug, "Server does not require an LEASE_BREAK_ACK on this LEASE_BREAK_NOTIFY"); } } BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the client by sending the following requests: TREE_DISCONNECT; LOG_OFF"); #region TREE_DISCONNECT status = client.TreeDisconnect(treeId); #endregion #region LOGOFF status = client.LogOff(); #endregion BaseTestSite.Log.Add( LogEntryKind.Comment, @"Complete creating a directory on share \\{0}\{1} with lease state {2}", TestConfig.SutComputerName, TestConfig.BasicFileShare, leaseState); }
public void MultipleChannel_FileLease() { #region Check Applicability TestConfig.CheckDialect(DialectRevision.Smb30); TestConfig.CheckCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING); TestConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE_V2); #endregion mainChannelClient.Smb2Client.LeaseBreakNotificationReceived += new Action <Packet_Header, LEASE_BREAK_Notification_Packet>(base.OnLeaseBreakNotificationReceived); uint treeId; FILEID fileId; BaseTestSite.Log.Add( LogEntryKind.TestStep, "Establish main channel with client {0} and server {1}.", clientIps[0].ToString(), serverIps[0].ToString()); EstablishMainChannel( TestConfig.RequestDialects, serverIps[0], clientIps[0], out treeId); #region CREATE to open file to request lease BaseTestSite.Log.Add(LogEntryKind.TestStep, "Main channel: CREATE to open file to request lease."); LeaseStateValues leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING; // Add expected NewLeaseState expectedNewLeaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING; Smb2CreateContextResponse[] serverCreateContexts; status = mainChannelClient.Create( treeId, fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileId, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateRequestLeaseV2 { LeaseKey = Guid.NewGuid(), LeaseState = leaseState, } }, accessMask: AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE); #endregion #region WRITE content BaseTestSite.Log.Add(LogEntryKind.TestStep, "Main channel: WRITE content."); status = mainChannelClient.Write(treeId, fileId, contentWrite); #endregion BaseTestSite.Log.Add( LogEntryKind.TestStep, "Establish alternative channel with client {0} and server {1}.", clientIps[1].ToString(), serverIps[1].ToString()); EstablishAlternativeChannel( TestConfig.RequestDialects, serverIps[1], clientIps[1], treeId); // Create a timer that signals the delegate to invoke CheckBreakNotification after 5 seconds Timer timer = new Timer(CheckBreakNotification, treeId, 5000, Timeout.Infinite); Smb2FunctionalClient clientTriggeringBreak = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client3 connect to same server."); clientTriggeringBreak.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, serverIps[1], clientIps[1]); base.clientToAckLeaseBreak = mainChannelClient; BaseTestSite.Log.Add(LogEntryKind.TestStep, "Request CREATE from Client3 to trigger lease break notification."); BaseTestSite.Log.Add(LogEntryKind.Debug, "The operation will be blocked until notification is acknowledged or 35 seconds timeout."); TriggerBreakFromClient( clientTriggeringBreak, TestConfig.RequestDialects, false, LeaseStateValues.SMB2_LEASE_NONE, AccessMask.GENERIC_WRITE); ClientTearDown(alternativeChannelClient, treeId, fileId); }
private Smb2CreateRequestLease createLeaseRequestContext(Guid leaseKey = new Guid(), LeaseStateValues leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING) { return(new Smb2CreateRequestLease { LeaseKey = leaseKey == Guid.Empty ? Guid.NewGuid() : leaseKey, LeaseState = leaseState }); }
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 }
private void DurableHandleV2_Reconnect_WithLeaseV1(bool sameFileName, bool persistent = false) { #region Check Applicability TestConfig.CheckDialect(DialectRevision.Smb30); TestConfig.CheckCapabilities( persistent ? NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING | NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES: NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING); TestConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2, CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2, CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE); #endregion string content = Smb2Utility.CreateRandomString(testConfig.WriteBufferLengthInKb); Guid clientGuid = Guid.NewGuid(); durableHandleUncSharePath = persistent ? Smb2Utility.GetUncPath(testConfig.CAShareServerName, testConfig.CAShareName) : Smb2Utility.GetUncPath(testConfig.SutComputerName, testConfig.BasicFileShare); fileName = (persistent ? "PersistentHandle" : "DurableHandleV2") + "_Reconnect_WithLeaseV1" + Guid.NewGuid() + ".txt"; #region client connect to server BaseTestSite.Log.Add( LogEntryKind.Comment, "Client connects to server and opens file with a {0} handle", persistent ? "persistent" : "durable"); uint treeIdBeforeDisconnection; Connect( DialectRevision.Smb30, clientBeforeDisconnection, clientGuid, testConfig.AccountCredential, persistent ? ConnectShareType.CAShare : ConnectShareType.BasicShareWithoutAssert, out treeIdBeforeDisconnection, null); Guid createGuid = Guid.NewGuid(); Guid leaseKey = Guid.NewGuid(); LeaseStateValues leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING; FILEID fileIdBeforeDisconnection; Smb2CreateContextResponse[] serverCreateContexts = null; status = clientBeforeDisconnection.Create( treeIdBeforeDisconnection, fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdBeforeDisconnection, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleRequestV2 { CreateGuid = createGuid, Flags = persistent? CREATE_DURABLE_HANDLE_REQUEST_V2_Flags.DHANDLE_FLAG_PERSISTENT : 0, }, new Smb2CreateRequestLease { LeaseKey = leaseKey, LeaseState = leaseState, } }, shareAccess: ShareAccess_Values.NONE, checker: (header, response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "{0} should be successful, actually server returns {1}.", header.Command, Smb2Status.GetStatusCode(header.Status)); CheckCreateContextResponses( serverCreateContexts, new DefaultDurableHandleV2ResponseChecker( BaseTestSite, persistent ? CREATE_DURABLE_HANDLE_RESPONSE_V2_Flags.DHANDLE_FLAG_PERSISTENT : 0, uint.MaxValue)); }); status = clientBeforeDisconnection.Write(treeIdBeforeDisconnection, fileIdBeforeDisconnection, content); #endregion clientBeforeDisconnection.Disconnect(); #region client reconnect to server BaseTestSite.Log.Add( LogEntryKind.Comment, "Client opens the same file and reconnects the {0} handle", persistent ? "durable" : "persistent"); uint treeIdAfterDisconnection; Connect( DialectRevision.Smb30, clientAfterDisconnection, clientGuid, testConfig.AccountCredential, persistent ? ConnectShareType.CAShare : ConnectShareType.BasicShareWithoutAssert, out treeIdAfterDisconnection, clientBeforeDisconnection); FILEID fileIdAfterDisconnection; status = clientAfterDisconnection.Create( treeIdAfterDisconnection, sameFileName ? fileName : (persistent ? "PersistentHandle" : "DurableHandleV2" + "_Reconnect_WithLeaseV1_WithDifferentFileName" + Guid.NewGuid() + ".txt"), CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdAfterDisconnection, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleReconnectV2 { CreateGuid = createGuid, Flags = persistent ? CREATE_DURABLE_HANDLE_RECONNECT_V2_Flags.DHANDLE_FLAG_PERSISTENT : 0, FileId = new FILEID { Persistent = fileIdBeforeDisconnection.Persistent } }, new Smb2CreateRequestLease { LeaseKey = leaseKey, LeaseState = leaseState, } }, shareAccess: ShareAccess_Values.NONE, checker: (header, response) => { }); if (sameFileName) { BaseTestSite.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Reconnect a durable handle should be successful"); string readContent; status = clientAfterDisconnection.Read(treeIdAfterDisconnection, fileIdAfterDisconnection, 0, (uint)content.Length, out readContent); BaseTestSite.Assert.IsTrue( readContent.Equals(content), "The written content should equal to read content."); clientAfterDisconnection.Close(treeIdAfterDisconnection, fileIdAfterDisconnection); } else { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_INVALID_PARAMETER, status, "If Open.Lease is not NULL and Open.FileName does not match the file name specified in the Buffer field of the SMB2 CREATE request, " + "the server MUST fail the request with STATUS_INVALID_PARAMETER."); } #endregion clientAfterDisconnection.TreeDisconnect(treeIdAfterDisconnection); clientAfterDisconnection.LogOff(); clientAfterDisconnection.Disconnect(); }
/// <summary> /// Verify if server grant lease state as expected /// </summary> /// <param name="requestedLeaseState">Requested lease state from client</param> /// <param name="expectedGrantedLeaseState">Expected lease state that server granted</param> private void VerifyGrantedLeaseState(LeaseStateValues requestedLeaseState, LeaseStateValues expectedGrantedLeaseState) { Guid clientGuid = Guid.NewGuid(); string testDirectory = "DirectoryLeasing_GrantedLeaseState_" + clientGuid.ToString(); #region Connect to share BaseTestSite.Log.Add(LogEntryKind.TestStep, "Connect to share {0}.", uncSharePath); Smb2FunctionalClient client = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite); client.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress); #region Negotiate Capabilities_Values clientCapabilities = Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES; client.Negotiate( TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled, SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED, clientCapabilities, clientGuid, checker: (Packet_Header header, NEGOTIATE_Response response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "NEGOTIATE should succeed."); TestConfig.CheckNegotiateDialect(DialectRevision.Smb30, response); TestConfig.CheckNegotiateCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING, response); }); #endregion #region SessionSetup status = client.SessionSetup( TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken); BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, status, "SessionSetup should succeed, actual status is {0}", Smb2Status.GetStatusCode(status)); #endregion #region TreeConnect uint treeId; status = client.TreeConnect(uncSharePath, out treeId); BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, status, "TreeConnect should succeed, actual status is {0}", Smb2Status.GetStatusCode(status)); #endregion #endregion #region CREATE open to directory with lease BaseTestSite.Log.Add(LogEntryKind.TestStep, "CREATE open to directory with lease."); Smb2CreateContextResponse[] serverCreateContexts; FILEID fileId; status = client.Create( treeId, testDirectory, CreateOptions_Values.FILE_DIRECTORY_FILE, out fileId, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateRequestLeaseV2 { LeaseKey = clientGuid, LeaseState = requestedLeaseState } }, accessMask: AccessMask.GENERIC_ALL, shareAccess: ShareAccess_Values.FILE_SHARE_READ, checker: (header, response) => { }); BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, status, "Create an open on directory should succeed, actual status is {0}", Smb2Status.GetStatusCode(status)); #endregion #region Verify server granted lease state BaseTestSite.Log.Add(LogEntryKind.TestStep, "Verify server granted lease state."); BaseTestSite.Assert.AreNotEqual( null, serverCreateContexts, "Server should return granted lease state"); foreach (Smb2CreateContextResponse serverCreateContext in serverCreateContexts) { Smb2CreateResponseLeaseV2 createResponseLeaseV2 = serverCreateContext as Smb2CreateResponseLeaseV2; if (createResponseLeaseV2 != null) { BaseTestSite.Assert.AreEqual( expectedGrantedLeaseState, createResponseLeaseV2.LeaseState, "Server granted lease state {0} should be the same as {1}", createResponseLeaseV2.LeaseState, expectedGrantedLeaseState); break; } } #endregion }
public Smb2LeaseBreakResponsePacket CreateLeaseBreakResponse( Smb2Endpoint endpoint, ulong messageId, LeaseStateValues leaseState ) { Smb2LeaseBreakResponsePacket packet = new Smb2LeaseBreakResponsePacket(); SetHeader(packet, endpoint, messageId); Smb2LeaseBreakAckPacket leaseBreakAck = context.FindRequestPacket(endpoint.EndpointId, messageId) as Smb2LeaseBreakAckPacket; packet.PayLoad.Flags = LEASE_BREAK_Response_Packet_Flags_Values.V1; packet.PayLoad.LeaseDuration = LEASE_BREAK_Response_Packet_LeaseDuration_Values.V1; packet.PayLoad.LeaseKey = leaseBreakAck.PayLoad.LeaseKey; packet.PayLoad.LeaseState = leaseState; packet.PayLoad.Reserved = LEASE_BREAK_Response_Reserved_Values.V1; packet.PayLoad.StructureSize = LEASE_BREAK_Response_StructureSize_Values.V1; packet.Sign(); return packet; }
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> /// Test FileServer failover with leasing /// </summary> /// <param name="isDirectory">True to indicate target is directory, otherwise is file</param> /// <param name="requestedLeaseState">Original LeaseState to request for durable open</param> /// <param name="accessMask">Original AccessMask to request for durable open</param> /// <param name="accessMaskToTriggerBreak">AccessMask that a separate client to request to open the same file/directory to trigger LeaseBreakNotification</param> private void FileServerFailoverWithLeasing(bool isDirectory, LeaseStateValues requestedLeaseState, AccessMask accessMask, AccessMask accessMaskToTriggerBreak) { clientAfterFailover.Smb2Client.LeaseBreakNotificationReceived += new Action<Packet_Header, LEASE_BREAK_Notification_Packet>(base.OnLeaseBreakNotificationReceived); FILEID fileIdBeforeFailover; uint treeIdBeforeFailover; BaseTestSite.Log.Add(LogEntryKind.TestStep, "BeforeFailover: Connect to general file server {0}.", TestConfig.ClusteredFileServerName); ConnectGeneralFileServerBeforeFailover(TestConfig.ClusteredFileServerName, out treeIdBeforeFailover); #region CREATE a durable open with flag DHANDLE_FLAG_PERSISTENT BaseTestSite.Log.Add(LogEntryKind.TestStep, "BeforeFailover: CREATE a durable open with flag DHANDLE_FLAG_PERSISTENT."); Smb2CreateContextResponse[] serverCreateContexts; createGuid = Guid.NewGuid(); leaseKey = Guid.NewGuid(); status = clientBeforeFailover.Create( treeIdBeforeFailover, isDirectory ? testDirectory : fileName, isDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdBeforeFailover, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleRequestV2 { CreateGuid = createGuid, Flags = CREATE_DURABLE_HANDLE_REQUEST_V2_Flags.DHANDLE_FLAG_PERSISTENT, Timeout = 3600000, }, new Smb2CreateRequestLeaseV2 { LeaseKey = leaseKey, LeaseState = requestedLeaseState, } }, accessMask: accessMask); #endregion BaseTestSite.Log.Add( LogEntryKind.TestStep, "Do failover of the file server."); FailoverServer(currentAccessIp, TestConfig.ClusteredFileServerName, FileServerType.GeneralFileServer); FILEID fileIdAfterFailover = FILEID.Zero; uint treeIdAfterFailover; BaseTestSite.Log.Add(LogEntryKind.TestStep, "AfterFailover: Reconnect to the same general file server {0}.", TestConfig.ClusteredFileServerName); ReconnectServerAfterFailover(TestConfig.ClusteredFileServerName, FileServerType.GeneralFileServer, out treeIdAfterFailover); #region CREATE to reconnect previous duarable open with flag DHANDLE_FLAG_PERSISTENT BaseTestSite.Log.Add(LogEntryKind.TestStep, "AfterFailover: CREATE to reconnect previous duarable open with flag DHANDLE_FLAG_PERSISTENT."); status = DoUntilSucceed( () => clientAfterFailover.Create( treeIdAfterFailover, isDirectory ? testDirectory : fileName, isDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdAfterFailover, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleReconnectV2 { FileId = new FILEID { Persistent = fileIdBeforeFailover.Persistent }, CreateGuid = createGuid, Flags = CREATE_DURABLE_HANDLE_RECONNECT_V2_Flags.DHANDLE_FLAG_PERSISTENT }, new Smb2CreateRequestLeaseV2 { LeaseKey = leaseKey, LeaseState = requestedLeaseState, } }, accessMask: accessMask, checker: (header, response) => { }), TestConfig.FailoverTimeout, "Retry Create until succeed within timeout span"); #endregion // Create a timer that signals the delegate to invoke CheckBreakNotification Timer timer = new Timer(CheckBreakNotification, treeIdAfterFailover, 0, Timeout.Infinite); base.clientToAckLeaseBreak = clientAfterFailover; Smb2FunctionalClient clientTriggeringBreak = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite); clientTriggeringBreak.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.ClusteredFileServerName, currentAccessIp); // Request CREATE from Client3 to trigger lease break notification and the operation will be blocked until notification is acknowledged or 35 seconds timeout BaseTestSite.Log.Add( LogEntryKind.TestStep, "AfterFailover: Request CREATE from Client3 to trigger lease break notification and the operation will be blocked until notification is acknowledged or 35 seconds timeout."); TriggerBreakFromClient( clientTriggeringBreak, TestConfig.RequestDialects, TestConfig.ClusteredFileServerName, isDirectory, LeaseStateValues.SMB2_LEASE_NONE, accessMaskToTriggerBreak); BaseTestSite.Log.Add( LogEntryKind.TestStep, "AfterFailover: Sleep 1 second to wait completion of LeaseBreakNotification check and acknowledgement in background thread"); Thread.Sleep(1000); status = clientAfterFailover.Close(treeIdAfterFailover, fileIdAfterFailover); status = clientAfterFailover.TreeDisconnect(treeIdAfterFailover); status = clientAfterFailover.LogOff(); }
/// <summary> /// Test FileServer failover with leasing /// </summary> /// <param name="isDirectory">True to indicate target is directory, otherwise is file</param> /// <param name="requestedLeaseState">Original LeaseState to request for durable open</param> /// <param name="accessMask">Original AccessMask to request for durable open</param> /// <param name="accessMaskToTriggerBreak">AccessMask that a separate client to request to open the same file/directory to trigger LeaseBreakNotification</param> private void FileServerFailoverWithLeasing(bool isDirectory, LeaseStateValues requestedLeaseState, AccessMask accessMask, AccessMask accessMaskToTriggerBreak) { clientAfterFailover.Smb2Client.LeaseBreakNotificationReceived += new Action <Packet_Header, LEASE_BREAK_Notification_Packet>(base.OnLeaseBreakNotificationReceived); FILEID fileIdBeforeFailover; uint treeIdBeforeFailover; BaseTestSite.Log.Add(LogEntryKind.TestStep, "BeforeFailover: Connect to general file server {0}.", TestConfig.ClusteredFileServerName); ConnectGeneralFileServerBeforeFailover(TestConfig.ClusteredFileServerName, out treeIdBeforeFailover); #region CREATE a durable open with flag DHANDLE_FLAG_PERSISTENT BaseTestSite.Log.Add(LogEntryKind.TestStep, "BeforeFailover: CREATE a durable open with flag DHANDLE_FLAG_PERSISTENT."); Smb2CreateContextResponse[] serverCreateContexts; createGuid = Guid.NewGuid(); leaseKey = Guid.NewGuid(); status = clientBeforeFailover.Create( treeIdBeforeFailover, isDirectory ? testDirectory : fileName, isDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdBeforeFailover, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleRequestV2 { CreateGuid = createGuid, Flags = CREATE_DURABLE_HANDLE_REQUEST_V2_Flags.DHANDLE_FLAG_PERSISTENT, Timeout = 3600000, }, new Smb2CreateRequestLeaseV2 { LeaseKey = leaseKey, LeaseState = requestedLeaseState, } }, accessMask: accessMask); #endregion BaseTestSite.Log.Add( LogEntryKind.TestStep, "Do failover of the file server."); FailoverServer(currentAccessIp, TestConfig.ClusteredFileServerName, FileServerType.GeneralFileServer); FILEID fileIdAfterFailover = FILEID.Zero; uint treeIdAfterFailover; BaseTestSite.Log.Add(LogEntryKind.TestStep, "AfterFailover: Reconnect to the same general file server {0}.", TestConfig.ClusteredFileServerName); ReconnectServerAfterFailover(TestConfig.ClusteredFileServerName, FileServerType.GeneralFileServer, out treeIdAfterFailover); #region CREATE to reconnect previous duarable open with flag DHANDLE_FLAG_PERSISTENT BaseTestSite.Log.Add(LogEntryKind.TestStep, "AfterFailover: CREATE to reconnect previous duarable open with flag DHANDLE_FLAG_PERSISTENT."); status = DoUntilSucceed( () => clientAfterFailover.Create( treeIdAfterFailover, isDirectory ? testDirectory : fileName, isDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdAfterFailover, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleReconnectV2 { FileId = new FILEID { Persistent = fileIdBeforeFailover.Persistent }, CreateGuid = createGuid, Flags = CREATE_DURABLE_HANDLE_RECONNECT_V2_Flags.DHANDLE_FLAG_PERSISTENT }, new Smb2CreateRequestLeaseV2 { LeaseKey = leaseKey, LeaseState = requestedLeaseState, } }, accessMask: accessMask, checker: (header, response) => { }), TestConfig.FailoverTimeout, "Retry Create until succeed within timeout span"); #endregion // Create a timer that signals the delegate to invoke CheckBreakNotification after 5 seconds Timer timer = new Timer(CheckBreakNotification, treeIdAfterFailover, 5000, Timeout.Infinite); base.clientToAckLeaseBreak = clientAfterFailover; Smb2FunctionalClient clientTriggeringBreak = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite); clientTriggeringBreak.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.ClusteredFileServerName, currentAccessIp); // Request CREATE from Client3 to trigger lease break notification and the operation will be blocked until notification is acknowledged or 35 seconds timeout BaseTestSite.Log.Add( LogEntryKind.TestStep, "AfterFailover: Request CREATE from Client3 to trigger lease break notification and the operation will be blocked until notification is acknowledged or 35 seconds timeout."); TriggerBreakFromClient( clientTriggeringBreak, TestConfig.RequestDialects, TestConfig.ClusteredFileServerName, isDirectory, LeaseStateValues.SMB2_LEASE_NONE, accessMaskToTriggerBreak); BaseTestSite.Log.Add( LogEntryKind.TestStep, "AfterFailover: Sleep 10 seconds to wait completion of LeaseBreakNotification check and acknowledgement in background thread"); Thread.Sleep(10000); status = clientAfterFailover.Close(treeIdAfterFailover, fileIdAfterFailover); status = clientAfterFailover.TreeDisconnect(treeIdAfterFailover); status = clientAfterFailover.LogOff(); }
/// <summary> /// Attempt to trigger LeaseBreakNotification from a separate client /// </summary> /// <param name="client">Client to trigger LeaseBreakNotification</param> /// <param name="requestDialect">Negotiate dialects</param> /// <param name="isDirectory">True value indicating to open a directory, false for a file</param> /// <param name="requestedLeaseState">LeaseState when open the directory or file</param> /// <param name="accessMask">AccessMask when open the directory or file</param> private void TriggerBreakFromClient( Smb2FunctionalClient client, DialectRevision[] requestDialect, bool isDirectory, LeaseStateValues requestedLeaseState, AccessMask accessMask) { BaseTestSite.Log.Add( LogEntryKind.Debug, "Trigger a lease break notification by accessing same file/directory from a separate client with LeaseState {0} and AccessMask {1}", requestedLeaseState, accessMask); #region Negotiate status = client.Negotiate( requestDialect, TestConfig.IsSMB1NegotiateEnabled, capabilityValue: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES); #endregion #region SESSION_SETUP status = client.SessionSetup( TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken); #endregion #region TREE_CONNECT to share uint treeId; status = client.TreeConnect(uncSharePath, out treeId); #endregion #region CREATE FILEID fileId; Smb2CreateContextResponse[] serverCreateContexts; status = client.Create( treeId, isDirectory ? testDirectory : fileName, isDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileId, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateRequestLeaseV2 { LeaseKey = Guid.NewGuid(), LeaseState = requestedLeaseState } }, accessMask: accessMask); #endregion BaseTestSite.Log.Add( LogEntryKind.Debug, "Finish triggering lease break notification"); }
public void DurableHandleV2_Reconnect_WithoutPersistence() { /// 1. Client requests a durable handle V2 without persistent flag /// 2. Lose connection by disabling NIC /// 3. Client reconnects the durable handle V2 without persistent flag. #region Check Applicability TestConfig.CheckDialect(DialectRevision.Smb30); TestConfig.CheckCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING); TestConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2, CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2, CreateContextTypeValue.SMB2_CREATE_REQUEST_LEASE); #endregion string content = Smb2Utility.CreateRandomString(testConfig.WriteBufferLengthInKb); Guid clientGuid = Guid.NewGuid(); durableHandleUncSharePath = Smb2Utility.GetUncPath(testConfig.SutComputerName, testConfig.BasicFileShare); fileName = "DurableHandleV2_Reconnect_WithoutPersistence" + Guid.NewGuid() + ".txt"; #region client connect to server BaseTestSite.Log.Add( LogEntryKind.Comment, "Client connects to server and opens file with a durable handle"); uint treeIdBeforeDisconnection; Connect(DialectRevision.Smb30, clientBeforeDisconnection, clientGuid, testConfig.AccountCredential, ConnectShareType.BasicShareWithoutAssert, out treeIdBeforeDisconnection, null); Guid createGuid = Guid.NewGuid(); Guid leaseKey = Guid.NewGuid(); LeaseStateValues leaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING; FILEID fileIdBeforeDisconnection; Smb2CreateContextResponse[] serverCreateContexts = null; clientBeforeDisconnection.Create( treeIdBeforeDisconnection, fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdBeforeDisconnection, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleRequestV2 { CreateGuid = createGuid, }, new Smb2CreateRequestLeaseV2 { LeaseKey = leaseKey, LeaseState = leaseState, } }, shareAccess: ShareAccess_Values.NONE, checker: (header, response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "{0} should be successful, actually server returns {1}.", header.Command, Smb2Status.GetStatusCode(header.Status)); CheckCreateContextResponses(serverCreateContexts, new DefaultDurableHandleV2ResponseChecker(BaseTestSite, 0, uint.MaxValue)); }); clientBeforeDisconnection.Write(treeIdBeforeDisconnection, fileIdBeforeDisconnection, content); #endregion clientBeforeDisconnection.Disconnect(); #region client reconnect to server BaseTestSite.Log.Add( LogEntryKind.Comment, "Client opens the same file and reconnects the durable handle"); uint treeIdAfterDisconnection; Connect(DialectRevision.Smb30, clientAfterDisconnection, clientGuid, testConfig.AccountCredential, ConnectShareType.BasicShareWithoutAssert, out treeIdAfterDisconnection, clientBeforeDisconnection); FILEID fileIdAfterDisconnection; clientAfterDisconnection.Create( treeIdAfterDisconnection, fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdAfterDisconnection, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleReconnectV2 { CreateGuid = createGuid, FileId = new FILEID { Persistent = fileIdBeforeDisconnection.Persistent } }, new Smb2CreateRequestLeaseV2 { LeaseKey = leaseKey, LeaseState = leaseState, } }, shareAccess: ShareAccess_Values.NONE); string readContent; clientAfterDisconnection.Read(treeIdAfterDisconnection, fileIdAfterDisconnection, 0, (uint)content.Length, out readContent); BaseTestSite.Assert.IsTrue( content.Equals(readContent), "The written content is expected to be equal to read content."); #endregion clientAfterDisconnection.Close(treeIdAfterDisconnection, fileIdAfterDisconnection); clientAfterDisconnection.TreeDisconnect(treeIdAfterDisconnection); clientAfterDisconnection.LogOff(); clientAfterDisconnection.Disconnect(); }