protected override void TestCleanup()
        {
            if (mainChannelClient != null)
            {
                try
                {
                    mainChannelClient.Disconnect();
                }
                catch (Exception ex)
                {
                    BaseTestSite.Log.Add(
                        LogEntryKind.Debug,
                        "Unexpected exception when disconnecting client: {0}", ex.ToString());
                }
            }

            if (mainChannelClient != null)
            {
                try
                {
                    alternativeChannelClient.Disconnect();
                }
                catch (Exception ex)
                {
                    BaseTestSite.Log.Add(
                        LogEntryKind.Debug,
                        "Unexpected exception when disconnecting client: {0}", ex.ToString());
                }
            }

            base.TestCleanup();
        }
        protected override void TestCleanup()
        {
            if (clientBeforeDisconnection != null)
            {
                try
                {
                    clientBeforeDisconnection.Disconnect();
                }
                catch (Exception ex)
                {
                    BaseTestSite.Log.Add(LogEntryKind.Debug, "Unexpected exception when disconnect clientBeforeFailover: {0}", ex.ToString());
                }
            }

            if (fileName != null)
            {
                try
                {
                    sutProtocolController.DeleteFile(durableHandleUncSharePath, fileName);
                }
                catch (Exception ex)
                {
                    BaseTestSite.Log.Add(LogEntryKind.Debug, "Unexpected exception when delete file: {0}", ex.ToString());
                }
            }

            base.TestCleanup();
        }
Пример #3
0
 protected override void TestCleanup()
 {
     if (client != null)
     {
         client.Disconnect();
     }
     base.TestCleanup();
 }
        private bool ConnectToShare(string uncSharePath, out uint treeId)
        {
            treeId = 0;

            string serverName = Smb2Utility.GetServerName(uncSharePath);
            var    serverIPs  = Dns.GetHostEntry(serverName).AddressList;

            if (serverIPs == null || serverIPs.Length == 0)
            {
                return(false);
            }

            uint status = 0;

            foreach (var ip in serverIPs) // Try to connect to each IP since not all of them can be connected successfully.
            {
                try
                {
                    client = new Smb2FunctionalClient(testConfig.Timeout, testConfig, Site);
                    client.ConnectToServer(Smb2TransportType.Tcp, serverName, ip);
                    status = client.Negotiate(
                        Smb2Utility.GetDialects(testConfig.MaxSmbVersionSupported),
                        true,
                        checker: (header, response) => { });
                    if (status != Smb2Status.STATUS_SUCCESS)
                    {
                        continue;
                    }

                    status = client.SessionSetup(testConfig.DefaultSecurityPackage, serverName, testConfig.AccountCredential, false, checker: (header, response) => { });
                    if (status != Smb2Status.STATUS_SUCCESS)
                    {
                        client.Disconnect();
                        continue;
                    }

                    status = client.TreeConnect(uncSharePath, out treeId, checker: (header, response) => { });
                    if (status == Smb2Status.STATUS_SUCCESS)
                    {
                        return(true);
                    }
                    else
                    {
                        client.LogOff();
                        client.Disconnect();
                    }
                }
                catch
                {
                    // Catch the exceptions thrown in Negotiage/SessionSetup/TreeConnect
                    // Try next IP
                }
            }

            return(false);
        }
        public override void Reset()
        {
            base.Reset();

            if (testClient != null)
            {
                testClient.Disconnect();
                testClient = null;
            }
        }
Пример #6
0
 protected override void TestCleanup()
 {
     if (mainChannelClient != null)
     {
         mainChannelClient.Disconnect();
     }
     if (alternativeChannelClient != null)
     {
         alternativeChannelClient.Disconnect();
     }
     base.TestCleanup();
 }
Пример #7
0
 protected override void TestCleanup()
 {
     if (clientBeforeDisconnection != null)
     {
         clientBeforeDisconnection.Disconnect();
     }
     if (clientAfterDisconnection != null)
     {
         clientAfterDisconnection.Disconnect();
     }
     sutProtocolController.DeleteFile(sharePath, fileName);
     base.TestCleanup();
 }
        public override void Reset()
        {
            if (prepareOpenClient != null)
            {
                prepareOpenClient.Disconnect();
            }
            if (reconnectClient != null)
            {
                reconnectClient.Disconnect();
            }

            base.Reset();
        }
Пример #9
0
        protected override void TestCleanup()
        {
            if (clientBeforeDisconnection != null)
            {
                clientBeforeDisconnection.Disconnect();
            }
            if (clientAfterDisconnection != null)
            {
                clientAfterDisconnection.Disconnect();
            }

            base.TestCleanup();
        }
Пример #10
0
        public override void Reset()
        {
            if (prepareOpenClient != null)
            {
                prepareOpenClient.Disconnect();
            }
            if (reconnectClient != null)
            {
                reconnectClient.Disconnect();
            }

            // delete created file
            File.Delete(string.Format("\\\\{0}\\{1}\\{2}", testConfig.SutComputerName, testConfig.BasicFileShare, fileName));

            base.Reset();
        }
        public override void Reset()
        {
            if (prepareClient != null)
            {
                prepareClient.Disconnect();
                prepareClient = null;
            }

            try
            {
                sutProtocolController.DeleteFile(Smb2Utility.GetUncPath(testConfig.SutComputerName, testConfig.BasicFileShare), fileName);
                if (cleanFileWithDifferentName)
                {
                    sutProtocolController.DeleteFile(Smb2Utility.GetUncPath(testConfig.SutComputerName, testConfig.BasicFileShare), fileName + different);
                }
                if (cleanFileInDifferentShare)
                {
                    sutProtocolController.DeleteFile(Smb2Utility.GetUncPath(testConfig.SutComputerName, testConfig.DifferentFromSMBBasic), fileName);
                }
            }
            catch
            {
            }

            cleanFileWithDifferentName = false;
            cleanFileInDifferentShare  = false;

            base.Reset();
        }
Пример #12
0
        protected void CreateNewFile(string sharePath, string fileName)
        {
            Smb2FunctionalClient clientAdmin;

            clientAdmin = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            clientAdmin.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress);
            uint treeId;

            ConnectToShare(clientAdmin, TestConfig.AccountCredential, sharePath, out treeId);

            FILEID fileId;

            Smb2CreateContextResponse[] createContextResponses;
            clientAdmin.Create(
                treeId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileId,
                out createContextResponses,
                accessMask: AccessMask.FILE_READ_DATA | AccessMask.FILE_WRITE_DATA |
                AccessMask.FILE_APPEND_DATA | AccessMask.FILE_READ_EA |
                AccessMask.FILE_WRITE_EA | AccessMask.READ_CONTROL |
                AccessMask.WRITE_DAC | AccessMask.FILE_READ_ATTRIBUTES |
                AccessMask.FILE_WRITE_ATTRIBUTES | AccessMask.SYNCHRONIZE,
                shareAccess: ShareAccess_Values.NONE,
                createDisposition: CreateDisposition_Values.FILE_CREATE);
            clientAdmin.Close(treeId, fileId);
            clientAdmin.TreeDisconnect(treeId);
            clientAdmin.Disconnect();
        }
Пример #13
0
        protected void DeleteExistingFile(string sharePath, string fileName)
        {
            Smb2FunctionalClient clientAdmin;

            clientAdmin = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            clientAdmin.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress);
            uint treeId;

            ConnectToShare(clientAdmin, TestConfig.AccountCredential, sharePath, out treeId);

            FILEID fileId;

            Smb2CreateContextResponse[] createContextResponses;
            clientAdmin.Create(
                treeId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE | CreateOptions_Values.FILE_DELETE_ON_CLOSE,
                out fileId,
                out createContextResponses,
                accessMask: AccessMask.FILE_READ_ATTRIBUTES | AccessMask.DELETE,
                shareAccess: ShareAccess_Values.FILE_SHARE_DELETE,
                createDisposition: CreateDisposition_Values.FILE_OPEN);
            clientAdmin.Close(treeId, fileId);
            clientAdmin.TreeDisconnect(treeId);
            clientAdmin.Disconnect();
        }
        public override void Reset()
        {
            if (testClientBeforeDisconnection != null)
            {
                testClientBeforeDisconnection.Disconnect();
            }

            if (testClientAfterDisconnection != null)
            {
                testClientAfterDisconnection.Disconnect();
            }

            fileIdBeforDisconnection = FILEID.Zero;

            base.Reset();
        }
        protected override void TestCleanup()
        {
            #region Tear Down Clients

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the first client by sending the following requests: 1. CLOSE; 2. TREE_DISCONNECT; 3. LOG_OFF");
            TearDownClient(client1, client1TreeId, client1FileId);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the second client by sending the following requests: 1. CLOSE; 2. TREE_DISCONNECT; 3. LOG_OFF");
            TearDownClient(client2, client2TreeId, client2FileId);

            #endregion

            if (client1 != null)
            {
                client1.Disconnect();
            }
            if (client2 != null)
            {
                client2.Disconnect();
            }

            base.TestCleanup();

            fsaAdapter.Dispose();
            base.TestCleanup();
            CleanupTestManager();
        }
        public void SessionMgmt_ReconnectWithDifferentDialect()
        {
            Guid clientGuid = Guid.NewGuid();

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start a first client by sending NEGOTIATE request.");
            client.Negotiate(TestConfig.RequestDialects,
                             TestConfig.IsSMB1NegotiateEnabled,
                             SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                             null, // capability value will be set inside the method according to requested dialects.
                             clientGuid);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "The first client sends SESSION_SETUP request with SESSION_ID set to ZERO.");
            client.SessionSetup(TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken);

            #region Reconnect and Do Session Setup with PreviousSessionId set.
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start a second client by sending NEGOTIATE request.");
            Smb2FunctionalClient client2 = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            client2.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress);
            // Select different dialects
            List <DialectRevision> newRequestDialects = new List <DialectRevision>();
            foreach (DialectRevision dialect in TestConfig.RequestDialects)
            {
                if (dialect != client.Dialect)
                {
                    newRequestDialects.Add(dialect);
                }
            }

            client2.Negotiate(newRequestDialects.ToArray(),
                              TestConfig.IsSMB1NegotiateEnabled,
                              SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                              null, // capability value will be set inside the method according to requested dialects.
                              clientGuid);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "The second client sends SESSION_SETUP request with SESSION_ID set to the value in the previous SESSION_SETUP response.");
            client2.ReconnectSessionSetup(
                client,
                TestConfig.DefaultSecurityPackage,
                TestConfig.SutComputerName,
                TestConfig.AccountCredential,
                false,
                SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                SESSION_SETUP_Request_Capabilities_Values.GLOBAL_CAP_DFS,
                checker: (Packet_Header header, SESSION_SETUP_Response response) =>
            {
                BaseTestSite.Assert.AreEqual(
                    Smb2Status.STATUS_USER_SESSION_DELETED,
                    header.Status,
                    "[MS-SMB2] 3.3.5.5.3 the server MUST look up a client entry in GlobalClientTable using Session.Connection.ClientGuid. " +
                    "If an entry is found and Client.Dialect is not equal to Session.Connection.Dialect, the server MUST close the newly created Session, as specified in section 3.3.4.12, " +
                    "by providing Session.SessionGlobalId as the input parameter, and fail the session setup request with STATUS_USER_SESSION_DELETED.");
            });
            #endregion

            #region Tear Down Client
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Disconnect both clients by sending DISCONNECT request.");
            client.Disconnect();
            client2.Disconnect();
            #endregion
        }
        protected override void TestCleanup()
        {
            if (clientForInitialOpen != null)
            {
                try
                {
                    clientForInitialOpen.Disconnect();
                }
                catch (Exception ex)
                {
                    BaseTestSite.Log.Add(LogEntryKind.Debug, "Unexpected exception when disconnect clientBeforeFailover: {0}", ex.ToString());
                }
            }

            if (clientForReOpen != null)
            {
                try
                {
                    clientForReOpen.Disconnect();
                }
                catch (Exception ex)
                {
                    BaseTestSite.Log.Add(LogEntryKind.Debug, "Unexpected exception when disconnect clientAfterFailover: {0}", ex.ToString());
                }
            }

            base.TestCleanup();
        }
