/// <summary> /// Get share capabilities /// </summary> /// <param name="server">The host node</param> /// <param name="sharePath">The path to the share</param> /// <param name="flags">Tree Connect flag</param> /// <returns>Share capabilities</returns> private Share_Capabilities_Values GetShareCapabilities(string server, string sharePath, TreeConnect_Flags flags = TreeConnect_Flags.SMB2_SHAREFLAG_NONE) { IPAddress shareIpAddr = Dns.GetHostEntry(server).AddressList[0]; Smb2FunctionalClient client = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite); client.ConnectToServer(TestConfig.UnderlyingTransport, server, shareIpAddr); client.Negotiate(TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled); client.SessionSetup(TestConfig.DefaultSecurityPackage, server, TestConfig.AccountCredential, false); Share_Capabilities_Values shareCaps = Share_Capabilities_Values.NONE; uint treeId; uint status = client.TreeConnect( sharePath, out treeId, (header, response) => { shareCaps = response.Capabilities; }, flags); if (status == Smb2Status.STATUS_SUCCESS) { client.TreeDisconnect(treeId); } client.LogOff(); client.Disconnect(); return(shareCaps); }
/// <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); }
private string GetShare(ShareFlags_Values shareFlags, Share_Capabilities_Values shareCap = Share_Capabilities_Values.NONE) { if (detectionInfo.shareInfo != null) { foreach (var item in detectionInfo.shareInfo) { ShareFlags_Values itemshareFlags = item.ShareFlags & shareFlags; Share_Capabilities_Values itemshareCap = item.ShareCapabilities & shareCap; if (item.ShareType == ShareType_Values.SHARE_TYPE_DISK && itemshareFlags == shareFlags && itemshareCap == shareCap) return item.ShareName; } } return string.Empty; }
private void TestAsymmetricShare(DialectRevision requestMaxDialect, string serverName, bool isAsymmetricShare) { int ret = 0; uint callId = 0; Guid clientGuid = Guid.NewGuid(); WITNESS_INTERFACE_INFO registerInterface; string shareName = isAsymmetricShare ? TestConfig.AsymmetricShare : TestConfig.BasicFileShare; #region Get the file server to access it through SMB2 IPAddress currentAccessIp = SWNTestUtility.GetCurrentAccessIP(serverName); BaseTestSite.Assert.IsNotNull(currentAccessIp, "IP address of the file server should NOT be empty"); BaseTestSite.Log.Add(LogEntryKind.Debug, "Got the IP {0} to access the file server", currentAccessIp.ToString()); #endregion #region Connect to the asymmetric share uncSharePath = Smb2Utility.GetUncPath(serverName, shareName); string content = Smb2Utility.CreateRandomString(TestConfig.WriteBufferLengthInKb); testDirectory = CreateTestDirectory(uncSharePath); string file = string.Format(@"{0}\{1}", testDirectory, Guid.NewGuid().ToString()); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start the client by sending the following requests: NEGOTIATE; SESSION_SETUP"); smb2Client = new Smb2FunctionalClient(TestConfig.FailoverTimeout, TestConfig, BaseTestSite); smb2Client.ConnectToServerOverTCP(currentAccessIp); smb2Client.Negotiate( Smb2Utility.GetDialects(requestMaxDialect), 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, "Negotiate should succeed."); BaseTestSite.Assert.AreEqual( requestMaxDialect, response.DialectRevision, "The server is expected to use dialect {0}. Actual dialect is {1}", requestMaxDialect, response.DialectRevision); }); smb2Client.SessionSetup( TestConfig.DefaultSecurityPackage, serverName, TestConfig.AccountCredential, TestConfig.UseServerGssToken); uint treeId = 0; Share_Capabilities_Values shareCapabilities = Share_Capabilities_Values.NONE; BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends TREE_CONNECT request to the {0} on the {1}", shareName, serverName); DoUntilSucceed( () => smb2Client.TreeConnect(uncSharePath, out treeId, (header, response) => { shareCapabilities = response.Capabilities; }), TestConfig.FailoverTimeout, "Retry TreeConnect until succeed within timeout span"); if (requestMaxDialect == DialectRevision.Smb302 && isAsymmetricShare) { BaseTestSite.Assert.IsTrue(shareCapabilities.HasFlag(Share_Capabilities_Values.SHARE_CAP_ASYMMETRIC), "The capabilities of the share should contain SHARE_CAP_ASYMMETRIC. The actual capabilities is {0}.", shareCapabilities); } else { BaseTestSite.Assert.IsFalse(shareCapabilities.HasFlag(Share_Capabilities_Values.SHARE_CAP_ASYMMETRIC), "The capabilities of the share should not contain SHARE_CAP_ASYMMETRIC. The actual capabilities is {0}.", shareCapabilities); #region Disconnect current SMB2 connection smb2Client.TreeDisconnect(treeId); smb2Client.LogOff(); smb2Client.Disconnect(); #endregion return; } FILEID fileId; Smb2CreateContextResponse[] serverCreateContexts; Guid createGuid = Guid.NewGuid(); Guid leaseKey = Guid.NewGuid(); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client writes to the file."); smb2Client.Create( treeId, file, CreateOptions_Values.FILE_NON_DIRECTORY_FILE | CreateOptions_Values.FILE_DELETE_ON_CLOSE, out fileId, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE); smb2Client.Write(treeId, fileId, content); string readContent; BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client reads from the file."); smb2Client.Read(treeId, fileId, 0, (uint)content.Length, out readContent); BaseTestSite.Assert.IsTrue( content.Equals(readContent), "Content read should be identical to that written."); #endregion #region Get register interface DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForInterface, currentAccessIp, TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage, TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout, serverName), TestConfig.FailoverTimeout, "Retry BindServer until succeed within timeout span"); WITNESS_INTERFACE_LIST interfaceList = new WITNESS_INTERFACE_LIST(); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client calls WitnessrGetInterfaceList."); DoUntilSucceed(() => { ret = swnClientForInterface.WitnessrGetInterfaceList(out interfaceList); BaseTestSite.Assert.AreEqual <SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrGetInterfaceList returns with result code = 0x{0:x8}", ret); return(SWNTestUtility.VerifyInterfaceList(interfaceList, TestConfig.Platform)); }, TestConfig.FailoverTimeout, "Retry to call WitnessrGetInterfaceList until succeed within timeout span"); swnClientForInterface.SwnUnbind(TestConfig.Timeout); SWNTestUtility.GetRegisterInterface(interfaceList, out registerInterface); #endregion #region Get SHARE_MOVE_NOTIFICATION DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForWitness, (registerInterface.Flags & (uint)SwnNodeFlagsValue.IPv4) != 0 ? new IPAddress(registerInterface.IPV4) : SWNTestUtility.ConvertIPV6(registerInterface.IPV6), TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage, TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout, serverName), TestConfig.FailoverTimeout, "Retry BindServer until succeed within timeout span"); string clientName = TestConfig.WitnessClientName; BaseTestSite.Log.Add(LogEntryKind.Debug, "Register witness:"); BaseTestSite.Log.Add(LogEntryKind.Debug, "\tNetName: {0}", serverName); BaseTestSite.Log.Add(LogEntryKind.Debug, "\tIPAddress: {0}", currentAccessIp.ToString()); BaseTestSite.Log.Add(LogEntryKind.Debug, "\tClient Name: {0}", clientName); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client calls WitnessrRegisterEx."); ret = swnClientForWitness.WitnessrRegisterEx(SwnVersion.SWN_VERSION_2, serverName, shareName, currentAccessIp.ToString(), clientName, WitnessrRegisterExFlagsValue.WITNESS_REGISTER_IP_NOTIFICATION, 120, out pContext); BaseTestSite.Assert.AreEqual <SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrRegisterEx returns with result code = 0x{0:x8}", ret); BaseTestSite.Assert.IsNotNull(pContext, "Expect pContext is not null."); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client calls WitnessrAsyncNotify."); callId = swnClientForWitness.WitnessrAsyncNotify(pContext); BaseTestSite.Assert.AreNotEqual <uint>(0, callId, "WitnessrAsyncNotify returns callId = {0}", callId); // NOTICE // This comment is for current Windows Cluster test environment. // Current test environment has only two nodes and both they are optimum nodes. // So whatever the server name is, SHARE_MOVE_NOTIFICATION notification will be recieved. // The configuration items 'OptimumNodeOfAsymmetricShare' and 'NonOptimumNodeOfAsymmetricShare' are assigned the same default value. // The code in if block will be executed all the time. if (serverName == TestConfig.NonOptimumNodeOfAsymmetricShare) { #region Expect that SHARE_MOVE_NOTIFICATION notification will be received when the client connects to the asymmetric share on the non-optimum share RESP_ASYNC_NOTIFY respNotify; ret = swnClientForWitness.ExpectWitnessrAsyncNotify(callId, out respNotify); BaseTestSite.Assert.AreEqual <SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrAsyncNotify returns with result code = 0x{0:x8}", ret); SWNTestUtility.PrintNotification(respNotify); SWNTestUtility.VerifyClientMoveShareMoveAndIpChange(respNotify, SwnMessageType.SHARE_MOVE_NOTIFICATION, (uint)SwnIPAddrInfoFlags.IPADDR_V4, TestConfig.Platform); #region Get the new IpAddr IPADDR_INFO_LIST ipAddrInfoList; SwnUtility.ParseIPAddrInfoList(respNotify, out ipAddrInfoList); currentAccessIp = (ipAddrInfoList.IPAddrList[0].Flags & (uint)SwnNodeFlagsValue.IPv4) != 0 ? new IPAddress(ipAddrInfoList.IPAddrList[0].IPV4) : SWNTestUtility.ConvertIPV6(ipAddrInfoList.IPAddrList[0].IPV6); #endregion #region Unregister SWN Witness BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client calls WitnessrUnRegister."); ret = swnClientForWitness.WitnessrUnRegister(pContext); BaseTestSite.Assert.AreEqual <SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrUnRegister returns with result code = 0x{0:x8}", ret); pContext = IntPtr.Zero; swnClientForWitness.SwnUnbind(TestConfig.Timeout); #endregion #region Disconnect current SMB2 connection BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the client by sending the following requests: TREE_DISCONNECT; LOG_OFF; DISCONNECT."); smb2Client.TreeDisconnect(treeId); smb2Client.LogOff(); smb2Client.Disconnect(); #endregion #endregion } else { #region Expect that no SHARE_MOVE_NOTIFICATION notification will be received when the client connects to the asymmetric share on the optimum share bool isNotificationReceived = false; try { RESP_ASYNC_NOTIFY respNotify; ret = swnClientForWitness.ExpectWitnessrAsyncNotify(callId, out respNotify); isNotificationReceived = true; } catch (TimeoutException) { isNotificationReceived = false; } #region Disconnect current SMB2 connection BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the second client by sending the following requests: TREE_DISCONNECT; LOG_OFF; DISCONNECT"); smb2Client.TreeDisconnect(treeId); smb2Client.LogOff(); smb2Client.Disconnect(); #endregion #region Unregister SWN Witness BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client calls WitnessrUnRegister."); ret = swnClientForWitness.WitnessrUnRegister(pContext); BaseTestSite.Assert.AreEqual <SwnErrorCode>(SwnErrorCode.ERROR_SUCCESS, (SwnErrorCode)ret, "WitnessrUnRegister returns with result code = 0x{0:x8}", ret); pContext = IntPtr.Zero; swnClientForWitness.SwnUnbind(TestConfig.Timeout); #endregion BaseTestSite.Assert.IsFalse(isNotificationReceived, "Expect that no notification will be received when the client has connected to asymmetric share on the optimum node."); #endregion return; } #endregion #region Connect to the share on the optimum node smb2Client = new Smb2FunctionalClient(TestConfig.FailoverTimeout, TestConfig, BaseTestSite); BaseTestSite.Log.Add( LogEntryKind.TestStep, "Got the IP {0} to access the file server", currentAccessIp.ToString()); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start a client by sending the following requests: NEGOTIATE; SESSION_SETUP"); smb2Client.ConnectToServerOverTCP(currentAccessIp); smb2Client.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: Guid.NewGuid(), checker: (Packet_Header header, NEGOTIATE_Response response) => { BaseTestSite.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, header.Status, "Negotiate should succeed."); }); smb2Client.SessionSetup( TestConfig.DefaultSecurityPackage, serverName, TestConfig.AccountCredential, TestConfig.UseServerGssToken); BaseTestSite.Log.Add( LogEntryKind.TestStep, "Client sends TREE_CONNECT and wait for a response until timeout."); DoUntilSucceed( () => smb2Client.TreeConnect(uncSharePath, out treeId, (header, response) => { }), TestConfig.FailoverTimeout, "Retry TreeConnect until succeed within timeout span"); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client writes to the file."); smb2Client.Create( treeId, file, CreateOptions_Values.FILE_NON_DIRECTORY_FILE | CreateOptions_Values.FILE_DELETE_ON_CLOSE, out fileId, out serverCreateContexts, RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE); smb2Client.Write(treeId, fileId, content); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client reads from the file."); smb2Client.Read(treeId, fileId, 0, (uint)content.Length, out readContent); BaseTestSite.Assert.IsTrue( content.Equals(readContent), "Content read should be identical to that written."); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the client by sending the following requests: TREE_DISCONNECT; LOG_OFF; DISCONNECT."); smb2Client.TreeDisconnect(treeId); smb2Client.LogOff(); smb2Client.Disconnect(); #endregion }
/// <summary> /// Verify behavior of redirect to owner specified in MS-SMB2 section 3.3.5.7 /// </summary> /// <param name="sofsHostedNode">ScaleOutFS hosted node</param> /// <param name="nonSofsHostedNode">Non ScaleOutFS hosted node</param> /// <returns>Redirect to owner is tested or not</returns> private bool TestRedirectToOwner(string sofsHostedNode, string nonSofsHostedNode) { bool isRedirectToOwnerTested = false; #region Get IP address list from ScaleOutFS string server = TestConfig.ClusteredScaleOutFileServerName; IPAddress[] accessIpList = Dns.GetHostEntry(server).AddressList; #endregion #region Get IP address from nonSofsHostedNode IPAddress currentAccessIpAddr = null; IPAddress[] accessIpListNonSoftHosted = Dns.GetHostEntry(nonSofsHostedNode).AddressList; for (int i = 0; i < accessIpList.Length; i++) { for (int j = 0; j < accessIpListNonSoftHosted.Length; j++) { // Make sure to get IP address from nonSofsHostedNode if (accessIpList[i].Address.Equals(accessIpListNonSoftHosted[j].Address)) { currentAccessIpAddr = accessIpList[i]; break; } } } BaseTestSite.Assert.IsNotNull( currentAccessIpAddr, "currentAccessIpAddr should be set as IP of nonSofsHostedNode {0}", nonSofsHostedNode); #endregion BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start a client by sending the following requests: NEGOTIATE; SESSION_SETUP"); Smb2FunctionalClient client = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite); client.ConnectToServer(TestConfig.UnderlyingTransport, server, currentAccessIpAddr); client.Negotiate(TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled); client.SessionSetup(TestConfig.DefaultSecurityPackage, server, TestConfig.AccountCredential, false); BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends TREE_CONNECT request with flag SMB2_SHAREFLAG_REDIRECT_TO_OWNER."); string uncSharePath = Smb2Utility.GetUncPath(server, testConfig.CAShareName); uint treeId; Share_Capabilities_Values shareCap = Share_Capabilities_Values.NONE; uint status = client.TreeConnect( uncSharePath, out treeId, (header, response) => { if (header.Status == Smb2Status.STATUS_SUCCESS) { shareCap = response.Capabilities; } }, TreeConnect_Flags.SMB2_SHAREFLAG_REDIRECT_TO_OWNER); if (status != Smb2Status.STATUS_SUCCESS && client.Smb2Client.Error != null) { ERROR_Response_packet error = client.Smb2Client.Error.PayLoad; if (error.ErrorContextCount > 0) { for (int i = 0; i < error.ErrorContextCount; i++) { Error_Context ctx = error.ErrorContextErrorData[i]; if (ctx.ErrorId == Error_Id.ERROR_ID_SHARE_REDIRECT) { Share_Capabilities_Values shareCaps = GetShareCapabilities(sofsHostedNode, uncSharePath, TreeConnect_Flags.SMB2_SHAREFLAG_REDIRECT_TO_OWNER); if (!shareCaps.HasFlag(Share_Capabilities_Values.SHARE_CAP_REDIRECT_TO_OWNER)) { BaseTestSite.Assert.Inconclusive( "The share {0} does not have the capability SHARE_CAP_REDIRECT_TO_OWNER", Smb2Utility.GetUncPath(TestConfig.ClusteredScaleOutFileServerName, testConfig.CAShareName) ); } BaseTestSite.Assert.AreEqual( Smb2Status.STATUS_BAD_NETWORK_NAME, status, "If TreeConnect.Share.Type includes STYPE_CLUSTER_SOFS," + "Connection.Dialect is \"3.1.1\" and" + "the SMB2_TREE_CONNECT_FLAG_REDIRECT_TO_OWNER bit is set" + "in the Flags field of the SMB2 TREE_CONNECT request," + "the server MUST query the underlying object store in an implementation-specific manner " + "to determine whether the share is hosted on this node." + "If not, the server MUST return error data as specified in section 2.2.2" + "with ErrorData set to SMB2 ERROR Context response formatted as ErrorId" + "set to SMB2_ERROR_ID_SHARE_REDIRECT, and ErrorContextData set to the Share Redirect error context data" + "as specified in section 2.2.2.2.2 with IPAddrMoveList set to" + "the list of IP addresses obtained in an implementation-specific manner." + "Actually server returns {0}.", Smb2Status.GetStatusCode(status) ); verifyErrorContext(ctx, uncSharePath, sofsHostedNode); isRedirectToOwnerTested = true; } } } } if (status == Smb2Status.STATUS_SUCCESS) { if (!shareCap.HasFlag(Share_Capabilities_Values.SHARE_CAP_REDIRECT_TO_OWNER)) { BaseTestSite.Assert.Inconclusive( "The share {0} does not have the capability SHARE_CAP_REDIRECT_TO_OWNER", Smb2Utility.GetUncPath(TestConfig.ClusteredScaleOutFileServerName, testConfig.CAShareName) ); } client.TreeDisconnect(treeId); } BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the client by sending the following requests: LOG_OFF; DISCONNECT."); client.LogOff(); client.Disconnect(); return(isRedirectToOwnerTested); }