private void NewTestFile(Smb2FunctionalClient client, string fileName, string content, out uint treeId, out FILEID fileId) { client.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.ShareServerName, TestConfig.ShareServerIP); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start the client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT"); client.Negotiate( TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled, checker: (Packet_Header header, NEGOTIATE_Response response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_SUCCESS, header.Status, "NEGOTIATE should succeed."); TestConfig.CheckNegotiateDialect(DialectRevision.Smb30, response); }); client.SessionSetup( TestConfig.DefaultSecurityPackage, TestConfig.ShareServerName, //TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken); //string uncSharePath = Smb2Utility.GetUncPath(TestConfig.HvrsSutComputerName, TestConfig.ShareName); client.TreeConnect(TestConfig.SharePath, out treeId); //string uncSharePath = Smb2Utility.GetUncPath(TestConfig.SutComputerName, TestConfig.BasicFileShare); //client.TreeConnect(uncSharePath, out treeId); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client writes to the file."); Smb2CreateContextResponse[] serverCreateContexts; client.Create( treeId, fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileId, out serverCreateContexts); client.Write(treeId, fileId, content); // Flush written content to backend storage to avoid cache. client.Flush(treeId, fileId); }
/// <summary> /// Write content before failover /// </summary> /// <param name="fsType">FileServerType</param> /// <param name="server">File Server name.</param> /// <param name="serverAccessIp">File Server Access IP.</param> /// <param name="uncSharePath">The share path to write the file.</param> /// <param name="file">The file name for writing content.</param> /// <param name="content">The content to write.</param> /// <param name="clientGuid">Smb2 client Guid.</param> /// <param name="createGuid">The Guid for smb2 create request.</param> /// <returns></returns> protected bool WriteContentBeforeFailover( FileServerType fsType, string server, IPAddress serverAccessIp, string uncSharePath, string file, string content, Guid clientGuid, Guid createGuid) { uint status = 0; beforeFailover = new Smb2FunctionalClient(TestConfig.FailoverTimeout, TestConfig, BaseTestSite); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start a client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT to {0}", uncSharePath); beforeFailover.ConnectToServer(TestConfig.UnderlyingTransport, server, serverAccessIp); Capabilities_Values requestCapabilities = 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 = beforeFailover.Negotiate( TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled, capabilityValue: requestCapabilities, clientGuid: clientGuid, checker: (header, response) => { TestConfig.CheckNegotiateDialect(DialectRevision.Smb30, response); }); if (status != Smb2Status.STATUS_SUCCESS) { BaseTestSite.Log.Add(LogEntryKind.Warning, "Negotiate failed with {0}.", Smb2Status.GetStatusCode(status)); return(false); } status = beforeFailover.SessionSetup( TestConfig.DefaultSecurityPackage, server, TestConfig.AccountCredential, TestConfig.UseServerGssToken); if (status != Smb2Status.STATUS_SUCCESS) { BaseTestSite.Log.Add(LogEntryKind.Warning, "SessionSetup failed with {0}.", Smb2Status.GetStatusCode(status)); return(false); } uint treeId = 0; Share_Capabilities_Values shareCapabilities = Share_Capabilities_Values.NONE; status = DoUntilSucceed( () => beforeFailover.TreeConnect(uncSharePath, out treeId, (header, response) => { shareCapabilities = response.Capabilities; }), TestConfig.FailoverTimeout, "Retry TreeConnect until succeed within timeout span"); if (status != Smb2Status.STATUS_SUCCESS) { BaseTestSite.Log.Add(LogEntryKind.Warning, "TreeConnect failed with {0}.", Smb2Status.GetStatusCode(status)); return(false); } BaseTestSite.Assert.IsTrue(shareCapabilities.HasFlag(Share_Capabilities_Values.SHARE_CAP_CONTINUOUS_AVAILABILITY), "CA Share should have SHARE_CAP_CONTINUOUS_AVAILABILITY bit set for Capabilities in TreeConnect response."); if (fsType == FileServerType.ScaleOutFileServer) { BaseTestSite.Assert.IsTrue(shareCapabilities.HasFlag(Share_Capabilities_Values.SHARE_CAP_SCALEOUT), "ScaleOut FS should have SHARE_CAP_SCALEOUT bit set for Capabilities in TreeConnect response."); } FILEID fileId; Smb2CreateContextResponse[] serverCreateContexts; BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends CREATE request with SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 with PERSISTENT flag set."); status = beforeFailover.Create( treeId, file, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileId, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleRequestV2 { CreateGuid = createGuid, Flags = CREATE_DURABLE_HANDLE_REQUEST_V2_Flags.DHANDLE_FLAG_PERSISTENT, Timeout = 3600000, }, }); if (status != Smb2Status.STATUS_SUCCESS) { BaseTestSite.Log.Add(LogEntryKind.Warning, "Create failed with {0}.", Smb2Status.GetStatusCode(status)); return(false); } BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends WRITE request to write content to the file."); status = beforeFailover.Write(treeId, fileId, content); if (status != Smb2Status.STATUS_SUCCESS) { BaseTestSite.Log.Add(LogEntryKind.Warning, "Write content failed with {0}.", Smb2Status.GetStatusCode(status)); return(false); } BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends FLUSH request."); status = beforeFailover.Flush(treeId, fileId); if (status != Smb2Status.STATUS_SUCCESS) { BaseTestSite.Log.Add(LogEntryKind.Warning, "Flush failed with {0}.", Smb2Status.GetStatusCode(status)); return(false); } return(true); }
/// <summary> /// Write content before failover /// </summary> /// <param name="fsType">FileServerType</param> /// <param name="server">File Server name.</param> /// <param name="serverAccessIp">File Server Access IP.</param> /// <param name="uncSharePath">The share path to write the file.</param> /// <param name="file">The file name for writing content.</param> /// <param name="content">The content to write.</param> /// <param name="clientGuid">Smb2 client Guid.</param> /// <param name="createGuid">The Guid for smb2 create request.</param> /// <returns></returns> protected bool WriteContentBeforeFailover( FileServerType fsType, string server, IPAddress serverAccessIp, string uncSharePath, string file, string content, Guid clientGuid, Guid createGuid) { uint status = 0; beforeFailover = new Smb2FunctionalClient(TestConfig.FailoverTimeout, TestConfig, BaseTestSite); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start a client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT to {0}", uncSharePath); beforeFailover.ConnectToServer(TestConfig.UnderlyingTransport, server, serverAccessIp); Capabilities_Values requestCapabilities = 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 = beforeFailover.Negotiate( TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled, capabilityValue: requestCapabilities, clientGuid: clientGuid, checker: (header, response) => { TestConfig.CheckNegotiateDialect(DialectRevision.Smb30, response); }); if (status != Smb2Status.STATUS_SUCCESS) { BaseTestSite.Log.Add(LogEntryKind.Warning, "Negotiate failed with {0}.", Smb2Status.GetStatusCode(status)); return false; } status = beforeFailover.SessionSetup( TestConfig.DefaultSecurityPackage, server, TestConfig.AccountCredential, TestConfig.UseServerGssToken); if (status != Smb2Status.STATUS_SUCCESS) { BaseTestSite.Log.Add(LogEntryKind.Warning, "SessionSetup failed with {0}.", Smb2Status.GetStatusCode(status)); return false; } uint treeId = 0; Share_Capabilities_Values shareCapabilities = Share_Capabilities_Values.NONE; status = DoUntilSucceed( () => beforeFailover.TreeConnect(uncSharePath, out treeId, (header, response) => { shareCapabilities = response.Capabilities; }), TestConfig.FailoverTimeout, "Retry TreeConnect until succeed within timeout span"); if (status != Smb2Status.STATUS_SUCCESS) { BaseTestSite.Log.Add(LogEntryKind.Warning, "TreeConnect failed with {0}.", Smb2Status.GetStatusCode(status)); return false; } BaseTestSite.Assert.IsTrue(shareCapabilities.HasFlag(Share_Capabilities_Values.SHARE_CAP_CONTINUOUS_AVAILABILITY), "CA Share should have SHARE_CAP_CONTINUOUS_AVAILABILITY bit set for Capabilities in TreeConnect response."); if (fsType == FileServerType.ScaleOutFileServer) { BaseTestSite.Assert.IsTrue(shareCapabilities.HasFlag(Share_Capabilities_Values.SHARE_CAP_SCALEOUT), "ScaleOut FS should have SHARE_CAP_SCALEOUT bit set for Capabilities in TreeConnect response."); } FILEID fileId; Smb2CreateContextResponse[] serverCreateContexts; BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends CREATE request with SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 with PERSISTENT flag set."); status = beforeFailover.Create( treeId, file, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileId, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleRequestV2 { CreateGuid = createGuid, Flags = CREATE_DURABLE_HANDLE_REQUEST_V2_Flags.DHANDLE_FLAG_PERSISTENT, Timeout = 3600000, }, }); if (status != Smb2Status.STATUS_SUCCESS) { BaseTestSite.Log.Add(LogEntryKind.Warning, "Create failed with {0}.", Smb2Status.GetStatusCode(status)); return false; } BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends WRITE request to write content to the file."); status = beforeFailover.Write(treeId, fileId, content); if (status != Smb2Status.STATUS_SUCCESS) { BaseTestSite.Log.Add(LogEntryKind.Warning, "Write content failed with {0}.", Smb2Status.GetStatusCode(status)); return false; } BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends FLUSH request."); status = beforeFailover.Flush(treeId, fileId); if (status != Smb2Status.STATUS_SUCCESS) { BaseTestSite.Log.Add(LogEntryKind.Warning, "Flush failed with {0}.", Smb2Status.GetStatusCode(status)); return false; } return true; }
public void BVT_CopyOffload() { BaseTestSite.Log.Add(LogEntryKind.TestStep, "1. Create a file with specified length {0} as the source of offload copy.", TestConfig.WriteBufferLengthInKb * 1024); string content = Smb2Utility.CreateRandomString(TestConfig.WriteBufferLengthInKb); string fileName = Guid.NewGuid().ToString(); uint treeId; FILEID fileIdSrc; PrepareTestFile(fileName, content, out treeId, out fileIdSrc); BaseTestSite.Log.Add(LogEntryKind.TestStep, "2. Client sends IOCTL request with FSCTL_OFFLOAD_READ to ask server to generate the token of the content for offload copy."); STORAGE_OFFLOAD_TOKEN token; ulong fileOffsetToRead = 0; //FileOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes ulong copyLengthToRead = (ulong)TestConfig.WriteBufferLengthInKb * 1024; //CopyLength should be aligned to logical sector boundary on the volume, e.g. 512 bytes ulong transferLength; // Request hardware to generate a token that represents a range of file to be copied client.OffloadRead( treeId, fileIdSrc, fileOffsetToRead, copyLengthToRead, out transferLength, out token); BaseTestSite.Log.Add(LogEntryKind.Debug, "Transfer length during OFFLOAD_READ is {0}", transferLength); BaseTestSite.Assert.AreEqual(copyLengthToRead, transferLength, "Transfer length {0} should be equal to copy length {1}", transferLength, copyLengthToRead); BaseTestSite.Log.Add(LogEntryKind.TestStep, "3. Create another file as the destination of offload copy."); FILEID fileIdDest; Smb2CreateContextResponse[] serverCreateContexts; client.Create( treeId, Guid.NewGuid().ToString(), CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileIdDest, out serverCreateContexts); // The destination file of CopyOffload Write should be equal to or larger than the size of original file client.Write(treeId, fileIdDest, Smb2Utility.CreateRandomString(TestConfig.WriteBufferLengthInKb)); client.Flush(treeId, fileIdDest); BaseTestSite.Log.Add(LogEntryKind.TestStep, "4. Client sends IOCTL request with FSCTL_OFFLOAD_WRITE to ask server to copy the content from source to destination."); ulong fileOffsetToWrite = 0; //FileOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes ulong copyLengthToWrite = transferLength; //CopyLength should be aligned to logical sector boundary on the volume, e.g. 512 bytes ulong transferOffset = 0; //TransferOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes // Request hardware to write a range of file which is represented by the generated token // and length/offset to another place (a different file or different offset of the same file) client.OffloadWrite( treeId, fileIdDest, fileOffsetToWrite, copyLengthToWrite, transferOffset, token); BaseTestSite.Log.Add(LogEntryKind.TestStep, "5. Compare the content of section 1 with the content of section 2."); string readContent; // Read the content that was just offload copied client.Read( treeId, fileIdDest, fileOffsetToWrite, (uint)copyLengthToWrite, out readContent); BaseTestSite.Assert.IsTrue( readContent.Equals(content), "File content read should equal to original"); BaseTestSite.Log.Add(LogEntryKind.TestStep, "6. Tear down the client by sending the following requests: CLOSE; TREE_DISCONNECT; LOG_OFF."); client.Close(treeId, fileIdSrc); client.Close(treeId, fileIdDest); client.TreeDisconnect(treeId); client.LogOff(); }
public void BVT_ResilientHandle_LockSequence() { #region Check Applicability TestConfig.CheckDialect(DialectRevision.Smb21); TestConfig.CheckIOCTL(CtlCode_Values.FSCTL_LMR_REQUEST_RESILIENCY); TestConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_RECONNECT); #endregion Guid clientGuid = Guid.NewGuid(); #region clientBeforeDisconnection Create a File BaseTestSite.Log.Add( LogEntryKind.TestStep, "Start the first client to create a file by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT; CREATE."); clientBeforeDisconnection.Negotiate(TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled, clientGuid: clientGuid); clientBeforeDisconnection.SessionSetup(TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, false); uint treeId; clientBeforeDisconnection.TreeConnect(sharePath, out treeId); FILEID fileId; Smb2CreateContextResponse[] createContextResponse; clientBeforeDisconnection.Create(treeId, fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileId, out createContextResponse); #endregion #region Request Resilient Handle IOCTL_Response IOCTLResponse; byte[] inputInResponse; byte[] outputInResponse; Packet_Header packetHeader; BaseTestSite.Log.Add( LogEntryKind.TestStep, "The first client sends an IOCTL FSCTL_LMR_REQUEST_RESILLIENCY request."); clientBeforeDisconnection.ResiliencyRequest(treeId, fileId, TestConfig.MaxResiliencyTimeoutInSecond * 1000, NETWORK_RESILIENCY_REQUEST_SIZE, out packetHeader, out IOCTLResponse, out inputInResponse, out outputInResponse); BaseTestSite.Log.Add(LogEntryKind.TestStep, "The first client sends WRITE request."); clientBeforeDisconnection.Write(treeId, fileId, "12345678"); BaseTestSite.Log.Add(LogEntryKind.TestStep, "The first client sends Flush request."); clientBeforeDisconnection.Flush(treeId, fileId); #endregion //The LockSequence field of the SMB2 lock request MUST be set to (BucketNumber<< 4) + BucketSequence. int bucketNum = 1; int bucketSeq = 1; uint lockSequence = (uint)bucketNum << 4 + bucketSeq; BaseTestSite.Log.Add( LogEntryKind.TestStep, "The first client sends LOCK request with LockSequence set to (BucketNumber<< 4) + BucketSequence"); clientBeforeDisconnection.Lock(treeId, lockSequence, fileId, new LOCK_ELEMENT[] { new LOCK_ELEMENT { Flags = LOCK_ELEMENT_Flags_Values.LOCKFLAG_EXCLUSIVE_LOCK | LOCK_ELEMENT_Flags_Values.LOCKFLAG_FAIL_IMMEDIATELY, Offset = 0, Length = 4 } }); clientBeforeDisconnection.Disconnect(); #region clientAfterDisconnection Opens the Previously Created File BaseTestSite.Log.Add( LogEntryKind.TestStep, "Start the second client to reconnect to the file created by the first client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT; CREATE (with SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context)."); clientAfterDisconnection.Negotiate(TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled, clientGuid: clientGuid); clientAfterDisconnection.ReconnectSessionSetup(clientBeforeDisconnection, TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, false); clientAfterDisconnection.TreeConnect(sharePath, out treeId); clientAfterDisconnection.Create(treeId, fileName, CreateOptions_Values.FILE_NON_DIRECTORY_FILE, out fileId, out createContextResponse, RequestedOplockLevel_Values.OPLOCK_LEVEL_BATCH, new Smb2CreateContextRequest[] { new Smb2CreateDurableHandleReconnect { Data = fileId } }); #endregion //If the sequence numbers are equal, the server MUST complete the lock/unlock request with success. BaseTestSite.Log.Add(LogEntryKind.TestStep, "The second client sends LOCK request with the same LockSequence with the first client."); clientAfterDisconnection.Lock(treeId, lockSequence, //Using same Lock Sequence fileId, new LOCK_ELEMENT[] { new LOCK_ELEMENT { Flags = LOCK_ELEMENT_Flags_Values.LOCKFLAG_EXCLUSIVE_LOCK | LOCK_ELEMENT_Flags_Values.LOCKFLAG_FAIL_IMMEDIATELY, Offset = 0, Length = 4 } }); clientAfterDisconnection.Lock(treeId, lockSequence + 1, //Using different Lock Sequence fileId, new LOCK_ELEMENT[] { new LOCK_ELEMENT { Flags = LOCK_ELEMENT_Flags_Values.LOCKFLAG_EXCLUSIVE_LOCK | LOCK_ELEMENT_Flags_Values.LOCKFLAG_FAIL_IMMEDIATELY, Offset = 0, Length = 4 } }, (header, response) => { BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_LOCK_NOT_GRANTED, header.Status, "If the range being locked is already locked by another open in a way that does not allow this open to take a lock on the range, " + "and if SMB2_LOCKFLAG_FAIL_IMMEDIATELY is set, the server MUST fail the request with STATUS_LOCK_NOT_GRANTED. " + "Actually server returns {0}.", Smb2Status.GetStatusCode(header.Status)); }); #region Tear Down Client BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the second client by sending the following requests: CLOSE; TREE_DISCONNECT; LOG_OFF"); clientAfterDisconnection.Close(treeId, fileId); clientAfterDisconnection.TreeDisconnect(treeId); clientAfterDisconnection.LogOff(); #endregion }