Пример #18
0
        protected override void TestCleanup()
        {
            if (client1 != null)
            {
                try
                {
                    client1.Disconnect();
                }
                catch (Exception ex)
                {
                    BaseTestSite.Log.Add(LogEntryKind.Debug, "Unexpected exception when disconnect client1: {0}", ex.ToString());
                }
            }

            if (client2 != null)
            {
                try
                {
                    client2.Disconnect();
                }
                catch (Exception ex)
                {
                    BaseTestSite.Log.Add(LogEntryKind.Debug, "Unexpected exception when disconnect client2: {0}", ex.ToString());
                }
            }

            base.TestCleanup();
        }
        public void PrepareOpen(
            ModelDialectRevision dialect,
            AppInstanceIdType appInstanceIdType,
            CreateType createType)
        {
            // Connect, Negotiate, SessionSetup, TreeConnect
            prepareClient = new Smb2FunctionalClient(testConfig.Timeout, testConfig, this.Site);
            this.connection_ClientGuid = Guid.NewGuid();
            clientDialect = dialect;
            ConnectToShare(clientDialect, prepareClient, connection_ClientGuid, testConfig.BasicFileShare, out treeConnect_TreeId);

            // Create
            this.fileName = GetTestFileName(Smb2Utility.GetUncPath(testConfig.SutComputerName, testConfig.BasicFileShare));
            Smb2CreateContextResponse[] createContextResponse;

            prepareClient.Create(
                this.treeConnect_TreeId,
                this.fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out this.open_FileId,
                out createContextResponse,
                createContexts: CreateContexts(appInstanceIdType, createType, true),
                shareAccess: ShareAccess_Values.NONE);

            if (createType == CreateType.CreateDurableThenDisconnect)
            {
                prepareClient.Disconnect();
            }
        }
        protected override void TestCleanup()
        {
            if (client != null)
            {
                try
                {
                    client.Disconnect();
                }
                catch (Exception ex)
                {
                    BaseTestSite.Log.Add(
                        LogEntryKind.Debug,
                        "Unexpected exception when disconnect client: {0}", ex.ToString());
                }
            }

            if (fileName != null)
            {
                try
                {
                    sutProtocolController.DeleteFile(Smb2Utility.GetUncPath(testConfig.SutComputerName, testConfig.BasicFileShare), fileName);
                }
                catch (Exception)
                {
                }
            }

            base.TestCleanup();
        }
Пример #21
0
        public override void Reset()
        {
            if (testClient != null)
            {
                try
                {
                    testClient.Close(treeId, fileId);
                    testClient.TreeDisconnect(treeId);
                    testClient.LogOff();

                    testClient.Disconnect();
                }
                catch
                {
                }
                finally
                {
                    testClient = null;
                }
            }

            try
            {
                sutProtocolController.DeleteFile(uncSharePath, fileName);
            }
            catch
            {
            }

            base.Reset();
        }
        protected override void TestCleanup()
        {
            if (clientForInitialOpen != null)
            {
                try
                {
                    clientForInitialOpen.Disconnect();
                }
                catch (Exception ex)
                {
                    BaseTestSite.Log.Add(LogEntryKind.Debug, "Unexpected exception when disconnect clientBeforeFailover: {0}", ex.ToString());
                }
            }

            if (clientForReOpen != null)
            {
                try
                {
                    clientForReOpen.Disconnect();
                }
                catch (Exception ex)
                {
                    BaseTestSite.Log.Add(LogEntryKind.Debug, "Unexpected exception when disconnect clientAfterFailover: {0}", ex.ToString());
                }
            }

            sutProtocolController.DeleteFile(sharePath, fileName);
            base.TestCleanup();
        }
Пример #23
0
        protected _SECURITY_DESCRIPTOR QuerySecurityDescriptor(string sharePath, string fileName, AdditionalInformation_Values securityAttributesToQuery)
        {
            Smb2FunctionalClient clientAdmin;

            clientAdmin = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            clientAdmin.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress);
            uint treeId;

            ConnectToShare(clientAdmin, TestConfig.AccountCredential, sharePath, out treeId);

            FILEID fileId;

            Smb2CreateContextResponse[] createContextResponses;
            clientAdmin.Create(treeId,
                               fileName,
                               fileName == null ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                               out fileId,
                               out createContextResponses,
                               accessMask: AccessMask.READ_CONTROL | AccessMask.WRITE_DAC | AccessMask.FILE_READ_ATTRIBUTES,
                               shareAccess: ShareAccess_Values.FILE_SHARE_DELETE | ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE,
                               createDisposition: CreateDisposition_Values.FILE_OPEN);
            _SECURITY_DESCRIPTOR sd;

            clientAdmin.QuerySecurityDescriptor(treeId, fileId, securityAttributesToQuery, out sd);
            clientAdmin.Close(treeId, fileId);
            clientAdmin.TreeDisconnect(treeId);
            clientAdmin.LogOff();
            clientAdmin.Disconnect();
            return(sd);
        }
Пример #24
0
        /// <summary>
        /// Determine if a share has shi*_type set to STYPE_CLUSTER_SOFS
        /// </summary>
        /// <param name="server">Server of the share</param>
        /// <param name="sharePath">Path of the share</param>
        /// <returns>Return true if share has shi*_type set to STYPE_CLUSTER_SOFS, otherwise return false</returns>
        private bool ShareContainsSofs(string server, string sharePath)
        {
            Smb2FunctionalClient client = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);

            client.ConnectToServerOverTCP(SWNTestUtility.GetCurrentAccessIP(server));

            client.Negotiate(TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled);

            client.SessionSetup(TestConfig.DefaultSecurityPackage, server, TestConfig.AccountCredential, false);

            uint treeId;
            bool ret = false;

            client.TreeConnect(sharePath, out treeId,
                               (header, response) =>
            {
                BaseTestSite.Assert.AreEqual(
                    Smb2Status.STATUS_SUCCESS,
                    header.Status,
                    "{0} should be successful.", header.Command);

                ret = response.Capabilities.HasFlag(Share_Capabilities_Values.SHARE_CAP_SCALEOUT);
            });

            client.TreeDisconnect(treeId);

            client.LogOff();

            client.Disconnect();

            return(ret);
        }
Пример #25
0
        /// <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);
        }
Пример #26
0
 protected override void TestCleanup()
 {
     client?.Disconnect();
     if (FilePermissionTestShareUncPath != null)
     {
         DeleteExistingFile(FilePermissionTestShareUncPath, tempFileName);
     }
     base.TestCleanup();
 }
        public override void Reset()
        {
            if (smb2ClientMainChannel != null)
            {
                smb2ClientMainChannel.Disconnect();
                smb2ClientMainChannel = null;
            }

            if (smb2ClientAlternativeChannel != null)
            {
                smb2ClientAlternativeChannel.Disconnect();
                smb2ClientAlternativeChannel = null;
            }

            Initialize();

            base.Reset();
        }
        public void ResilientOpenScavengerTimer_ReconnectBeforeTimeout()
        {
            /// 1. Open Resilient Handle with specific timeout.
            /// 2. Disconnect to start the Resilient Timer.
            /// 3. Wait for specific timeout - 1 seconds.
            /// 4. Reconnect the resilient handle and expect the result is success.
            #region Check Applicability
            TestConfig.CheckDialect(DialectRevision.Smb21);
            TestConfig.CheckIOCTL(CtlCode_Values.FSCTL_LMR_REQUEST_RESILIENCY);
            TestConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_RECONNECT);
            #endregion

            Smb2FunctionalClient prepareClient = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);

            uint   timeoutInSecond = testConfig.MaxResiliencyTimeoutInSecond / 2;
            Guid   clientGuid      = Guid.NewGuid();
            string fileName        = "ResilientHandle_" + Guid.NewGuid() + ".txt";
            FILEID fileId;

            // Open file & Resiliency request
            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Create resilient handle to file '{0}' and timeout is {1} seconds", fileName, timeoutInSecond);
            OpenFileAndResilientRequest(
                prepareClient,
                clientGuid,
                fileName,
                timeoutInSecond * 1000, // convert second to millisecond
                out fileId);

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Disconnect the client to start the Resilient Open Scavenger Timer on server");
            prepareClient.Disconnect();

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Wait {0} seconds before Resilient Open Scavenger Timer expired.", timeoutInSecond - 1);
            Thread.Sleep(TimeSpan.FromSeconds(timeoutInSecond - 1));

            Smb2FunctionalClient reconnectClient = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Re-establish Resilient Open, verify the returned status is STATUS_SUCCESS.");
            ReconnectResilientHandle(
                reconnectClient,
                clientGuid,
                fileName,
                fileId,
                NtStatus.STATUS_SUCCESS,
                "Reconnect resilient handle should be successful.");

            // clean
            reconnectClient.Disconnect();
        }
Пример #29
0
        public override void Reset()
        {
            if (testClientBeforeDisconnection != null)
            {
                testClientBeforeDisconnection.Disconnect();
            }

            if (testClientAfterDisconnection != null)
            {
                testClientAfterDisconnection.Disconnect();
            }

            fileIdBeforDisconnection = FILEID.Zero;

            // Add test file to collection, to delete it in Reset() of base;
            AddTestFileName(sharePath, fileName);

            base.Reset();
        }
 private void DisconnectToShare(uint treeId, FILEID fileId)
 {
     if (fileId.Persistent != 0 || fileId.Volatile != 0)
     {
         client.Close(treeId, fileId);
     }
     client.TreeDisconnect(treeId);
     client.LogOff();
     client.Disconnect();
 }
        /// <summary>
        /// Determine if a share has shi*_type set to STYPE_CLUSTER_SOFS
        /// </summary>
        /// <param name="server">Server of the share</param>
        /// <param name="sharePath">Path of the share</param>
        /// <returns>Return true if share has shi*_type set to STYPE_CLUSTER_SOFS, otherwise return false</returns>
        private bool ShareContainsSofs(string server, string sharePath)
        {
            Smb2FunctionalClient client = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);

            client.ConnectToServerOverTCP(SWNTestUtility.GetCurrentAccessIP(server));

            client.Negotiate(TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled);

            client.SessionSetup(TestConfig.DefaultSecurityPackage, server, TestConfig.AccountCredential, false);

            uint treeId;
            bool ret = false;
            client.TreeConnect(sharePath, out treeId,
                (header, response) =>
                {
                    BaseTestSite.Assert.AreEqual(
                        Smb2Status.STATUS_SUCCESS,
                        header.Status,
                        "{0} should be successful.", header.Command);

                    ret = response.Capabilities.HasFlag(Share_Capabilities_Values.SHARE_CAP_SCALEOUT);
                });

            client.TreeDisconnect(treeId);

            client.LogOff();

            client.Disconnect();

            return ret;
        }
        public void BVT_MultiCredit_OneRequestWithMultiCredit()
        {
            TestConfig.CheckDialect(DialectRevision.Smb21);
            TestConfig.CheckCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LARGE_MTU);

            Guid clientGuid = Guid.NewGuid();
            string fileName = "MultiCredit_" + clientGuid.ToString() + ".txt";

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start a client by sending the following requests: 1. NEGOTIATE; 2. SESSION_SETUP; 3. TREE_CONNECT");
            Smb2FunctionalClient client = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            client.ConnectToServerOverTCP(TestConfig.SutIPAddress);
            Capabilities_Values clientCapabilities = Capabilities_Values.GLOBAL_CAP_LARGE_MTU;
            client.Negotiate(
                TestConfig.RequestDialects,
                TestConfig.IsSMB1NegotiateEnabled,
                capabilityValue: clientCapabilities);
            client.SessionSetup(
                TestConfig.DefaultSecurityPackage,
                TestConfig.SutComputerName,
                TestConfig.AccountCredential,
                TestConfig.UseServerGssToken);
            uint treeId;
            client.TreeConnect(uncSharePath, out treeId);

            int bufferSize = (int)client.MaxBufferSize;
            FILEID fileId;
            Smb2CreateContextResponse[] serverCreateContexts;
            ushort grantedCredit = 0;
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends CREATE request with {0} credits", client.Credits);
            client.Create(
                treeId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileId,
                out serverCreateContexts,
                checker: (header, response) =>
                {
                    BaseTestSite.Assert.AreEqual(
                        Smb2Status.STATUS_SUCCESS,
                        header.Status,
                        "{0} should succeed, actually server returns {1}.", header.Command, Smb2Status.GetStatusCode(header.Status));

                    BaseTestSite.Log.Add(LogEntryKind.Debug,
                        "The MaxBufferSize of the server is {0}.",
                        client.MaxBufferSize);
                    BaseTestSite.Log.Add(LogEntryKind.Debug,
                        "Server has granted {0} credits to the client.",
                        client.Credits);

                    // Make sure client hold enough credits for test
                    ushort maxBufferSizeInCredit = (ushort)((client.MaxBufferSize -1)/ 65536 + 1);
                    if (client.Credits < maxBufferSizeInCredit)
                    {
                        if (client.Credits < 2)
                        {
                            BaseTestSite.Assert.Inconclusive(
                                "This test case is not applicable when the server only grants {0} credits",
                                client.Credits);
                        }
                        // Test max buffer according to granted credits.
                        bufferSize = (client.Credits - 1) * 65536;
                    }

                    grantedCredit = header.CreditRequestResponse;
                });

            contentWrite = Smb2Utility.CreateRandomStringInByte(bufferSize);

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Client attempts to write {0} bytes content to file when server grants {1} credits",
                client.MaxBufferSize, client.Credits);

            client.Write(
                treeId,
                fileId,
                contentWrite,
                checker: (header, response) =>
                {
                    BaseTestSite.Assert.AreEqual(
                        Smb2Status.STATUS_SUCCESS,
                        header.Status,
                        "{0} should succeed, actually server returns {1}.", header.Command, Smb2Status.GetStatusCode(header.Status));

                    grantedCredit = header.CreditRequestResponse;
                });

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Client attempts to read {0} bytes content from file when server grants {1} credit",
                bufferSize, client.Credits);
            client.Read(treeId, fileId, 0, (uint)contentWrite.Length, out contentRead);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the client by sending the following requests: 1. CLOSE; 2. TREE_DISCONNECT; 3. LOG_OFF; 4. DISCONNECT");
            client.Close(treeId, fileId);
            client.TreeDisconnect(treeId);
            client.LogOff();
            client.Disconnect();
        }
        public void ResilientWithPersistentHandle_OpenFromDiffClient()
        {
            /// 1. Open Persistent Handle with lease
            /// 2. Send Resiliency request
            /// 3. Disconnect
            /// 4. Open the same file from different client (different client guid)
            /// 5. The expected result of OPEN is successful.
            ///

            #region Check Applicability
            TestConfig.CheckDialect(DialectRevision.Smb30);
            TestConfig.CheckCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES);
            #endregion

            Smb2FunctionalClient client = new Smb2FunctionalClient(testConfig.Timeout, testConfig, this.Site);
            Guid clientGuid = Guid.NewGuid();
            Guid createGuid = Guid.NewGuid();
            Guid leaseKey = Guid.NewGuid();
            string fileName = "ResilientWithPersistentHandle_" + Guid.NewGuid() + ".txt";
            FILEID fileId;
            uint treeId;

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Open Persistent Handle with lease.");
            OpenFile(
                client,
                clientGuid,
                fileName,
                true,
                out createGuid,
                out treeId,
                out fileId);

            // resiliency request
            Packet_Header ioCtlHeader;
            IOCTL_Response ioCtlResponse;
            byte[] inputInResponse;
            byte[] outputInResponse;
            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Send resiliency request with timeout {0} milliseconds", testConfig.MaxResiliencyTimeoutInSecond);
            client.ResiliencyRequest(
                treeId,
                fileId,
                testConfig.MaxResiliencyTimeoutInSecond,
                (uint)Marshal.SizeOf(typeof(NETWORK_RESILIENCY_Request)),
                out ioCtlHeader,
                out ioCtlResponse,
                out inputInResponse,
                out outputInResponse
                );

            // Disconnect
            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Disconnect the resilient handle");
            client.Disconnect();

            // open from another client
            Smb2FunctionalClient anotherClient = new Smb2FunctionalClient(testConfig.Timeout, testConfig, this.Site);
            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Open the same file from different client (different client guid), the expected result of OPEN is successful");
            OpenFile(
                anotherClient,
                Guid.NewGuid(),
                fileName,
                false,
                out createGuid,
                out treeId,
                out fileId);
        }
        /// <summary>
        /// Reconnect to share on clustered file server after failover happens, include NEGOTIATE, SESSION_SETUP, TREE_CONNECT
        /// </summary>
        /// <param name="server">Name of clustered file server</param>
        /// <param name="fsType">Type of clustered file server</param>
        /// <param name="treeId">Out param for tree Id that connected</param>
        /// <param name="enableEncryptionPerShare">Set true if enable encryption on share, otherwise set false</param>
        private void ReconnectServerAfterFailover(string server, FileServerType fsType, out uint treeId, bool enableEncryptionPerShare = false)
        {
            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "AfterFailover: Connect share {0} on server {1} with following steps.", uncSharePath, server);
            if (fsType == FileServerType.ScaleOutFileServer)
            {
                // For scale-out file server case, retrieve and use another access IP for connection
                IPAddress oldAccessIp = currentAccessIp;
                currentAccessIp = null;

                foreach (var ip in accessIpList)
                {
                    if (!ip.Equals(oldAccessIp))
                    {
                        currentAccessIp = ip;
                        break;
                    }
                }
            }
            else if (fsType == FileServerType.GeneralFileServer)
            {
                currentAccessIp = null;
                DoUntilSucceed(() =>
                {
                    foreach (IPAddress ipAddress in accessIpList)
                    {
                        Smb2FunctionalClient pingClient = new Smb2FunctionalClient(TestConfig.FailoverTimeout, TestConfig, BaseTestSite);

                        try
                        {
                            pingClient.ConnectToServerOverTCP(ipAddress);
                            pingClient.Disconnect();
                            pingClient = null;

                            currentAccessIp = ipAddress;
                            return true;
                        }
                        catch
                        {
                        }
                    }
                    return false;
                }, TestConfig.FailoverTimeout, "Retry to ping to server until succeed within timeout span");
            }
            BaseTestSite.Assert.AreNotEqual(
                null,
                currentAccessIp,
                "Access IP to the file server should not be empty");
            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Got IP {0} to access the file server",
                    currentAccessIp.ToString());

            DoUntilSucceed(() => clientAfterFailover.ConnectToServer(TestConfig.UnderlyingTransport, server, currentAccessIp), TestConfig.FailoverTimeout,
                "Retry to connect to server until succeed within timeout span");

            #region Negotiate
            Capabilities_Values clientCapabilitiesAfterFailover = 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 | Capabilities_Values.GLOBAL_CAP_ENCRYPTION;
            status = clientAfterFailover.Negotiate(
                TestConfig.RequestDialects,
                TestConfig.IsSMB1NegotiateEnabled,
                capabilityValue: clientCapabilitiesAfterFailover,
                clientGuid: clientGuid,
                checker: (Packet_Header header, NEGOTIATE_Response response) =>
                {
                    TestConfig.CheckNegotiateDialect(DialectRevision.Smb30, response);
                });
            #endregion

            #region SESSION_SETUP
            status = clientAfterFailover.ReconnectSessionSetup(
                        clientBeforeFailover,
                        TestConfig.DefaultSecurityPackage,
                        server,
                        TestConfig.AccountCredential,
                        TestConfig.UseServerGssToken);

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Global encryption disabled");
            #endregion

            #region TREE_CONNECT to share
            uint innerTreeId = 0;
            //Retry TreeConnect until succeed within timeout span
            status = DoUntilSucceed(
                () => clientAfterFailover.TreeConnect(uncSharePath, out innerTreeId, (header, response) => { }),
                TestConfig.FailoverTimeout,
                "Retry TreeConnect until succeed within timeout span");
            BaseTestSite.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "TreeConnect to {0} should succeed, actual status is {1}", uncSharePath, Smb2Status.GetStatusCode(status));
            treeId = innerTreeId;

            clientAfterFailover.SetTreeEncryption(innerTreeId, enableEncryptionPerShare);
            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Per share encryption for TreeId=0x{0:x} : {1}", treeId, enableEncryptionPerShare);
            #endregion

            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "AfterFailover: Finish connecting to share {0} on server {1}", uncSharePath, server);
        }
        public void ResilientOpenScavengerTimer_ReconnectAfterTimeout()
        {
            /// 1. Wait for MaxResiliencyTimeoutInSecond seconds to expire the Resilient Timer and make sure that the Timer is not started.
            /// 2. Open Resilient Handle with specific timeout.
            /// 3. Disconnect to start the Resilient Timer.
            /// 4. Wait for specific timeout + 1 seconds.
            /// 5. Reconnect the resilient handle and expect the handle is terminated.

            #region Check Applicability
            TestConfig.CheckDialect(DialectRevision.Smb21);
            TestConfig.CheckIOCTL(CtlCode_Values.FSCTL_LMR_REQUEST_RESILIENCY);
            TestConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_RECONNECT);
            #endregion

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Wait {0} seconds to make sure Resilient Timer is not started.", testConfig.MaxResiliencyTimeoutInSecond);
            Thread.Sleep(TimeSpan.FromSeconds((int)testConfig.MaxResiliencyTimeoutInSecond));

            Smb2FunctionalClient prepareClient = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);

            uint timeoutInSecond = testConfig.MaxResiliencyTimeoutInSecond / 2;
            Guid clientGuid = Guid.NewGuid();
            string fileName = "ResilientHandle_" + Guid.NewGuid() + ".txt";
            FILEID fileId;

            // Open file & Resiliency request
            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Create resilient handle to file '{0}' and timeout is {1} seconds", fileName, timeoutInSecond);
            OpenFileAndResilientRequest(
                prepareClient,
                clientGuid,
                fileName,
                timeoutInSecond * 1000, // convert second to millisecond
                out fileId);

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Disconnect the client to start the Resilient Open Scavenger Timer on server");
            prepareClient.Disconnect();

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Wait {0} seconds before Resilient Open Scavenger Timer expired.", timeoutInSecond + 10);
            Thread.Sleep(TimeSpan.FromSeconds(timeoutInSecond + 10));

            Smb2FunctionalClient reconnectClient = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Re-establish Resilient Open, verify the returned status is STATUS_OBJECT_NAME_NOT_FOUND.");
            ReconnectResilientHandle(
                reconnectClient,
                clientGuid,
                fileName,
                fileId,
                NtStatus.STATUS_OBJECT_NAME_NOT_FOUND,
                "Resilient handle should be terminated.");

            // clean
            reconnectClient.Disconnect();
        }
        public void ReconnectSharedVHDWithoutDeviceContext()
        {
            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "1.	Client opens a shared virtual disk file with SMB2 create contexts " +
                "SVHDX_OPEN_DEVICE_CONTEXT and SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 (persistent bit is set). ");

            Smb2FunctionalClient clientBeforeDisconnect = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            uint treeId;
            Guid clientGuid = Guid.NewGuid();
            ConnectToShare(clientBeforeDisconnect, clientGuid, TestConfig.FullPathShareContainingSharedVHD, out treeId);

            Guid createGuid = Guid.NewGuid();
            Guid initiatorId = Guid.NewGuid();
            Smb2CreateContextResponse[] serverCreateContexts;
            FILEID fileIdBeforeDisconnect;
            clientBeforeDisconnect.Create
                (treeId,
                TestConfig.NameOfSharedVHDX + fileNameSuffix,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileIdBeforeDisconnect,
                out serverCreateContexts,
                RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                new Smb2CreateContextRequest[]
                {
                    new Smb2CreateSvhdxOpenDeviceContext
                    {
                        Version = (uint)RSVD_PROTOCOL_VERSION.RSVD_PROTOCOL_VERSION_1,
                        OriginatorFlags = (uint)OriginatorFlag.SVHDX_ORIGINATOR_PVHDPARSER,
                        InitiatorHostName = TestConfig.InitiatorHostName,
                        InitiatorHostNameLength = (ushort)(TestConfig.InitiatorHostName.Length * 2),  // InitiatorHostName is a null-terminated Unicode UTF-16 string
                        InitiatorId = initiatorId
                    },
                    new Smb2CreateDurableHandleRequestV2
                    {
                        CreateGuid = createGuid,
                        Flags = CREATE_DURABLE_HANDLE_REQUEST_V2_Flags.DHANDLE_FLAG_PERSISTENT
                    }
                });

            bool persistentHandleReturned = false;
            if (serverCreateContexts != null && serverCreateContexts[0] is Smb2CreateDurableHandleResponseV2)
            {
                var durableResponse = serverCreateContexts[0] as Smb2CreateDurableHandleResponseV2;
                if (durableResponse.Flags.HasFlag(CREATE_DURABLE_HANDLE_RESPONSE_V2_Flags.DHANDLE_FLAG_PERSISTENT))
                {
                    persistentHandleReturned = true;
                }
            }

            BaseTestSite.Assert.IsTrue(persistentHandleReturned, "Server should return a persistent handle.");

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "2.	Client disconnects from the server.");
            clientBeforeDisconnect.Disconnect();

            Smb2FunctionalClient clientAfterDisconnect = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            ConnectToShare(clientAfterDisconnect, clientGuid, TestConfig.FullPathShareContainingSharedVHD, out treeId);
            FILEID fileIdAfterDisconnect;
            uint status = clientAfterDisconnect.Create
                (treeId,
                TestConfig.NameOfSharedVHDX + fileNameSuffix,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileIdAfterDisconnect,
                out serverCreateContexts,
                RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                new Smb2CreateContextRequest[]
                {
                    new Smb2CreateDurableHandleReconnectV2
                    {
                        CreateGuid = createGuid,
                        Flags = CREATE_DURABLE_HANDLE_RECONNECT_V2_Flags.DHANDLE_FLAG_PERSISTENT,
                        FileId = new FILEID { Persistent = fileIdBeforeDisconnect.Persistent }
                    }
                },
                checker: (header, response) => { });

            BaseTestSite.Assert.AreEqual(
                (uint)Smb2Status.STATUS_SUCCESS,
                status,
                "3. Client reconnects the persistent handle without create context SVHDX_OPEN_DEVICE_CONTEXT and expects success. Actual status is: {0}",
                GetStatus(status));

            clientAfterDisconnect.Close(treeId, fileIdAfterDisconnect);
            clientAfterDisconnect.TreeDisconnect(treeId);
            clientAfterDisconnect.LogOff();
            clientAfterDisconnect.Disconnect();
        }
        private void CreateFile(string uncShare, string fileName, int lengthInByte)
        {
            Site.Log.Add(
                LogEntryKind.Debug,
                "Create file {0} in share {1}", fileName, uncShare);

            Smb2FunctionalClient client = new Smb2FunctionalClient(testConfig.Timeout, testConfig, this.Site);
            client.ConnectToServer(testConfig.UnderlyingTransport, testConfig.SutComputerName, testConfig.SutIPAddress);

            client.CreditGoal = 32;

            client.Negotiate(
                new DialectRevision[] { ModelUtility.GetDialectRevision(config.MaxSmbVersionSupported) },
                testConfig.IsSMB1NegotiateEnabled,
                capabilityValue: Capabilities_Values.GLOBAL_CAP_LARGE_MTU);

            client.SessionSetup(
                testConfig.DefaultSecurityPackage,
                testConfig.SutComputerName,
                testConfig.AccountCredential,
                testConfig.UseServerGssToken);

            uint tId;
            client.TreeConnect(
                uncShare,
                out tId);

            Smb2CreateContextResponse[] serverCreateContexts;
            FILEID fId;
            client.Create(
                tId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fId,
                out serverCreateContexts);

            string content;
            if (isMultiCreditSupportedOnConnection)
            {
                content = Smb2Utility.CreateRandomStringInByte(lengthInByte);
                client.Write(tId, fId, content);
            }
            else
            {
                // Write several times if server does not support multi credit
                int writeTimes = lengthInByte / (64 * 1024);
                int rest = lengthInByte % (64 * 1024);
                ulong offset = 0;

                for (int time = 0; time < writeTimes; time++)
                {
                    content = Smb2Utility.CreateRandomString(64);
                    client.Write(tId, fId, content, offset);
                    offset += 64 * 1024;
                }

                if (rest != 0)
                {
                    content = Smb2Utility.CreateRandomStringInByte(rest);
                    client.Write(tId, fId, content, offset);
                }
            }

            client.Close(tId, fId);

            client.TreeDisconnect(tId);

            client.LogOff();

            client.Disconnect();

            Site.Log.Add(
                LogEntryKind.Debug,
                "Create file {0} in share {1}", fileName, uncShare);
        }
        public void ResilientWithPersistentHandle_OpenFromDiffClient()
        {
            /// 1. Open Persistent Handle with lease
            /// 2. Send Resiliency request
            /// 3. Disconnect
            /// 4. Open the same file from different client (different client guid)
            /// 5. The expected result of OPEN is successful.
            ///
            /// Covered TD, section
            /// If Connection.Dialect is "3.000" and the request does not contain SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context
            /// or SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context, the server MUST look up an existing open in the
            /// GlobalOpenTable where Open.FileName matches the file name in the Buffer field of the request. If an Open entry is found,
            /// if Open.IsPersistent is TRUE, *Open.IsResilient is TRUE* and if Open.Connection is NULL, the server MUST fail the request with STATUS_FILE_NOT_AVAILABLE.
            ///
            /// Related TDI: 67939
            #region Check Applicability
            TestConfig.CheckDialect(DialectRevision.Smb30);
            TestConfig.CheckCapabilities(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES);
            #endregion

            Smb2FunctionalClient client = new Smb2FunctionalClient(testConfig.Timeout, testConfig, this.Site);
            Guid clientGuid = Guid.NewGuid();
            Guid createGuid = Guid.NewGuid();
            Guid leaseKey = Guid.NewGuid();
            string fileName = "ResilientWithPersistentHandle_" + Guid.NewGuid() + ".txt";
            FILEID fileId;
            uint treeId;

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Open Persistent Handle with lease.");
            OpenFile(
                client,
                clientGuid,
                fileName,
                true,
                out createGuid,
                out treeId,
                out fileId);

            // resiliency request
            Packet_Header ioCtlHeader;
            IOCTL_Response ioCtlResponse;
            byte[] inputInResponse;
            byte[] outputInResponse;
            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Send resiliency request with timeout {0} milliseconds", testConfig.MaxResiliencyTimeoutInSecond);
            client.ResiliencyRequest(
                treeId,
                fileId,
                testConfig.MaxResiliencyTimeoutInSecond,
                (uint)Marshal.SizeOf(typeof(NETWORK_RESILIENCY_Request)),
                out ioCtlHeader,
                out ioCtlResponse,
                out inputInResponse,
                out outputInResponse
                );

            // Disconnect
            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Disconnect the resilient handle");
            client.Disconnect();

            // open from another client
            Smb2FunctionalClient anotherClient = new Smb2FunctionalClient(testConfig.Timeout, testConfig, this.Site);
            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Open the same file from different client (different client guid), the expected result of OPEN is successful");
            OpenFile(
                anotherClient,
                Guid.NewGuid(),
                fileName,
                false,
                out createGuid,
                out treeId,
                out fileId);
        }
        /// <summary>
        /// Read and write file within byte lock range when the file is locked or unlocked
        /// </summary>
        /// <param name="isLocked">Set true to indicate that byte lock range is taken on the file</param>
        private void ValidateByteLockRangeFromAnotherClient(bool isLocked)
        {
            uint status = 0;

            Smb2FunctionalClient client = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);

            client = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            client.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress, TestConfig.ClientNic2IPAddress);

            status = client.Negotiate(
                TestConfig.RequestDialects,
                TestConfig.IsSMB1NegotiateEnabled);

            status = client.SessionSetup(
                TestConfig.DefaultSecurityPackage,
                TestConfig.SutComputerName,
                TestConfig.AccountCredential,
                TestConfig.UseServerGssToken);

            uint treeId;
            status = client.TreeConnect(uncSharePath, out treeId);

            Smb2CreateContextResponse[] serverCreateContexts;
            FILEID fileId;
            status = client.Create(
                treeId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileId,
                out serverCreateContexts);

            string data;
            Random random = new Random();
            uint offset = (uint)random.Next(0, TestConfig.WriteBufferLengthInKb * 1024 - 1);
            uint length = (uint)random.Next(0, (int)(TestConfig.WriteBufferLengthInKb * 1024 - offset));
            status = client.Read(treeId, fileId, offset, length, out data);

            status = client.Write(treeId, fileId, contentWrite, checker:(header, response) => { });
            if (isLocked)
            {
                BaseTestSite.Assert.AreNotEqual(
                    Smb2Status.STATUS_SUCCESS,
                    status,
                    "Write content to locked range of file from different client is not expected to success");
                BaseTestSite.CaptureRequirementIfAreEqual(
                    Smb2Status.STATUS_FILE_LOCK_CONFLICT,
                    status,
                    RequirementCategory.STATUS_FILE_LOCK_CONFLICT.Id,
                    RequirementCategory.STATUS_FILE_LOCK_CONFLICT.Description);
            }
            else
            {
                BaseTestSite.Assert.AreEqual(
                    Smb2Status.STATUS_SUCCESS,
                    status,
                    "Write content in file should succeed, actual status is {0}", Smb2Status.GetStatusCode(status));
            }

            status = client.Close(treeId, fileId);

            status = client.TreeDisconnect(treeId);

            status = client.LogOff();

            client.Disconnect();
        }
        protected bool AccessShare(AccountCredential user, string sharePath)
        {
            bool accessSucceed = true;
            Smb2FunctionalClient client = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            client.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress);
            try
            {
                BaseTestSite.Log.Add(LogEntryKind.Debug, "Client sends NEGOTIATE message.");
                client.Negotiate(TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled);
                BaseTestSite.Log.Add(LogEntryKind.Debug, "Client sends SESSION_SETUP message using account: {0}@{1}.", user.AccountName, user.DomainName);
                client.SessionSetup(TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, user, false);

                uint treeId;
                BaseTestSite.Log.Add(LogEntryKind.Debug, "Client sends TREE_CONNECT message to access share: {0}.", sharePath);
                client.TreeConnect(sharePath, out treeId, checker: (header, response) =>
                {
                    if (header.Status == Smb2Status.STATUS_SUCCESS)
                    {
                        BaseTestSite.Log.Add(LogEntryKind.Debug, "Access succeeded in TREE_CONNECT phase.");
                        accessSucceed = true;
                    }
                    else if (header.Status == Smb2Status.STATUS_ACCESS_DENIED)
                    {
                        BaseTestSite.Log.Add(LogEntryKind.Debug, "Access denied in TREE_CONNECT phase.");
                        accessSucceed = false;
                    }
                    else
                    {
                        BaseTestSite.Assert.Fail("Unexpected error code in TREE_CONNECT response: {0}", Smb2Status.GetStatusCode(header.Status));
                    }
                });

                if (!accessSucceed)
                {
                    client.LogOff();
                    return false;
                }

                FILEID fileId;
                Smb2CreateContextResponse[] createContexResponse;

                BaseTestSite.Log.Add(LogEntryKind.Debug, "Client sends CREATE request.");
                uint status = client.Create(
                    treeId,
                    null,
                    CreateOptions_Values.FILE_DIRECTORY_FILE,
                    out fileId,
                    out createContexResponse,
                    accessMask: AccessMask.FILE_READ_DATA | AccessMask.FILE_READ_ATTRIBUTES,
                    createDisposition: CreateDisposition_Values.FILE_OPEN,
                    checker: (header, response) =>
                    {
                        if (header.Status == Smb2Status.STATUS_SUCCESS)
                        {
                            BaseTestSite.Log.Add(LogEntryKind.Debug, "Access succeeded in CREATE phase.");
                            accessSucceed = true;
                        }
                        else if (header.Status == Smb2Status.STATUS_ACCESS_DENIED)
                        {
                            BaseTestSite.Log.Add(LogEntryKind.Debug, "Access denied in CREATE phase.");
                            accessSucceed = false;
                        }
                        else
                        {
                            BaseTestSite.Assert.Fail("Unexpected error code in CREATE response: {0}", Smb2Status.GetStatusCode(header.Status));
                        }
                    });

                if (status == Smb2Status.STATUS_SUCCESS)
                {
                    BaseTestSite.Log.Add(LogEntryKind.Debug, "Tear down the client by sending the following requests: CLOSE; TREE_DISCONNECT; LOG_OFF.");
                    client.Close(treeId, fileId);
                }
                client.TreeDisconnect(treeId);
                client.LogOff();
            }
            finally
            {
                client.Disconnect();
            }
            return accessSucceed;
        }
 protected bool ShareExists(AccountCredential user, string sharePath)
 {
     BaseTestSite.Log.Add(LogEntryKind.Debug, "Test whether the specific share exists: {0}", sharePath);
     Smb2FunctionalClient clientAdmin;
     clientAdmin = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
     clientAdmin.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress);
     uint treeId;
     bool connected = ConnectToShare(clientAdmin, user, sharePath, out treeId);
     if (connected)
     {
         BaseTestSite.Log.Add(LogEntryKind.Debug, "Share exists: {0}", sharePath);
         clientAdmin.TreeDisconnect(treeId);
         clientAdmin.LogOff();
     }
     else
     {
         BaseTestSite.Log.Add(LogEntryKind.Debug, "Share does not exist: {0}", sharePath);
     }
     clientAdmin.Disconnect();
     return connected;
 }
        protected void SetSecurityDescriptor(string sharePath, string fileName, _SECURITY_DESCRIPTOR sd, SET_INFO_Request_AdditionalInformation_Values securityAttributesToApply)
        {
            Smb2FunctionalClient clientAdmin;
            clientAdmin = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            clientAdmin.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress);
            uint treeId;
            ConnectToShare(clientAdmin, TestConfig.AccountCredential, sharePath, out treeId);

            FILEID fileId;
            Smb2CreateContextResponse[] createContextResponses;
            clientAdmin.Create(treeId,
                fileName,
                fileName == null ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileId,
                out createContextResponses,
                accessMask: AccessMask.READ_CONTROL | AccessMask.WRITE_DAC | AccessMask.FILE_READ_ATTRIBUTES | AccessMask.WRITE_OWNER | AccessMask.ACCESS_SYSTEM_SECURITY,
                shareAccess: ShareAccess_Values.FILE_SHARE_DELETE | ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE,
                createDisposition: CreateDisposition_Values.FILE_OPEN);
            clientAdmin.SetSecurityDescriptor(treeId, fileId, securityAttributesToApply, sd);
            clientAdmin.Close(treeId, fileId);
            clientAdmin.TreeDisconnect(treeId);
            clientAdmin.Disconnect();
        }
        public void SessionMgmt_ReconnectWithDifferentDialect()
        {
            Guid clientGuid = Guid.NewGuid();

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start a first client by sending NEGOTIATE request.");
            client.Negotiate(TestConfig.RequestDialects,
                TestConfig.IsSMB1NegotiateEnabled,
                SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                null, // capability value will be set inside the method according to requested dialects.
                clientGuid);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "The first client sends SESSION_SETUP request with SESSION_ID set to ZARO.");
            client.SessionSetup(TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Disconnect the first client by sending DISCONNECT request.");
            client.Disconnect();

            #region Reconnect and Do Session Setup with PreviousSessionId set.
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start a second client by sending NEGOTIATE request.");
            Smb2FunctionalClient client2 = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            client2.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress);
            // Select different dialects
            List<DialectRevision> newRequestDialects = new List<DialectRevision>();
            foreach (DialectRevision dialect in TestConfig.RequestDialects)
            {
                if (dialect != client.Dialect)
                {
                    newRequestDialects.Add(dialect);
                }
            }

            client2.Negotiate(newRequestDialects.ToArray(),
                TestConfig.IsSMB1NegotiateEnabled,
                SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                null, // capability value will be set inside the method according to requested dialects.
                clientGuid);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "The second client sends SESSION_SETUP request with SESSION_ID set to the value in the previous SESSION_SETUP response.");
            client2.ReconnectSessionSetup(
                client,
                TestConfig.DefaultSecurityPackage,
                TestConfig.SutComputerName,
                TestConfig.AccountCredential,
                false,
                SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                SESSION_SETUP_Request_Capabilities_Values.GLOBAL_CAP_DFS,
                checker: (Packet_Header header, SESSION_SETUP_Response response) =>
                {
                    if (testConfig.IsWindowsPlatform && testConfig.Platform != Platform.WindowsServer2008R2)
                    {
                        BaseTestSite.Assert.AreEqual(
                            Smb2Status.STATUS_USER_SESSION_DELETED,
                            header.Status,
                            "[MS-SMB2] 3.3.5.5.3 The server MUST look up all existing connections from the client in the global ConnectionList where Connection.ClientGuid matches Session.Connection.ClientGuid. " +
                            "For any matching Connection, if Connection.Dialect is not the same as Session.Connection.Dialect, the server SHOULD<235> close the newly created Session, " +
                            "as specified in section 3.3.4.12, by providing Session.SessionGlobalId as the input parameter, and fail the session setup request with STATUS_USER_SESSION_DELETED.");
                    }
                    else if (testConfig.Platform == Platform.NonWindows)
                    {
                        BaseTestSite.Assert.AreNotEqual(
                            Smb2Status.STATUS_SUCCESS,
                            header.Status,
                            "Reconnect with different SMB2 dialect SHOULD NOT succeed.");
                    }
                });
            #endregion

            #region Tear Down Client
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Disconnect the second client by sending DISCONNECT request.");
            client2.Disconnect();
            #endregion
        }
        /// <summary>
        /// Read content after failover
        /// </summary>
        /// <param name="server">File server name.</param>
        /// <param name="serverAccessIp">File server access IP.</param>
        /// <param name="uncSharePath">The share path to read the file.</param>
        /// <param name="file">The file name for reading content.</param>
        /// <param name="content">The content to read.</param>
        /// <param name="clientGuid">Smb2 client Guid.</param>
        /// <param name="createGuid">The Guid for smb2 create request.</param>
        /// <returns></returns>
        protected bool ReadContentAfterFailover(string server,
            IPAddress serverAccessIp,
            string uncSharePath,
            string file,
            string content,
            Guid clientGuid,
            Guid createGuid)
        {
            uint status;

            BaseTestSite.Assert.AreNotEqual(
                null,
                serverAccessIp,
                "Access IP to the file server should not be empty");
            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Got IP {0} to access the file server", serverAccessIp.ToString());

            Smb2FunctionalClient afterFailover = new Smb2FunctionalClient(TestConfig.FailoverTimeout, TestConfig, BaseTestSite);
            DoUntilSucceed(() => afterFailover.ConnectToServer(TestConfig.UnderlyingTransport, server, serverAccessIp), TestConfig.FailoverTimeout,
                "Retry to connect to server until succeed within timeout span");

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends NEGOTIATE request with the same clientguid of previous client.");
            status = afterFailover.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);
            if (status != Smb2Status.STATUS_SUCCESS)
            {
                BaseTestSite.Log.Add(LogEntryKind.Warning, "Negotiate failed with {0}.", Smb2Status.GetStatusCode(status));
                return false;
            }

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends SESSION_SETUP request with the same SESSION_ID of previous client.");
            status = afterFailover.ReconnectSessionSetup(
                        beforeFailover,
                        TestConfig.DefaultSecurityPackage,
                        server,
                        TestConfig.AccountCredential,
                        TestConfig.UseServerGssToken);
            if (status != Smb2Status.STATUS_SUCCESS)
            {
                BaseTestSite.Log.Add(LogEntryKind.Warning, "ReconnectSessionSetup failed with {0}.", Smb2Status.GetStatusCode(status));
                return false;
            }

            // Retry TreeConnect because network path may not be available immediately
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client retries TREE_CONNECT to {0} until succeed or timeout in {1} because network path may not be available immediately.", uncSharePath, TestConfig.FailoverTimeout);
            uint treeId = 0;
            status = afterFailover.TreeConnect(uncSharePath, out treeId, (header, response) => { });
            if (status != Smb2Status.STATUS_SUCCESS)
            {
                BaseTestSite.Log.Add(LogEntryKind.Warning, "TreeConnect failed with {0}.", Smb2Status.GetStatusCode(status));
                return false;
            }

            // Retry Create because file may not be available immediately
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client retries to send CREATE request with SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 context with PERSISTENT flag set until succeed or timeout in {0}.", TestConfig.FailoverTimeout);
            FILEID fileId = new FILEID();
            Smb2CreateContextResponse[] serverCreateContexts;
            status = DoUntilSucceed(
                () => afterFailover.Create(
                        treeId,
                        file,
                        CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                        out fileId,
                        out serverCreateContexts,
                        RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                        new Smb2CreateContextRequest[] {
                            new Smb2CreateDurableHandleReconnectV2
                            {
                                FileId = new FILEID { Persistent = fileId.Persistent },
                                CreateGuid = createGuid,
                                Flags = CREATE_DURABLE_HANDLE_RECONNECT_V2_Flags.DHANDLE_FLAG_PERSISTENT
                            },
                        },
                        checker: (header, response) => { }),
                TestConfig.FailoverTimeout,
                "Retry Create until succeed within timeout span");
            if (status != Smb2Status.STATUS_SUCCESS)
            {
                BaseTestSite.Log.Add(LogEntryKind.Warning, "Create failed with {0}.", Smb2Status.GetStatusCode(status));
                return false;
            }

            string readContent;
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Client sends READ request to read content.");
            status = afterFailover.Read(treeId, fileId, 0, (uint)content.Length, out readContent);
            if (status != Smb2Status.STATUS_SUCCESS)
            {
                BaseTestSite.Log.Add(LogEntryKind.Warning, "Read failed with {0}.", Smb2Status.GetStatusCode(status));
                return false;
            }

            BaseTestSite.Assert.IsTrue(
                content.Equals(readContent),
                "Content read after failover should be identical to that written before failover");

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the client by sending the following requests: CLOSE; TREE_DISCONNECT; LOG_OFF");
            status = afterFailover.Close(treeId, fileId);
            status = afterFailover.TreeDisconnect(treeId);
            status = afterFailover.LogOff();
            afterFailover.Disconnect();
            return true;
        }
        public void BVT_SessionMgmt_ReconnectSessionSetup()
        {
            Guid clientGuid = (TestConfig.RequestDialects.Length == 1 && TestConfig.RequestDialects[0] == DialectRevision.Smb2002) ? Guid.Empty : Guid.NewGuid();

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start a first client by sending NEGOTIATE request.");
            client.Negotiate(TestConfig.RequestDialects,
                TestConfig.IsSMB1NegotiateEnabled,
                SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                null, // capability value will be set inside the method according to requested dialects.
                clientGuid);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "The first client sends SESSION_SETUP request with SESSION_ID set to ZARO.");
            client.SessionSetup(TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, TestConfig.UseServerGssToken);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Disconnect the first client by sending DISCONNECT request.");
            client.Disconnect();

            #region Reconnect and Do Session Setup with PreviousSessionId set.
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start a second client by sending NEGOTIATE request.");
            Smb2FunctionalClient client2 = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            client2.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress);
            client2.Negotiate(TestConfig.RequestDialects,
                TestConfig.IsSMB1NegotiateEnabled,
                SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                null, // capability value will be set inside the method according to requested dialects.
                clientGuid);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "The second client sends SESSION_SETUP request with SESSION_ID set to the value in the previous SESSION_SETUP response.");
            client2.ReconnectSessionSetup(client, TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, TestConfig.AccountCredential, false);
            #endregion

            #region Tear Down Client
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the second client by sending the following requests: LOG_OFF; DISCONNECT");
            client2.LogOff();
            client2.Disconnect();
            #endregion
        }
        private void AppInstanceIdTest(bool sameAppInstanceId, bool containCreateDurableContext)
        {
            string content = Smb2Utility.CreateRandomString(TestConfig.WriteBufferLengthInKb);

            #region Client 1 Connect to Server
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start the first client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT");
            clientForInitialOpen = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            clientForInitialOpen.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress, TestConfig.ClientNic1IPAddress);
            clientForInitialOpen.Negotiate(TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled);
            clientForInitialOpen.SessionSetup(
                TestConfig.DefaultSecurityPackage,
                TestConfig.SutComputerName,
                TestConfig.AccountCredential,
                TestConfig.UseServerGssToken);
            uint treeIdForInitialOpen;
            clientForInitialOpen.TreeConnect(sharePath, out treeIdForInitialOpen);

            Guid appInstanceId = Guid.NewGuid();
            FILEID fileIdForInitialOpen;
            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "The first client sends CREATE request for exclusive open with SMB2_CREATE_APP_INSTANCE_ID create context.");
            Smb2CreateContextResponse[] serverCreateContexts;
            Smb2CreateContextRequest[] createContextsRequestForInitialOpen = null;
            if (containCreateDurableContext)
            {
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 create context is also included in the CREATE request.");
                createContextsRequestForInitialOpen = new Smb2CreateContextRequest[] {
                    new Smb2CreateDurableHandleRequestV2
                    {
                         CreateGuid = Guid.NewGuid()
                    },
                    new Smb2CreateAppInstanceId
                    {
                         AppInstanceId = appInstanceId
                    }
                };
            }
            else
            {
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 create context is not included in the CREATE request.");
                createContextsRequestForInitialOpen = new Smb2CreateContextRequest[] {
                    new Smb2CreateAppInstanceId
                    {
                         AppInstanceId = appInstanceId
                    }
                };
            }

            clientForInitialOpen.Create(
                treeIdForInitialOpen,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileIdForInitialOpen,
                out serverCreateContexts,
                RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                createContextsRequestForInitialOpen,
                shareAccess: ShareAccess_Values.NONE);
            #endregion

            #region Client 2 Connect to Server

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Start the second client by sending the following requests: NEGOTIATE; SESSION-SETUP; TREE_CONNECT");
            clientForReOpen = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            clientForReOpen.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress, TestConfig.ClientNic2IPAddress);
            clientForReOpen.Negotiate(TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled);
            clientForReOpen.SessionSetup(
                TestConfig.DefaultSecurityPackage,
                TestConfig.SutComputerName,
                TestConfig.AccountCredential,
                TestConfig.UseServerGssToken);
            uint treeIdForReOpen;
            clientForReOpen.TreeConnect(sharePath, out treeIdForReOpen);

            FILEID fileIdForReOpen;
            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "The second client sends CREATE request for exclusive open with the {0} SMB2_CREATE_APP_INSTANCE_ID of the first client.", sameAppInstanceId ? "same" : "different");
            Smb2CreateContextRequest[] createContextsRequestForReOpen = null;
            if (containCreateDurableContext)
            {
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 create context is also included in the CREATE request.");
                createContextsRequestForReOpen = new Smb2CreateContextRequest[] {
                    new Smb2CreateDurableHandleRequestV2
                    {
                         CreateGuid = Guid.NewGuid()
                    },
                    new Smb2CreateAppInstanceId
                    {
                         AppInstanceId = sameAppInstanceId ? appInstanceId : Guid.NewGuid()
                    }
                };
            }
            else
            {
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 create context is not included in the CREATE request.");
                createContextsRequestForReOpen = new Smb2CreateContextRequest[] {
                    new Smb2CreateAppInstanceId
                    {
                         AppInstanceId = sameAppInstanceId ? appInstanceId : Guid.NewGuid()
                    }
                };
            }

            clientForReOpen.Create(
                treeIdForReOpen,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileIdForReOpen,
                out serverCreateContexts,
                RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                createContextsRequestForReOpen,
                shareAccess: ShareAccess_Values.NONE,
                checker: (header, response) =>
                {
                    if (sameAppInstanceId)
                    {
                        BaseTestSite.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, header.Status, "The second client should create the open successfully.");
                    }
                    else
                    {
                        BaseTestSite.Assert.AreNotEqual(Smb2Status.STATUS_SUCCESS, header.Status, "The second client should not create the open successfully.");
                    }
                });

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "The first client sends another WRITE request.");

            if (sameAppInstanceId)
            {
                clientForInitialOpen.Write(treeIdForInitialOpen, fileIdForInitialOpen, content,
                    checker: (header, response) =>
                    {
                        BaseTestSite.Assert.AreNotEqual(
                            Smb2Status.STATUS_SUCCESS,
                            header.Status,
                            "The initial open is closed. Write should not succeed. Actually server returns with {0}.", Smb2Status.GetStatusCode(header.Status));
                        BaseTestSite.CaptureRequirementIfAreEqual(
                            Smb2Status.STATUS_FILE_CLOSED,
                            header.Status,
                            RequirementCategory.STATUS_FILE_CLOSED.Id,
                            RequirementCategory.STATUS_FILE_CLOSED.Description);
                    });

                // The first open is closed, no need to do clean up job.
                // Clean up the second client.
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the second client by sending the following requests: CLOSE; TREE_DISCONNECT; LOG_OFF; DISCONNECT");
                clientForReOpen.Close(treeIdForReOpen, fileIdForReOpen);
                clientForReOpen.TreeDisconnect(treeIdForReOpen);
                clientForReOpen.LogOff();
                clientForReOpen.Disconnect();
            }
            else
            {
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "The initial open is not closed. Write should succeed.");
                clientForInitialOpen.Write(treeIdForInitialOpen, fileIdForInitialOpen, content);

                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the first client by sending the following requests: CLOSE; TREE_DISCONNECT; LOG_OFF");
                clientForInitialOpen.Close(treeIdForInitialOpen, fileIdForInitialOpen);
                clientForInitialOpen.TreeDisconnect(treeIdForInitialOpen);
                clientForInitialOpen.LogOff();

                // The second client doesn't create the open succesfully, so no need to close the open.
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Tear down the second client by sending the following requests: TREE_DISCONNECT; LOG_OFF; DISCONNECT");
                clientForReOpen.TreeDisconnect(treeIdForReOpen);
                clientForReOpen.LogOff();
                clientForReOpen.Disconnect();
            }

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

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

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

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

            Smb2CreateContextRequest[] contexts;
            RequestedOplockLevel_Values oplockLevel;
            LeaseStateValues requestLeaseState;

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

            FillChannelSequence(client, channelSequence);

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

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

            CreateResponse(
                (ModelSmb2Status)status,
                ConvertHandle(serverCreateContexts),
                replayConfig);
        }
        /// <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
        }
        /// <summary>
        /// Get the owner node of general clustered file server
        /// </summary>
        /// <param name="server">Name of clustered file server</param>
        /// <param name="fsType">Type of clustered file server</param>
        private void GetGeneralFileServerClusterOwner(string server)
        {
            currentAccessIp = null;
            DoUntilSucceed(() =>
            {
                foreach (IPAddress ipAddress in accessIpList)
                {
                    Smb2FunctionalClient pingClient = new Smb2FunctionalClient(TestConfig.FailoverTimeout, TestConfig, BaseTestSite);

                    try
                    {
                        pingClient.ConnectToServerOverTCP(ipAddress);
                        pingClient.Disconnect();
                        pingClient = null;

                        currentAccessIp = ipAddress;
                        return true;
                    }
                    catch
                    {
                    }
                }
                return false;
            }, TestConfig.FailoverTimeout, "Retry to ping to server until succeed within timeout span");

            BaseTestSite.Assert.AreNotEqual(
                null,
                currentAccessIp,
                "Access IP to the file server should NOT be empty");
            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Got IP {0} to access the file server", currentAccessIp.ToString());

            if (TestConfig.IsWindowsPlatform)
            {
                AssignCurrentAccessNode(server, FileServerType.GeneralFileServer, currentAccessIp);
            }
        }
        public void OpenRequest(
            ClientGuidType clientGuidType,
            PathNameType pathNameType,
            CreateType createType,
            ShareType shareType,
            AppInstanceIdType appInstanceIdType)
        {
            Smb2FunctionalClient testClient = new Smb2FunctionalClient(testConfig.Timeout, testConfig, this.Site);
            uint treeId;
            string share;
            switch (shareType)
            {
                case ShareType.SameShare:
                    share = testConfig.BasicFileShare;
                    break;
                case ShareType.DifferentShareSameLocal:
                    share = testConfig.SameWithSMBBasic;
                    break;
                case ShareType.DifferentShareDifferentLocal:
                    share = testConfig.DifferentFromSMBBasic;
                    cleanFileInDifferentShare = true;
                    break;
                default:
                    throw new ArgumentException("shareType");
            }

            ConnectToShare(
                clientDialect,
                testClient,
                clientGuidType == ClientGuidType.SameClientGuid ? this.connection_ClientGuid : Guid.NewGuid(),
                share,
                out treeId);

            FILEID fileId;
            Smb2CreateContextResponse[] createContextResponse;
            uint status;
            string fileNameInOpen;
            if (pathNameType == PathNameType.SamePathName)
            {
                fileNameInOpen = fileName;
            }
            else
            {
                fileNameInOpen = fileName + different;
                cleanFileWithDifferentName = true;
            }

            status = testClient.Create(
                treeId,
                fileNameInOpen,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileId,
                out createContextResponse,
                createContexts: CreateContexts(appInstanceIdType, createType, false),
                shareAccess: ShareAccess_Values.NONE,
                checker: (header, response) => { });

            // The file is not created, no need to delete.
            if (status != Smb2Status.STATUS_SUCCESS)
            {
                cleanFileInDifferentShare = false;
                cleanFileWithDifferentName = false;
            }

            testClient.Disconnect();
            testClient = null;

            // Check if the Open is closed.
            // If status is success, and fileId is the same with the previous one, then the Open is not closed.
            // Otherwise, use some other way to check if the Open is closed.
            bool ifClosed;
            if (status == Smb2Status.STATUS_SUCCESS && fileId.Persistent == this.open_FileId.Persistent)
                ifClosed = false;
            else
                ifClosed = CheckIfOpenClosed(clientDialect, createType);
            this.OpenResponse(ifClosed ? OpenStatus.OpenClosed : OpenStatus.OpenNotClosed);
        }
        public void SharePermission_CreateClose_DeleteFile_MaximalAccessNotIncludeDeleteOrGenericAll()
        {
            _SID sid = DtypUtility.GetSidFromAccount(TestConfig.DomainName, azUser01Name);
            if (!dynamicallyConfigurableShareExist)
            {
                BaseTestSite.Assert.Inconclusive("Required share: {0} does not exist!", dynamicallyConfigurableShareName);
            }
            object ace = DtypUtility.CreateAccessAllowedAce(sid, (DtypUtility.ACCESS_MASK_STANDARD_RIGHTS_ALL | DtypUtility.ACCESS_MASK_SPECIFIC_RIGHTS_ALL) & ~DtypUtility.ACCESS_MASK_DELETE, ACE_FLAGS.None);
            SetSecurityDescriptorOnDynamicallyConfigurableShare(ace);
            string shareName = dynamicallyConfigurableShareName;
            string shareUncPath = Smb2Utility.GetUncPath(TestConfig.SutComputerName, shareName);

            Smb2FunctionalClient client = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            client.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress);
            AccountCredential user = new AccountCredential(TestConfig.DomainName, azUser01Name, TestConfig.UserPassword);
            try
            {
                BaseTestSite.Log.Add(LogEntryKind.Debug, "Client sends NEGOTIATE message.");
                client.Negotiate(TestConfig.RequestDialects, TestConfig.IsSMB1NegotiateEnabled);
                BaseTestSite.Log.Add(LogEntryKind.Debug, "Client sends SESSION_SETUP message using account: {0}@{1}.", user.AccountName, user.DomainName);
                client.SessionSetup(TestConfig.DefaultSecurityPackage, TestConfig.SutComputerName, user, false);

                uint treeId;
                BaseTestSite.Log.Add(LogEntryKind.Debug, "Client sends TREE_CONNECT message to access share: {0}.", shareUncPath);
                client.TreeConnect(shareUncPath, out treeId, checker: (header, response) =>
                {
                    BaseTestSite.Assert.IsTrue((response.MaximalAccess.ACCESS_MASK & (DtypUtility.ACCESS_MASK_DELETE | DtypUtility.ACCESS_MASK_GENERIC_ALL)) == 0,
                        "Treeconnect.MaximalAccess does not include DELETE or GENERIC_ALL.");
                });

                string fileName = string.Format("SharePermission_CreateClose_InvalidMaximalAccess_{0}.txt", Guid.NewGuid());
                FILEID fileId;
                Smb2CreateContextResponse[] createContexResponse;
                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Create the file: {0}", fileName);
                BaseTestSite.Log.Add(LogEntryKind.Debug, "Client sends CREATE request.");
                uint status = client.Create(
                    treeId,
                    fileName,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    out fileId,
                    out createContexResponse,
                    accessMask: AccessMask.FILE_READ_DATA | AccessMask.FILE_WRITE_DATA | AccessMask.FILE_APPEND_DATA |
                    AccessMask.FILE_READ_ATTRIBUTES | AccessMask.FILE_READ_EA | AccessMask.FILE_WRITE_ATTRIBUTES |
                    AccessMask.FILE_WRITE_EA | AccessMask.READ_CONTROL | AccessMask.WRITE_DAC | AccessMask.SYNCHRONIZE, // Windows client behavior
                    shareAccess: ShareAccess_Values.NONE,
                    createDisposition: CreateDisposition_Values.FILE_CREATE);
                client.Close(treeId, fileId);

                BaseTestSite.Log.Add(LogEntryKind.TestStep, "Delete the file: {0}", fileName);
                BaseTestSite.Log.Add(LogEntryKind.Debug, "Client sends CREATE request with FILE_DELETE_ON_CLOSE flag set in CreateOptions .");
                status = client.Create(
                    treeId,
                    fileName,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE | CreateOptions_Values.FILE_DELETE_ON_CLOSE,
                    out fileId,
                    out createContexResponse,
                    accessMask: AccessMask.DELETE | AccessMask.FILE_READ_ATTRIBUTES | AccessMask.SYNCHRONIZE, // Windows client behavior
                    shareAccess: ShareAccess_Values.FILE_SHARE_DELETE,
                    createDisposition: CreateDisposition_Values.FILE_OPEN,
                    checker:(header, response) =>
                    {
                        if(TestConfig.Platform == Platform.NonWindows)
                        {
                            BaseTestSite.Assert.AreNotEqual(Smb2Status.STATUS_SUCCESS, header.Status,
                                "If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and " +
                                "Treeconnect.MaximalAccess does not include DELETE or GENERIC_ALL, " +
                                "the server SHOULD fail the request with STATUS_ACCESS_DENIED");
                        }
                        else
                        {
                            BaseTestSite.Assert.AreEqual(Smb2Status.STATUS_ACCESS_DENIED, header.Status,
                                "If the FILE_DELETE_ON_CLOSE flag is set in CreateOptions and " +
                                "Treeconnect.MaximalAccess does not include DELETE or GENERIC_ALL, " +
                                "the server SHOULD fail the request with STATUS_ACCESS_DENIED");
                        }
                    });

                client.TreeDisconnect(treeId);
                client.LogOff();
            }
            catch(Exception e)
            {
                BaseTestSite.Assert.Fail("Case failed due to: {0}", e.Message);
            }
            finally
            {
                client.Disconnect();
            }
        }
        private bool CheckIfOpenClosed(ModelDialectRevision dialect, CreateType createType)
        {
            if (createType == CreateType.ReconnectDurable)
            {
                /// prepareClient is disconnected, so
                /// Reconnect to the share and try to get the open, if the durable open can be reconnected, then it's not closed.
                Smb2FunctionalClient reconnectClient = new Smb2FunctionalClient(testConfig.Timeout, testConfig, this.Site);
                uint treeId;
                ConnectToShare(
                    dialect,
                    reconnectClient,
                    this.connection_ClientGuid,
                    testConfig.BasicFileShare,
                    out treeId);
                FILEID fileId;
                Smb2CreateContextResponse[] createContextResponse;
                uint status = reconnectClient.Create(
                    treeId,
                    this.fileName,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    out fileId,
                    out createContextResponse,
                    createContexts: CreateContexts(AppInstanceIdType.NoAppInstanceId, createType, false),
                    shareAccess:ShareAccess_Values.NONE,
                    checker: (header, response) => {});

                Site.Log.Add(LogEntryKind.Debug, "CheckIfOpenClosed: status of reconnectClient.Create is " + Smb2Status.GetStatusCode(status));

                reconnectClient.Close(treeId, fileId, (header, response) => { });
                reconnectClient.Disconnect();
                return !(status == Smb2Status.STATUS_SUCCESS);
            }
            else
            {
                /// Write (using the FileID got from the create response of PrepareOpen) to check if the Open is closed.
                uint status = prepareClient.Write(this.treeConnect_TreeId, this.open_FileId, "AppInstanceId", checker: (header, response) => { });
                Site.Log.Add(LogEntryKind.Debug, "CheckIfOpenClosed: status of Write is " + Smb2Status.GetStatusCode(status));
                prepareClient.Close(this.treeConnect_TreeId, this.open_FileId, (header, response) => { });
                return status == Smb2Status.STATUS_FILE_CLOSED;
            }
        }
        public void ResilientOpenScavengerTimer_ReconnectBeforeTimeout_Zero()
        {
            /// 1. Open Resilient Handle with timeout = 0. When server receive resilient handle with timeout = 0,
            /// it will set the Open.ResilientTimeout as implementation-specific value.
            /// 2. Disconnect to start the Resilient Timer.
            /// 3. Wait for specific timeout - 1 seconds.
            /// 4. Reconnect the resilient handle and expect the result is success.
            #region Check Applicability
            TestConfig.CheckDialect(DialectRevision.Smb21);
            TestConfig.CheckIOCTL(CtlCode_Values.FSCTL_LMR_REQUEST_RESILIENCY);
            TestConfig.CheckCreateContext(CreateContextTypeValue.SMB2_CREATE_DURABLE_HANDLE_RECONNECT);
            #endregion

            Smb2FunctionalClient prepareClient = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);

            Guid clientGuid = Guid.NewGuid();
            string fileName = "ResilientHandle_" + Guid.NewGuid() + ".txt";
            FILEID fileId;

            // Open file & Resiliency request
            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Create resilient handle to file '{0}' and timeout is {1} seconds", fileName, 0);
            OpenFileAndResilientRequest(
                prepareClient,
                clientGuid,
                fileName,
                0, // convert second to millisecond
                out fileId);

            /// Open.ResiliencyTimeout SHOULD be set to an implementation-specific value.<294>
            uint timeout = DEFAULT_RESILIENT_TIMEOUT_IN_SECONDS;
            if (TestConfig.Platform == Platform.WindowsServer2012)
            {
                /// <294> Section 3.3.5.15.9: Windows 7 and Windows Server 2008 R2 servers keep the resilient
                /// handle open indefinitely when the requested Timeout value is equal to zero.
                /// Windows 8 and Windows Server 2012 servers set a constant value of 120 seconds.
                timeout = DEFAULT_RESILIENT_TIMEOUT_IN_SECONDS;
            }
            else
            {
                timeout = testConfig.DefaultResiliencyTimeoutInSecond;
            }
            BaseTestSite.Log.Add(
                LogEntryKind.Debug,
                "Server should set the timeout of resilient handle to implementation-specific timeout {0} seconds", timeout);

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Disconnect the client to start the Resilient Open Scavenger Timer on server");
            prepareClient.Disconnect();

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Wait {0} seconds before Resilient Open Scavenger Timer expired.", timeout - 1);

            Thread.Sleep(TimeSpan.FromSeconds(timeout - 1));

            Smb2FunctionalClient reconnectClient = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);

            BaseTestSite.Log.Add(
                LogEntryKind.TestStep,
                "Re-establish Resilient Open, verify the returned status is STATUS_SUCCESS.");
            ReconnectResilientHandle(
                reconnectClient,
                clientGuid,
                fileName,
                fileId,
                NtStatus.STATUS_SUCCESS,
                "Reconnect resilient handle should be successful.");

            // clean
            reconnectClient.Disconnect();
        }
        public void PrepareOpen(
            ModelDialectRevision dialect,
            AppInstanceIdType appInstanceIdType,
            CreateType createType)
        {
            // Connect, Negotiate, SessionSetup, TreeConnect
            prepareClient = new Smb2FunctionalClient(testConfig.Timeout, testConfig, this.Site);
            this.connection_ClientGuid = Guid.NewGuid();
            clientDialect = dialect;
            ConnectToShare(clientDialect, prepareClient, connection_ClientGuid, testConfig.BasicFileShare, out treeConnect_TreeId);

            // Create
            this.fileName = "AppInstanceIdModel_" + Guid.NewGuid();
            Smb2CreateContextResponse[] createContextResponse;

            prepareClient.Create(
                this.treeConnect_TreeId,
                this.fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out this.open_FileId,
                out createContextResponse,
                createContexts: CreateContexts(appInstanceIdType, createType, true),
                shareAccess:ShareAccess_Values.NONE);

            if (createType == CreateType.CreateDurableThenDisconnect)
            {
                prepareClient.Disconnect();
            }
        }
        private void Compound_RelatedRequests(string fileName, bool isEncrypted)
        {
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Initialize the test client.");
            Smb2FunctionalClient client = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            uint treeId;
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Connect to the SMB2 basic share by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT.");
            ConnectToShare(client, out treeId);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Construct Create packet.");
            Smb2CreateRequestPacket createPacket = ConstructCreatePacket(client.SessionId, treeId, fileName);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Construct Write packet, flag FLAGS_RELATED_OPERATIONS is set.");
            Smb2WriteRequestPacket writePacket = ConstructRelatedWritePacket();

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Construct Close packet, flag FLAGS_RELATED_OPERATIONS is set.");
            Smb2CloseRequestPacket closePacket = ConstructRelatedClosePacket();

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Send {0}compounded Create, Write and Close requests to SUT.", isEncrypted ? "encrypted " : "");
            List<Smb2SinglePacket> requestPackets = new List<Smb2SinglePacket>();
            requestPackets.Add(createPacket);
            requestPackets.Add(writePacket);
            requestPackets.Add(closePacket);

            if (isEncrypted)
            {
                // Enable encryption
                client.EnableSessionSigningAndEncryption(enableSigning: testConfig.SendSignedRequest, enableEncryption: true);
            }
            List<Smb2SinglePacket> responsePackets = client.SendAndReceiveCompoundPacket(requestPackets);

            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Verify responses to the compounded request.");
            foreach (var responsePacket in responsePackets)
            {
                if (TestConfig.Platform == Platform.WindowsServer2016 && responsePacket.Header.Status != Smb2Status.STATUS_SUCCESS)
                {

                }
                else
                {
                    BaseTestSite.Assert.AreEqual(
                        Smb2Status.STATUS_SUCCESS,
                        responsePacket.Header.Status,
                        "{0} should succeed, actual status is {1}", responsePacket.Header.Command, Smb2Status.GetStatusCode(responsePacket.Header.Status));
                }
            }

            client.TreeDisconnect(treeId);
            client.LogOff();
            client.Disconnect();
        }
 private void Logoff(Smb2FunctionalClient client)
 {
     client.LogOff();
     client.Disconnect();
 }
        protected void CreateNewFile(string sharePath, string fileName)
        {
            Smb2FunctionalClient clientAdmin;
            clientAdmin = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            clientAdmin.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress);
            uint treeId;
            ConnectToShare(clientAdmin, TestConfig.AccountCredential, sharePath, out treeId);

            FILEID fileId;
            Smb2CreateContextResponse[] createContextResponses;
            clientAdmin.Create(
                treeId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                out fileId,
                out createContextResponses,
                accessMask: AccessMask.FILE_READ_DATA | AccessMask.FILE_WRITE_DATA |
                            AccessMask.FILE_APPEND_DATA | AccessMask.FILE_READ_EA |
                            AccessMask.FILE_WRITE_EA | AccessMask.READ_CONTROL |
                            AccessMask.WRITE_DAC | AccessMask.FILE_READ_ATTRIBUTES |
                            AccessMask.FILE_WRITE_ATTRIBUTES | AccessMask.SYNCHRONIZE,
                shareAccess: ShareAccess_Values.NONE,
                createDisposition: CreateDisposition_Values.FILE_CREATE);
            clientAdmin.Close(treeId, fileId);
            clientAdmin.TreeDisconnect(treeId);
            clientAdmin.Disconnect();
        }
        protected void DeleteExistingFile(string sharePath, string fileName)
        {
            Smb2FunctionalClient clientAdmin;
            clientAdmin = new Smb2FunctionalClient(TestConfig.Timeout, TestConfig, BaseTestSite);
            clientAdmin.ConnectToServer(TestConfig.UnderlyingTransport, TestConfig.SutComputerName, TestConfig.SutIPAddress);
            uint treeId;
            ConnectToShare(clientAdmin, TestConfig.AccountCredential, sharePath, out treeId);

            FILEID fileId;
            Smb2CreateContextResponse[] createContextResponses;
            clientAdmin.Create(
                treeId,
                fileName,
                CreateOptions_Values.FILE_NON_DIRECTORY_FILE | CreateOptions_Values.FILE_DELETE_ON_CLOSE,
                out fileId,
                out createContextResponses,
                accessMask: AccessMask.FILE_READ_ATTRIBUTES | AccessMask.DELETE,
                shareAccess: ShareAccess_Values.FILE_SHARE_DELETE,
                createDisposition: CreateDisposition_Values.FILE_OPEN);
            clientAdmin.Close(treeId, fileId);
            clientAdmin.TreeDisconnect(treeId);
            clientAdmin.Disconnect();
        }
        private void FileServerFailoverTest(string server, FileServerType fsType, bool reconnectWithoutFailover = false)
        {
            int ret = 0;
            uint callId = 0;
            IPAddress currentAccessIpAddr = null;
            WITNESS_INTERFACE_INFO registerInterface = new WITNESS_INTERFACE_INFO();
            WITNESS_INTERFACE_LIST interfaceList = new WITNESS_INTERFACE_LIST();

            currentAccessIpAddr = SWNTestUtility.GetCurrentAccessIP(server);
            BaseTestSite.Log.Add(LogEntryKind.Debug, "Get current file server IP: {0}.", currentAccessIpAddr);

            #region Register SWN witness
            if (witnessType == WitnessType.SwnWitness)
            {
                if (TestConfig.IsWindowsPlatform && fsType == FileServerType.ScaleOutFileServer)
                {
                    // Windows Server: when stopping a non-owner node of ScaleOutFS, no notication will be sent by SMB witness.
                    // So get one IP of the owner node of ScaleOutFS to access.
                    string resourceOwnerNode = sutController.GetClusterResourceOwner(server);
                    IPAddress[] ownerIpList = Dns.GetHostEntry(resourceOwnerNode).AddressList;
                    foreach (var ip in ownerIpList)
                    {
                        BaseTestSite.Log.Add(LogEntryKind.Debug, "Owner IP: {0}", ip);
                    }
                    if (!ownerIpList.Contains(currentAccessIpAddr))
                    {
                        currentAccessIpAddr = null;
                        IPAddress[] accessIpList = Dns.GetHostEntry(server).AddressList;
                        foreach (var ip in accessIpList)
                        {
                            if (ownerIpList.Contains(ip))
                            {
                                currentAccessIpAddr = ip;
                                break;
                            }
                        }
                        BaseTestSite.Assert.IsNotNull(currentAccessIpAddr, "IP should not be null.");
                        BaseTestSite.Log.Add(LogEntryKind.Debug, "Get the owner IP {0} as file server IP.", currentAccessIpAddr);
                    }

                    DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForInterface, currentAccessIpAddr,
                        TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage,
                        TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout, resourceOwnerNode), TestConfig.FailoverTimeout,
                        "Retry BindServer until succeed within timeout span");
                }
                else
                {
                    DoUntilSucceed(() => SWNTestUtility.BindServer(swnClientForInterface, currentAccessIpAddr,
                        TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword, TestConfig.DefaultSecurityPackage,
                        TestConfig.DefaultRpceAuthenticationLevel, TestConfig.Timeout, server), TestConfig.FailoverTimeout,
                        "Retry BindServer until succeed within timeout span");
                }

                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.");

                SWNTestUtility.GetRegisterInterface(interfaceList, out registerInterface);

                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, registerInterface.InterfaceGroupName), TestConfig.FailoverTimeout,
                    "Retry BindServer until succeed within timeout span");

                string clientName = Guid.NewGuid().ToString();

                BaseTestSite.Log.Add(LogEntryKind.Debug, "Register witness:");
                BaseTestSite.Log.Add(LogEntryKind.Debug, "\tNetName: {0}", SWNTestUtility.GetPrincipleName(TestConfig.DomainName, server));
                BaseTestSite.Log.Add(LogEntryKind.Debug, "\tIPAddress: {0}", currentAccessIpAddr.ToString());
                BaseTestSite.Log.Add(LogEntryKind.Debug, "\tClient Name: {0}", clientName);

                ret = swnClientForWitness.WitnessrRegister(SwnVersion.SWN_VERSION_1, SWNTestUtility.GetPrincipleName(TestConfig.DomainName, server),
                    currentAccessIpAddr.ToString(), clientName, out pContext);
                BaseTestSite.Assert.AreEqual<SwnErrorCode>(
                    SwnErrorCode.ERROR_SUCCESS,
                    (SwnErrorCode)ret,
                    "WitnessrRegister returns with result code = 0x{0:x8}", ret);
                BaseTestSite.Assert.IsNotNull(
                    pContext,
                    "Expect pContext is not null.");

                callId = swnClientForWitness.WitnessrAsyncNotify(pContext);
                BaseTestSite.Assert.AreNotEqual<uint>(
                    0,
                    callId,
                    "WitnessrAsyncNotify returns callId = {0}", callId);
            }
            #endregion

            #region Create a file and write content
            string uncSharePath = Smb2Utility.GetUncPath(server, TestConfig.ClusteredFileShare);
            string content = Smb2Utility.CreateRandomString(TestConfig.WriteBufferLengthInKb);
            string testDirectory = CreateTestDirectory(uncSharePath);
            string file = Path.Combine(testDirectory, Guid.NewGuid().ToString());
            Guid clientGuid = Guid.NewGuid();
            Guid createGuid = Guid.NewGuid();

            DoUntilSucceed(() => WriteContentBeforeFailover(fsType, server, currentAccessIpAddr, uncSharePath, file, content, clientGuid, createGuid),
                    TestConfig.FailoverTimeout,
                    "Before failover, retry Write content until succeed within timeout span.");
            #endregion

            #region Disable accessed node

            if (TestConfig.IsWindowsPlatform)
            {
                AssignCurrentAccessNode(server, fsType, currentAccessIpAddr);
            }

            if (!reconnectWithoutFailover)
            {
                BaseTestSite.Log.Add(
                    LogEntryKind.TestStep,
                    "Disable owner node for general file server or the node currently provides the access for scale-out file server.");
                FailoverServer(currentAccessIpAddr, server, fsType);
            }

            #endregion

            #region Wait for available server
            BaseTestSite.Log.Add(LogEntryKind.TestStep, "Wait for available server.");
            if (witnessType == WitnessType.None)
            {
                if (fsType == FileServerType.GeneralFileServer)
                {
                    currentAccessIpAddr = null;
                    IPAddress[] accessIpList = Dns.GetHostEntry(server).AddressList;
                    DoUntilSucceed(() =>
                    {
                        foreach (IPAddress ipAddress in accessIpList)
                        {
                            Smb2FunctionalClient pingClient = new Smb2FunctionalClient(TestConfig.FailoverTimeout, TestConfig, BaseTestSite);

                            try
                            {
                                pingClient.ConnectToServerOverTCP(ipAddress);
                                pingClient.Disconnect();
                                pingClient = null;

                                currentAccessIpAddr = ipAddress;
                                return true;
                            }
                            catch
                            {
                            }
                        }
                        return false;
                    }, TestConfig.FailoverTimeout, "Retry to ping to server until succeed within timeout span");
                }
                else
                {
                    currentAccessIpAddr = null;

                    IPAddress[] accessIpList = Dns.GetHostEntry(server).AddressList;
                    foreach (IPAddress ipAddress in accessIpList)
                    {
                        if (TestConfig.IsWindowsPlatform)
                        {
                            // When setting failover mode to StopNodeService for Windows, SMB2 servers on two nodes can still be accessed by the client.
                            // So the client needs to get the new node to access it after failover by comparing host name.
                            if (string.Compare(currentAccessNode, Dns.GetHostEntry(ipAddress).HostName, true) == 0)
                            {
                                continue;
                            }
                        }
                        Smb2FunctionalClient pingClient = new Smb2FunctionalClient(TestConfig.FailoverTimeout, TestConfig, BaseTestSite);

                        try
                        {
                            pingClient.ConnectToServerOverTCP(ipAddress);
                            pingClient.Disconnect();
                            pingClient = null;

                            currentAccessIpAddr = ipAddress;
                            break;
                        }
                        catch
                        {
                        }
                    }
                }
            }
            else if (witnessType == WitnessType.SwnWitness)
            {
                // Verifying for notification
                RESP_ASYNC_NOTIFY respNotify;
                do
                {
                    // Wait the notification
                    ret = swnClientForWitness.ExpectWitnessrAsyncNotify(callId, out respNotify);
                    BaseTestSite.Assert.AreEqual<SwnErrorCode>(
                        SwnErrorCode.ERROR_SUCCESS,
                        (SwnErrorCode)ret,
                        "ExpectWitnessrAsyncNotify returns with result code = 0x{0:x8}", ret);
                    SWNTestUtility.PrintNotification(respNotify);

                    RESOURCE_CHANGE[] resourceChangeList;
                    SwnUtility.ParseResourceChange(respNotify, out resourceChangeList);
                    BaseTestSite.Assert.AreEqual<uint>(0x00000001, respNotify.NumberOfMessages, "Expect NumberOfMessages is set to 1.");

                    if (resourceChangeList[0].ChangeType == (uint)SwnResourceChangeType.RESOURCE_STATE_AVAILABLE)
                    {
                        // Verify RESP_ASYNC_NOTIFY, the resource is available
                        SWNTestUtility.VerifyResourceChange(respNotify, SwnResourceChangeType.RESOURCE_STATE_AVAILABLE);
                        break;
                    }

                    // Verify RESP_ASYNC_NOTIFY, the resource is unavailable
                    SWNTestUtility.VerifyResourceChange(respNotify, SwnResourceChangeType.RESOURCE_STATE_UNAVAILABLE);

                    callId = swnClientForWitness.WitnessrAsyncNotify(pContext);
                    BaseTestSite.Assert.AreNotEqual<uint>(0, callId, "WitnessrAsyncNotify returns callId = {0}", callId);
                } while (true);

                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);

                if (fsType == FileServerType.ScaleOutFileServer)
                {
                    // For scale-out file server case, retrieve and use another access IP for connection
                    currentAccessIpAddr =
                        (registerInterface.Flags & (uint)SwnNodeFlagsValue.IPv4) != 0 ? new IPAddress(registerInterface.IPV4) : SWNTestUtility.ConvertIPV6(registerInterface.IPV6);
                }
            }
            #endregion

            #region Read content and close the file
            DoUntilSucceed(() => ReadContentAfterFailover(server, currentAccessIpAddr, uncSharePath, file, content, clientGuid, createGuid),
                    TestConfig.FailoverTimeout,
                    "After failover, retry Read content until succeed within timeout span.");
            #endregion
        }
        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 = Path.Combine(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: clientGuid,
                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
        }