File: System\ServiceModel\Security\SecuritySessionServerSettings.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//----------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.ServiceModel.Security
{
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IdentityModel.Claims;
    using System.IdentityModel.Selectors;
    using System.IdentityModel.Tokens;
    using System.Runtime;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.ServiceModel.Diagnostics;
    using System.ServiceModel.Dispatcher;
    using System.ServiceModel.Security.Tokens;
    using System.Threading;
    using System.Xml;
    using System.Globalization;
    using System.ServiceModel.Diagnostics.Application;
 
    // Please use 'sdv //depot/devdiv/private/indigo_xws/ndp/indigo/src/ServiceModel/System/ServiceModel/Security/SecuritySessionListenerFactory.cs' 
    // to see version history before the file was renamed
    // This class is named Settings since the only public APIs are for
    // settings; however, this class also manages all functionality
    // for session channels through internal APIs
    sealed class SecuritySessionServerSettings : IListenerSecureConversationSessionSettings, ISecurityCommunicationObject
    {
        internal const string defaultKeyRenewalIntervalString = "15:00:00";
        internal const string defaultKeyRolloverIntervalString = "00:05:00";
        internal const string defaultInactivityTimeoutString = "00:02:00";
 
        internal static readonly TimeSpan defaultKeyRenewalInterval = TimeSpan.Parse(defaultKeyRenewalIntervalString, CultureInfo.InvariantCulture);
        internal static readonly TimeSpan defaultKeyRolloverInterval = TimeSpan.Parse(defaultKeyRolloverIntervalString, CultureInfo.InvariantCulture);
        internal const bool defaultTolerateTransportFailures = true;
        internal const int defaultMaximumPendingSessions = 128;
        internal static readonly TimeSpan defaultInactivityTimeout = TimeSpan.Parse(defaultInactivityTimeoutString, CultureInfo.InvariantCulture);
 
        int maximumPendingSessions;
        Dictionary<UniqueId, IServerReliableChannelBinder> pendingSessions1;
        Dictionary<UniqueId, IServerReliableChannelBinder> pendingSessions2;
        IOThreadTimer inactivityTimer;
        TimeSpan inactivityTimeout;
        bool tolerateTransportFailures;
        TimeSpan maximumKeyRenewalInterval;
        TimeSpan keyRolloverInterval;
        int maximumPendingKeysPerSession;
        SecurityProtocolFactory sessionProtocolFactory;
        ICommunicationObject channelAcceptor;
        Dictionary<UniqueId, IServerSecuritySessionChannel> activeSessions;
        ChannelListenerBase securityChannelListener;
        ChannelBuilder channelBuilder;
        SecurityStandardsManager standardsManager;
        SecurityTokenParameters issuedTokenParameters;
        SecurityTokenAuthenticator sessionTokenAuthenticator;
        ISecurityContextSecurityTokenCache sessionTokenCache;
        SecurityTokenResolver sessionTokenResolver;
        WrapperSecurityCommunicationObject communicationObject;
        volatile bool acceptNewWork;
        MessageVersion messageVersion;
        TimeSpan closeTimeout;
        TimeSpan openTimeout;
        TimeSpan sendTimeout;
        Uri listenUri;
        SecurityListenerSettingsLifetimeManager settingsLifetimeManager;
        bool canRenewSession = true;
        object thisLock = new object();
 
        public SecuritySessionServerSettings()
        {
            activeSessions = new Dictionary<UniqueId, IServerSecuritySessionChannel>();
 
            this.maximumKeyRenewalInterval = defaultKeyRenewalInterval;
            this.maximumPendingKeysPerSession = 5;
            this.keyRolloverInterval = defaultKeyRolloverInterval;
            this.inactivityTimeout = defaultInactivityTimeout;
            this.tolerateTransportFailures = defaultTolerateTransportFailures;
            this.maximumPendingSessions = defaultMaximumPendingSessions;
            this.communicationObject = new WrapperSecurityCommunicationObject(this);
        }
 
        internal ChannelBuilder ChannelBuilder
        {
            get
            {
                return this.channelBuilder;
            }
            set
            {
                this.communicationObject.ThrowIfDisposedOrImmutable();
                this.channelBuilder = value;
            }
        }
 
        internal SecurityListenerSettingsLifetimeManager SettingsLifetimeManager
        {
            get
            {
                return this.settingsLifetimeManager;
            }
            set
            {
                this.communicationObject.ThrowIfDisposedOrImmutable();
                this.settingsLifetimeManager = value;
            }
        }
 
        internal ChannelListenerBase SecurityChannelListener
        {
            get
            {
                return this.securityChannelListener;
            }
            set
            {
                this.communicationObject.ThrowIfDisposedOrImmutable();
                this.securityChannelListener = value;
            }
        }
 
        Uri Uri
        {
            get
            {
                this.communicationObject.ThrowIfNotOpened();
                return this.listenUri;
            }
        }
 
        object ThisLock
        {
            get
            {
                return this.thisLock;
            }
        }
 
        public SecurityTokenAuthenticator SessionTokenAuthenticator
        {
            get
            {
                return this.sessionTokenAuthenticator;
            }
        }
 
        public ISecurityContextSecurityTokenCache SessionTokenCache
        {
            get
            {
                return this.sessionTokenCache;
            }
        }
 
        public SecurityTokenResolver SessionTokenResolver
        {
            get
            {
                return this.sessionTokenResolver;
            }
        }
 
        public SecurityTokenParameters IssuedSecurityTokenParameters
        {
            get
            {
                return this.issuedTokenParameters;
            }
            set
            {
                this.communicationObject.ThrowIfDisposedOrImmutable();
                this.issuedTokenParameters = value;
            }
        }
 
        public SecurityStandardsManager SecurityStandardsManager
        {
            get
            {
                return this.standardsManager;
            }
            set
            {
                this.communicationObject.ThrowIfDisposedOrImmutable();
                this.standardsManager = value;
            }
        }
 
        public bool TolerateTransportFailures
        {
            get
            {
                return this.tolerateTransportFailures;
            }
            set
            {
                this.communicationObject.ThrowIfDisposedOrImmutable();
                this.tolerateTransportFailures = value;
            }
        }
 
        public bool CanRenewSession
        {
            get
            {
                return this.canRenewSession;
            }
            set
            {
                this.canRenewSession = value;
            }
        }
 
        public int MaximumPendingSessions
        {
            get
            {
                return this.maximumPendingSessions;
            }
            set
            {
                if (value <= 0)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
                }
 
                this.communicationObject.ThrowIfDisposedOrImmutable();
                this.maximumPendingSessions = value;
            }
        }
 
        public TimeSpan InactivityTimeout
        {
            get
            {
                return this.inactivityTimeout;
            }
            set
            {
                if (value <= TimeSpan.Zero)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.TimeSpanMustbeGreaterThanTimeSpanZero)));
                }
 
                this.communicationObject.ThrowIfDisposedOrImmutable();
                this.inactivityTimeout = value;
            }
        }
 
        public TimeSpan MaximumKeyRenewalInterval
        {
            get
            {
                return this.maximumKeyRenewalInterval;
            }
            set
            {
                if (value <= TimeSpan.Zero)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.TimeSpanMustbeGreaterThanTimeSpanZero)));
                }
                this.communicationObject.ThrowIfDisposedOrImmutable();
                this.maximumKeyRenewalInterval = value;
            }
        }
 
        public TimeSpan KeyRolloverInterval
        {
            get
            {
                return this.keyRolloverInterval;
            }
            set
            {
                if (value <= TimeSpan.Zero)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.TimeSpanMustbeGreaterThanTimeSpanZero)));
                }
                this.communicationObject.ThrowIfDisposedOrImmutable();
                this.keyRolloverInterval = value;
            }
        }
 
        public int MaximumPendingKeysPerSession
        {
            get
            {
                return this.maximumPendingKeysPerSession;
            }
            set
            {
                if (value <= 0)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.ValueMustBeGreaterThanZero)));
                }
                this.communicationObject.ThrowIfDisposedOrImmutable();
                this.maximumPendingKeysPerSession = value;
            }
        }
 
        public SecurityProtocolFactory SessionProtocolFactory
        {
            get
            {
                return this.sessionProtocolFactory;
            }
            set
            {
                this.communicationObject.ThrowIfDisposedOrImmutable();
                this.sessionProtocolFactory = value;
            }
        }
 
        public MessageVersion MessageVersion
        {
            get
            {
                return this.messageVersion;
            }
        }
 
        public TimeSpan OpenTimeout
        {
            get
            {
                return this.openTimeout;
            }
        }
 
        public TimeSpan CloseTimeout
        {
            get
            {
                return this.closeTimeout;
            }
        }
 
        public TimeSpan SendTimeout
        {
            get
            {
                return this.sendTimeout;
            }
        }
 
 
        // ISecurityCommunicationObject members
        public TimeSpan DefaultOpenTimeout
        {
            get { return ServiceDefaults.OpenTimeout; }
        }
 
        public TimeSpan DefaultCloseTimeout
        {
            get { return ServiceDefaults.CloseTimeout; }
        }
 
        public IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return new OperationWithTimeoutAsyncResult(new OperationWithTimeoutCallback(this.OnClose), timeout, callback, state);
        }
 
        public IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return new OperationWithTimeoutAsyncResult(new OperationWithTimeoutCallback(this.OnOpen), timeout, callback, state);
        }
 
        public void OnClosed()
        {
        }
 
        public void OnClosing()
        {
        }
 
        public void OnEndClose(IAsyncResult result)
        {
            OperationWithTimeoutAsyncResult.End(result);
        }
 
        public void OnEndOpen(IAsyncResult result)
        {
            OperationWithTimeoutAsyncResult.End(result);
        }
 
        public void OnFaulted()
        {
        }
 
        public void OnOpened()
        {
        }
 
        public void OnOpening()
        {
        }
 
        public void OnAbort()
        {
            this.AbortPendingChannels();
            this.OnAbortCore();
        }
 
        public void OnClose(TimeSpan timeout)
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            this.ClosePendingChannels(timeoutHelper.RemainingTime());
            this.OnCloseCore(timeoutHelper.RemainingTime());
        }
 
        internal void Close(TimeSpan timeout)
        {
            this.communicationObject.Close(timeout);
        }
 
        internal IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return this.communicationObject.BeginClose(timeout, callback, state);
        }
 
        internal void EndClose(IAsyncResult result)
        {
            this.communicationObject.EndClose(result);
        }
 
        internal void Abort()
        {
            this.communicationObject.Abort();
        }
 
        internal void Open(TimeSpan timeout)
        {
            this.communicationObject.Open(timeout);
        }
 
        internal IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return this.communicationObject.BeginOpen(timeout, callback, state);
        }
 
        internal void EndOpen(IAsyncResult result)
        {
            this.communicationObject.EndOpen(result);
        }
 
        void OnCloseCore(TimeSpan timeout)
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            if (this.inactivityTimer != null)
            {
                this.inactivityTimer.Cancel();
            }
            if (this.sessionProtocolFactory != null)
            {
                this.sessionProtocolFactory.Close(false, timeoutHelper.RemainingTime());
            }
            if (this.sessionTokenAuthenticator != null)
            {
                SecurityUtils.CloseTokenAuthenticatorIfRequired(this.sessionTokenAuthenticator, timeoutHelper.RemainingTime());
            }
        }
 
        void OnAbortCore()
        {
            if (this.inactivityTimer != null)
            {
                this.inactivityTimer.Cancel();
            }
            if (this.sessionProtocolFactory != null)
            {
                this.sessionProtocolFactory.Close(true, TimeSpan.Zero);
            }
            if (this.sessionTokenAuthenticator != null)
            {
                SecurityUtils.AbortTokenAuthenticatorIfRequired(this.sessionTokenAuthenticator);
            }
        }
 
        void SetupSessionTokenAuthenticator()
        {
            RecipientServiceModelSecurityTokenRequirement requirement = new RecipientServiceModelSecurityTokenRequirement();
            this.issuedTokenParameters.InitializeSecurityTokenRequirement(requirement);
            requirement.KeyUsage = SecurityKeyUsage.Signature;
            requirement.ListenUri = this.listenUri;
            requirement.SecurityBindingElement = this.sessionProtocolFactory.SecurityBindingElement;
            requirement.SecurityAlgorithmSuite = this.sessionProtocolFactory.IncomingAlgorithmSuite;
            requirement.SupportSecurityContextCancellation = true;
            requirement.MessageSecurityVersion = sessionProtocolFactory.MessageSecurityVersion.SecurityTokenVersion;
            requirement.AuditLogLocation = sessionProtocolFactory.AuditLogLocation;
            requirement.SuppressAuditFailure = sessionProtocolFactory.SuppressAuditFailure;
            requirement.MessageAuthenticationAuditLevel = sessionProtocolFactory.MessageAuthenticationAuditLevel;
            requirement.Properties[ServiceModelSecurityTokenRequirement.MessageDirectionProperty] = MessageDirection.Input;
            if (sessionProtocolFactory.EndpointFilterTable != null)
            {
                requirement.Properties[ServiceModelSecurityTokenRequirement.EndpointFilterTableProperty] = sessionProtocolFactory.EndpointFilterTable;
            }
            this.sessionTokenAuthenticator = this.sessionProtocolFactory.SecurityTokenManager.CreateSecurityTokenAuthenticator(requirement, out this.sessionTokenResolver);
            if (!(this.sessionTokenAuthenticator is IIssuanceSecurityTokenAuthenticator))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecuritySessionRequiresIssuanceAuthenticator, typeof(IIssuanceSecurityTokenAuthenticator), this.sessionTokenAuthenticator.GetType())));
            }
            if (sessionTokenResolver == null || (!(sessionTokenResolver is ISecurityContextSecurityTokenCache)))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecuritySessionRequiresSecurityContextTokenCache, this.sessionTokenResolver.GetType(), typeof(ISecurityContextSecurityTokenCache))));
            }
            this.sessionTokenCache = (ISecurityContextSecurityTokenCache)this.sessionTokenResolver;
        }
 
 
        public void OnOpen(TimeSpan timeout)
        {
            if (this.sessionProtocolFactory == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecuritySessionProtocolFactoryShouldBeSetBeforeThisOperation)));
            }
            if (this.standardsManager == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecurityStandardsManagerNotSet, this.GetType())));
            }
            if (this.issuedTokenParameters == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.IssuedSecurityTokenParametersNotSet, this.GetType())));
            }
            if (this.maximumKeyRenewalInterval < this.keyRolloverInterval)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.KeyRolloverGreaterThanKeyRenewal)));
            }
            if (this.securityChannelListener == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecurityChannelListenerNotSet, this.GetType())));
            }
            if (this.settingsLifetimeManager == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecuritySettingsLifetimeManagerNotSet, this.GetType())));
            }
 
            this.messageVersion = this.channelBuilder.Binding.MessageVersion;
            this.listenUri = this.securityChannelListener.Uri;
            this.openTimeout = this.securityChannelListener.InternalOpenTimeout;
            this.closeTimeout = this.securityChannelListener.InternalCloseTimeout;
            this.sendTimeout = this.securityChannelListener.InternalSendTimeout;
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            this.pendingSessions1 = new Dictionary<UniqueId, IServerReliableChannelBinder>();
            this.pendingSessions2 = new Dictionary<UniqueId, IServerReliableChannelBinder>();
            if (this.inactivityTimeout < TimeSpan.MaxValue)
            {
                this.inactivityTimer = new IOThreadTimer(new Action<object>(this.OnTimer), this, false);
                this.inactivityTimer.Set(this.inactivityTimeout);
            }
            this.ConfigureSessionSecurityProtocolFactory();
            this.sessionProtocolFactory.Open(false, timeoutHelper.RemainingTime());
            SetupSessionTokenAuthenticator();
            ((IIssuanceSecurityTokenAuthenticator)this.sessionTokenAuthenticator).IssuedSecurityTokenHandler = this.OnTokenIssued;
            ((IIssuanceSecurityTokenAuthenticator)this.sessionTokenAuthenticator).RenewedSecurityTokenHandler = this.OnTokenRenewed;
            this.acceptNewWork = true;
            SecurityUtils.OpenTokenAuthenticatorIfRequired(this.sessionTokenAuthenticator, timeoutHelper.RemainingTime());
        }
 
        public void StopAcceptingNewWork()
        {
            this.acceptNewWork = false;
        }
 
        int GetPendingSessionCount()
        {
            return this.pendingSessions1.Count + this.pendingSessions2.Count + ((IInputQueueChannelAcceptor)this.channelAcceptor).PendingCount;
        }
 
        void AbortPendingChannels()
        {
            lock (ThisLock)
            {
                if (this.pendingSessions1 != null)
                {
                    foreach (IServerReliableChannelBinder pendingChannelBinder in pendingSessions1.Values)
                    {
                        pendingChannelBinder.Abort();
                    }
                }
                if (this.pendingSessions2 != null)
                {
                    foreach (IServerReliableChannelBinder pendingChannelBinder in pendingSessions2.Values)
                    {
                        pendingChannelBinder.Abort();
                    }
                }
            }
        }
 
        void ClosePendingChannels(TimeSpan timeout)
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            lock (ThisLock)
            {
                foreach (IServerReliableChannelBinder pendingChannelBinder in pendingSessions1.Values)
                {
                    pendingChannelBinder.Close(timeoutHelper.RemainingTime());
                }
                foreach (IServerReliableChannelBinder pendingChannelBinder in pendingSessions2.Values)
                {
                    pendingChannelBinder.Close(timeoutHelper.RemainingTime());
                }
            }
        }
 
        void ConfigureSessionSecurityProtocolFactory()
        {
            if (this.sessionProtocolFactory is SessionSymmetricMessageSecurityProtocolFactory)
            {
                AddressingVersion addressing = MessageVersion.Default.Addressing;
                if (this.channelBuilder != null)
                {
                    MessageEncodingBindingElement encoding = this.channelBuilder.Binding.Elements.Find<MessageEncodingBindingElement>();
                    if (encoding != null)
                    {
                        addressing = encoding.MessageVersion.Addressing;
                    }
                }
 
                if (addressing != AddressingVersion.WSAddressing10 && addressing != AddressingVersion.WSAddressingAugust2004)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new ProtocolException(SR.GetString(SR.AddressingVersionNotSupported, addressing)));
                }
 
                SessionSymmetricMessageSecurityProtocolFactory messagePf = (SessionSymmetricMessageSecurityProtocolFactory)this.sessionProtocolFactory;
                if (!messagePf.ApplyIntegrity || !messagePf.RequireIntegrity)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecuritySessionRequiresMessageIntegrity)));
                }
                MessagePartSpecification bodyPart = new MessagePartSpecification(true);
                messagePf.ProtectionRequirements.IncomingSignatureParts.AddParts(bodyPart, this.SecurityStandardsManager.SecureConversationDriver.CloseAction);
                messagePf.ProtectionRequirements.IncomingSignatureParts.AddParts(bodyPart, this.SecurityStandardsManager.SecureConversationDriver.CloseResponseAction);
                messagePf.ProtectionRequirements.OutgoingSignatureParts.AddParts(bodyPart, this.SecurityStandardsManager.SecureConversationDriver.CloseResponseAction);
                messagePf.ProtectionRequirements.OutgoingSignatureParts.AddParts(bodyPart, this.SecurityStandardsManager.SecureConversationDriver.CloseAction);
                messagePf.ProtectionRequirements.OutgoingSignatureParts.AddParts(bodyPart, addressing.FaultAction);
                messagePf.ProtectionRequirements.OutgoingSignatureParts.AddParts(bodyPart, addressing.DefaultFaultAction);
                messagePf.ProtectionRequirements.OutgoingSignatureParts.AddParts(bodyPart, DotNetSecurityStrings.SecuritySessionFaultAction);
                if (messagePf.ApplyConfidentiality)
                {
                    messagePf.ProtectionRequirements.OutgoingEncryptionParts.AddParts(MessagePartSpecification.NoParts, this.SecurityStandardsManager.SecureConversationDriver.CloseResponseAction);
                    messagePf.ProtectionRequirements.OutgoingEncryptionParts.AddParts(MessagePartSpecification.NoParts, this.SecurityStandardsManager.SecureConversationDriver.CloseAction);
                    messagePf.ProtectionRequirements.OutgoingEncryptionParts.AddParts(bodyPart, addressing.FaultAction);
                    messagePf.ProtectionRequirements.OutgoingEncryptionParts.AddParts(bodyPart, addressing.DefaultFaultAction);
                    messagePf.ProtectionRequirements.OutgoingEncryptionParts.AddParts(bodyPart, DotNetSecurityStrings.SecuritySessionFaultAction);
                }
                if (messagePf.RequireConfidentiality)
                {
                    messagePf.ProtectionRequirements.IncomingEncryptionParts.AddParts(MessagePartSpecification.NoParts, this.SecurityStandardsManager.SecureConversationDriver.CloseAction);
                    messagePf.ProtectionRequirements.IncomingEncryptionParts.AddParts(MessagePartSpecification.NoParts, this.SecurityStandardsManager.SecureConversationDriver.CloseResponseAction);
                }
                messagePf.SecurityTokenParameters = this.IssuedSecurityTokenParameters;
            }
            else if (this.sessionProtocolFactory is SessionSymmetricTransportSecurityProtocolFactory)
            {
                SessionSymmetricTransportSecurityProtocolFactory transportPf = (SessionSymmetricTransportSecurityProtocolFactory)this.sessionProtocolFactory;
                transportPf.AddTimestamp = true;
                transportPf.SecurityTokenParameters = this.IssuedSecurityTokenParameters;
                transportPf.SecurityTokenParameters.RequireDerivedKeys = false;
            }
            else
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
            }
        }
 
        internal IChannelAcceptor<TChannel> CreateAcceptor<TChannel>()
            where TChannel : class, IChannel
        {
            if (this.channelAcceptor != null)
            {
                Fx.Assert("SecuritySessionServerSettings.CreateAcceptor (this.channelAcceptor != null)");
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SSSSCreateAcceptor)));
            }
            object listenerSecurityState = this.sessionProtocolFactory.CreateListenerSecurityState();
            if (typeof(TChannel) == typeof(IReplySessionChannel))
            {
                this.channelAcceptor = new SecuritySessionChannelAcceptor<IReplySessionChannel>(this.SecurityChannelListener, listenerSecurityState);
            }
            else if (typeof(TChannel) == typeof(IDuplexSessionChannel))
            {
                this.channelAcceptor = new SecuritySessionChannelAcceptor<IDuplexSessionChannel>(this.SecurityChannelListener, listenerSecurityState);
            }
            else
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
            }
            return (IChannelAcceptor<TChannel>)this.channelAcceptor;
        }
 
        internal IChannelListener CreateInnerChannelListener()
        {
            if (this.ChannelBuilder.CanBuildChannelListener<IDuplexSessionChannel>())
            {
                return this.ChannelBuilder.BuildChannelListener<IDuplexSessionChannel>(new MatchNoneMessageFilter(), int.MinValue);
            }
            else if (this.ChannelBuilder.CanBuildChannelListener<IDuplexChannel>())
            {
                return this.ChannelBuilder.BuildChannelListener<IDuplexChannel>(new MatchNoneMessageFilter(), int.MinValue);
            }
            else if (this.ChannelBuilder.CanBuildChannelListener<IReplyChannel>())
            {
                return this.ChannelBuilder.BuildChannelListener<IReplyChannel>(new MatchNoneMessageFilter(), int.MinValue);
            }
            else
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
            }
        }
 
        void OnTokenRenewed(SecurityToken newToken, SecurityToken oldToken)
        {
            this.communicationObject.ThrowIfClosed();
            if (!this.acceptNewWork)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(SR.SecurityListenerClosing)));
            }
            SecurityContextSecurityToken newSecurityContextToken = newToken as SecurityContextSecurityToken;
            if (newSecurityContextToken == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.SessionTokenIsNotSecurityContextToken, newToken.GetType(), typeof(SecurityContextSecurityToken))));
            }
            SecurityContextSecurityToken oldSecurityContextToken = oldToken as SecurityContextSecurityToken;
            if (oldSecurityContextToken == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.SessionTokenIsNotSecurityContextToken, oldToken.GetType(), typeof(SecurityContextSecurityToken))));
            }
            IServerSecuritySessionChannel sessionChannel = this.FindSessionChannel(newSecurityContextToken.ContextId);
            if (sessionChannel == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.CannotFindSecuritySession, newSecurityContextToken.ContextId)));
            }
            sessionChannel.RenewSessionToken(newSecurityContextToken, oldSecurityContextToken);
        }
 
        IServerReliableChannelBinder CreateChannelBinder(SecurityContextSecurityToken sessionToken, EndpointAddress remoteAddress)
        {
            IServerReliableChannelBinder result = null;
            MessageFilter sctFilter = new SecuritySessionFilter(sessionToken.ContextId, this.sessionProtocolFactory.StandardsManager, (this.sessionProtocolFactory.SecurityHeaderLayout == SecurityHeaderLayout.Strict), this.SecurityStandardsManager.SecureConversationDriver.RenewAction.Value, this.SecurityStandardsManager.SecureConversationDriver.RenewResponseAction.Value);
            int sctPriority = Int32.MaxValue;
            TolerateFaultsMode faultMode = this.TolerateTransportFailures ? TolerateFaultsMode.Always : TolerateFaultsMode.Never;
            lock (ThisLock)
            {
                if (this.ChannelBuilder.CanBuildChannelListener<IDuplexSessionChannel>())
                {
                    result = ServerReliableChannelBinder<IDuplexSessionChannel>.CreateBinder(this.ChannelBuilder, remoteAddress, sctFilter, sctPriority, faultMode,
                        this.CloseTimeout, this.SendTimeout);
                }
                else if (this.ChannelBuilder.CanBuildChannelListener<IDuplexChannel>())
                {
                    result = ServerReliableChannelBinder<IDuplexChannel>.CreateBinder(this.ChannelBuilder, remoteAddress, sctFilter, sctPriority, faultMode,
                        this.CloseTimeout, this.SendTimeout);
                }
                else if (this.ChannelBuilder.CanBuildChannelListener<IReplyChannel>())
                {
                    result = ServerReliableChannelBinder<IReplyChannel>.CreateBinder(this.ChannelBuilder, remoteAddress, sctFilter, sctPriority, faultMode,
                        this.CloseTimeout, this.SendTimeout);
                }
            }
            if (result == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
            }
 
            result.Open(this.OpenTimeout);
            SessionInitiationMessageHandler handler = new SessionInitiationMessageHandler(result, this, sessionToken);
            handler.BeginReceive(TimeSpan.MaxValue);
            return result;
        }
 
        void OnTokenIssued(SecurityToken issuedToken, EndpointAddress tokenRequestor)
        {
            this.communicationObject.ThrowIfClosed();
            if (!this.acceptNewWork)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(SR.SecurityListenerClosing)));
            }
            SecurityContextSecurityToken issuedSecurityContextToken = issuedToken as SecurityContextSecurityToken;
            if (issuedSecurityContextToken == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.SessionTokenIsNotSecurityContextToken, issuedToken.GetType(), typeof(SecurityContextSecurityToken))));
            }
            IServerReliableChannelBinder channelBinder = CreateChannelBinder(issuedSecurityContextToken, tokenRequestor ?? EndpointAddress.AnonymousAddress);
            bool wasSessionAdded = false;
            try
            {
                this.AddPendingSession(issuedSecurityContextToken.ContextId, channelBinder);
                wasSessionAdded = true;
            }
            finally
            {
                if (!wasSessionAdded)
                {
                    channelBinder.Abort();
                }
            }
        }
 
        void OnTimer(object state)
        {
            if (this.communicationObject.State == CommunicationState.Closed
                || this.communicationObject.State == CommunicationState.Faulted)
            {
                return;
            }
            try
            {
                this.ClearPendingSessions();
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    throw;
                }
            }
            finally
            {
                if (this.communicationObject.State != CommunicationState.Closed
                    && this.communicationObject.State != CommunicationState.Closing
                    && this.communicationObject.State != CommunicationState.Faulted)
                {
                    this.inactivityTimer.Set(this.inactivityTimeout);
                }
            }
        }
 
        void AddPendingSession(UniqueId sessionId, IServerReliableChannelBinder channelBinder)
        {
            lock (ThisLock)
            {
                if ((GetPendingSessionCount() + 1) > this.MaximumPendingSessions)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QuotaExceededException(SR.GetString(SR.SecuritySessionLimitReached)));
                }
                if (this.pendingSessions1.ContainsKey(sessionId) || this.pendingSessions2.ContainsKey(sessionId))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.SecuritySessionAlreadyPending, sessionId)));
                }
                this.pendingSessions1.Add(sessionId, channelBinder);
            }
            SecurityTraceRecordHelper.TracePendingSessionAdded(sessionId, this.Uri);
            if (TD.SecuritySessionRatioIsEnabled())
            {
                TD.SecuritySessionRatio(GetPendingSessionCount(), this.MaximumPendingSessions);
            }
        }
 
        void TryCloseBinder(IServerReliableChannelBinder binder, TimeSpan timeout)
        {
            bool abortBinder = false;
            try
            {
                binder.Close(timeout);
            }
            catch (CommunicationException e)
            {
                abortBinder = true;
                DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
            }
            catch (TimeoutException e)
            {
                abortBinder = true;
 
                if (TD.CloseTimeoutIsEnabled())
                {
                    TD.CloseTimeout(e.Message);
                }
                DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
            }
            finally
            {
                if (abortBinder)
                {
                    binder.Abort();
                }
            }
        }
 
        // this method should be called by the timer under ThisLock
        void ClearPendingSessions()
        {
            lock (ThisLock)
            {
                if (this.pendingSessions1.Count == 0 && this.pendingSessions2.Count == 0)
                {
                    return;
                }
                foreach (UniqueId sessionId in this.pendingSessions2.Keys)
                {
                    IServerReliableChannelBinder channelBinder = this.pendingSessions2[sessionId];
                    try
                    {
                        TryCloseBinder(channelBinder, this.CloseTimeout);
                        this.SessionTokenCache.RemoveAllContexts(sessionId);
                    }
                    catch (CommunicationException e)
                    {
                        DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
                    }
                    catch (TimeoutException e)
                    {
                        if (TD.CloseTimeoutIsEnabled())
                        {
                            TD.CloseTimeout(e.Message);
                        }
                        DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
                    }
                    catch (ObjectDisposedException e)
                    {
                        DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
                    }
                    SecurityTraceRecordHelper.TracePendingSessionClosed(sessionId, this.Uri);
                }
                this.pendingSessions2.Clear();
                Dictionary<UniqueId, IServerReliableChannelBinder> temp = this.pendingSessions2;
                this.pendingSessions2 = this.pendingSessions1;
                this.pendingSessions1 = temp;
            }
        }
 
        bool RemovePendingSession(UniqueId sessionId)
        {
            bool result;
            lock (ThisLock)
            {
                if (this.pendingSessions1.ContainsKey(sessionId))
                {
                    this.pendingSessions1.Remove(sessionId);
                    result = true;
                }
                else if (pendingSessions2.ContainsKey(sessionId))
                {
                    this.pendingSessions2.Remove(sessionId);
                    result = true;
                }
                else
                {
                    result = false;
                }
            }
            if (result)
            {
                SecurityTraceRecordHelper.TracePendingSessionActivated(sessionId, this.Uri);
                if (TD.SecuritySessionRatioIsEnabled())
                {
                    TD.SecuritySessionRatio(GetPendingSessionCount(), this.MaximumPendingSessions);
                }
            }
            return result;
        }
 
        IServerSecuritySessionChannel FindSessionChannel(UniqueId sessionId)
        {
            IServerSecuritySessionChannel result;
            lock (ThisLock)
            {
                this.activeSessions.TryGetValue(sessionId, out result);
            }
            return result;
        }
 
        void AddSessionChannel(UniqueId sessionId, IServerSecuritySessionChannel channel)
        {
            lock (ThisLock)
            {
                this.activeSessions.Add(sessionId, channel);
            }
        }
 
        void RemoveSessionChannel(string sessionId)
        {
            RemoveSessionChannel(new UniqueId(sessionId));
        }
 
        void RemoveSessionChannel(UniqueId sessionId)
        {
            lock (ThisLock)
            {
                this.activeSessions.Remove(sessionId);
            }
            SecurityTraceRecordHelper.TraceActiveSessionRemoved(sessionId, this.Uri);
        }
 
        class SessionInitiationMessageHandler
        {
            static AsyncCallback receiveCallback = Fx.ThunkCallback(new AsyncCallback(ReceiveCallback));
            IServerReliableChannelBinder channelBinder;
            SecuritySessionServerSettings settings;
            SecurityContextSecurityToken sessionToken;
            bool processedInitiation = false;
 
            public SessionInitiationMessageHandler(IServerReliableChannelBinder channelBinder, SecuritySessionServerSettings settings, SecurityContextSecurityToken sessionToken)
            {
                this.channelBinder = channelBinder;
                this.settings = settings;
                this.sessionToken = sessionToken;
            }
 
            public IAsyncResult BeginReceive(TimeSpan timeout)
            {
                return this.channelBinder.BeginTryReceive(timeout, receiveCallback, this);
            }
 
            public void ProcessMessage(IAsyncResult result)
            {
                bool threwException = false;
                try
                {
                    RequestContext requestContext;
                    if (!this.channelBinder.EndTryReceive(result, out requestContext))
                    {
                        // we should never have timed out since the receive was called with an Infinite timeout
                        // if we did then do a BeginReceive and return
                        this.BeginReceive(TimeSpan.MaxValue);
                        return;
                    }
 
                    if (requestContext == null)
                    {
                        return;
                    }
 
                    Message message = requestContext.RequestMessage;
                    lock (this.settings.ThisLock)
                    {
                        if (this.settings.communicationObject.State != CommunicationState.Opened)
                        {
                            ((IDisposable)requestContext).Dispose();
                            return;
                        }
                        if (this.processedInitiation)
                        {
                            return;
                        }
                        this.processedInitiation = true;
                    }
                    if (!this.settings.RemovePendingSession(this.sessionToken.ContextId))
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new CommunicationException(SR.GetString(SR.SecuritySessionNotPending, this.sessionToken.ContextId)));
                    }
                    if (this.settings.channelAcceptor is SecuritySessionChannelAcceptor<IReplySessionChannel>)
                    {
                        SecuritySessionChannelAcceptor<IReplySessionChannel> replyAcceptor = ((SecuritySessionChannelAcceptor<IReplySessionChannel>)this.settings.channelAcceptor);
                        SecurityReplySessionChannel replySessionChannel = new SecurityReplySessionChannel(this.settings,
                            this.channelBinder,
                            sessionToken,
                            replyAcceptor.ListenerSecurityState,
                            this.settings.SettingsLifetimeManager);
                        settings.AddSessionChannel(this.sessionToken.ContextId, replySessionChannel);
                        replySessionChannel.StartReceiving(requestContext);
                        replyAcceptor.EnqueueAndDispatch(replySessionChannel);
                    }
                    else if (this.settings.channelAcceptor is SecuritySessionChannelAcceptor<IDuplexSessionChannel>)
                    {
                        SecuritySessionChannelAcceptor<IDuplexSessionChannel> duplexAcceptor = ((SecuritySessionChannelAcceptor<IDuplexSessionChannel>)this.settings.channelAcceptor);
                        ServerSecurityDuplexSessionChannel duplexSessionChannel = new ServerSecurityDuplexSessionChannel(this.settings,
                            this.channelBinder,
                            sessionToken,
                            duplexAcceptor.ListenerSecurityState,
                            this.settings.SettingsLifetimeManager);
                        settings.AddSessionChannel(this.sessionToken.ContextId, duplexSessionChannel);
                        duplexSessionChannel.StartReceiving(requestContext);
                        duplexAcceptor.EnqueueAndDispatch(duplexSessionChannel);
                    }
                    else
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new EndpointNotFoundException(SR.GetString(SR.SecuritySessionListenerNotFound, message.Headers.Action)));
                    }
                }
#pragma warning suppress 56500 // covered by FxCOP
                catch (Exception e)
                {
                    threwException = true;
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
                }
                finally
                {
                    if (threwException)
                    {
                        this.channelBinder.Abort();
                    }
                }
            }
 
            static void ReceiveCallback(IAsyncResult result)
            {
                ((SessionInitiationMessageHandler)result.AsyncState).ProcessMessage(result);
            }
        }
 
        interface IInputQueueChannelAcceptor
        {
            int PendingCount { get; }
        }
 
        class SecuritySessionChannelAcceptor<T> : InputQueueChannelAcceptor<T>, IInputQueueChannelAcceptor
            where T : class, IChannel
        {
            object listenerState;
 
            public SecuritySessionChannelAcceptor(ChannelListenerBase manager, object listenerState)
                : base(manager)
            {
                this.listenerState = listenerState;
            }
 
            public object ListenerSecurityState
            {
                get
                {
                    return this.listenerState;
                }
            }
 
            int IInputQueueChannelAcceptor.PendingCount
            {
                get { return this.PendingCount; }
            }
        }
 
        interface IServerSecuritySessionChannel
        {
            void RenewSessionToken(SecurityContextSecurityToken newToken, SecurityContextSecurityToken supportingToken);
        }
 
        abstract class ServerSecuritySessionChannel : ChannelBase, IServerSecuritySessionChannel
        {
            FaultCode renewFaultCode;
            FaultReason renewFaultReason;
            FaultCode sessionAbortedFaultCode;
            FaultReason sessionAbortedFaultReason;
            
            // Double-checked locking pattern requires volatile for read/write synchronization
            volatile bool areFaultCodesInitialized;
            IServerReliableChannelBinder channelBinder;
            SecurityProtocol securityProtocol;
            // This is used to sign outgoing messages
            SecurityContextSecurityToken currentSessionToken;
            UniqueId sessionId;
            // These are renewed tokens that have not been used as yet
            List<SecurityContextSecurityToken> futureSessionTokens;
            SecuritySessionServerSettings settings;
            RequestContext initialRequestContext;
            volatile bool isInputClosed;
            ThreadNeutralSemaphore receiveLock;
            MessageVersion messageVersion;
            SecurityListenerSettingsLifetimeManager settingsLifetimeManager;
            volatile bool hasSecurityStateReference;
 
            protected ServerSecuritySessionChannel(SecuritySessionServerSettings settings,
                IServerReliableChannelBinder channelBinder,
                SecurityContextSecurityToken sessionToken,
                object listenerSecurityProtocolState,
                SecurityListenerSettingsLifetimeManager settingsLifetimeManager)
                : base(settings.SecurityChannelListener)
            {
                this.settings = settings;
                this.channelBinder = channelBinder;
                this.messageVersion = settings.MessageVersion;
                this.channelBinder.Faulted += this.OnInnerFaulted;
                this.securityProtocol = this.Settings.SessionProtocolFactory.CreateSecurityProtocol(null, null, listenerSecurityProtocolState, true, TimeSpan.Zero);
                if (!(this.securityProtocol is IAcceptorSecuritySessionProtocol))
                {
                    Fx.Assert("Security protocol must be IAcceptorSecuritySessionProtocol.");
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ProtocolMisMatch, "IAcceptorSecuritySessionProtocol", this.GetType().ToString())));
                }
                this.currentSessionToken = sessionToken;
                this.sessionId = sessionToken.ContextId;
                this.futureSessionTokens = new List<SecurityContextSecurityToken>(1);
                ((IAcceptorSecuritySessionProtocol)this.securityProtocol).SetOutgoingSessionToken(sessionToken);
                ((IAcceptorSecuritySessionProtocol)this.securityProtocol).SetSessionTokenAuthenticator(this.sessionId, this.settings.SessionTokenAuthenticator, this.settings.SessionTokenResolver);
                this.settingsLifetimeManager = settingsLifetimeManager;
                this.receiveLock = new ThreadNeutralSemaphore(1);
            }
 
            protected SecuritySessionServerSettings Settings
            {
                get
                {
                    return this.settings;
                }
            }
 
            protected virtual bool CanDoSecurityCorrelation
            {
                get
                {
                    return false;
                }
            }
 
            internal IServerReliableChannelBinder ChannelBinder
            {
                get
                {
                    return this.channelBinder;
                }
            }
 
            internal TimeSpan InternalSendTimeout
            {
                get
                {
                    return this.DefaultSendTimeout;
                }
            }
 
            public EndpointAddress LocalAddress
            {
                get
                {
                    return this.channelBinder.LocalAddress;
                }
            }
 
            protected override void OnOpen(TimeSpan timeout)
            {
                this.securityProtocol.Open(timeout);
                if (this.CanDoSecurityCorrelation)
                {
                    ((IAcceptorSecuritySessionProtocol)this.securityProtocol).ReturnCorrelationState = true;
                }
                lock (ThisLock)
                {
                    // if an abort happened concurrently with the open, then return
                    if (this.State == CommunicationState.Closed || this.State == CommunicationState.Closing)
                    {
                        return;
                    }
                    this.settingsLifetimeManager.AddReference();
                    this.hasSecurityStateReference = true;
                }
            }
 
            protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
            {
                OnOpen(timeout);
                return new CompletedAsyncResult(callback, state);
            }
 
            protected override void OnEndOpen(IAsyncResult result)
            {
                CompletedAsyncResult.End(result);
            }
 
            protected virtual void AbortCore()
            {
                if (this.channelBinder != null)
                {
                    this.channelBinder.Abort();
                }
                if (this.securityProtocol != null)
                {
                    this.securityProtocol.Close(true, TimeSpan.Zero);
                }
                this.Settings.SessionTokenCache.RemoveAllContexts(this.currentSessionToken.ContextId);
                bool abortLifetimeManager = false;
                lock (ThisLock)
                {
                    if (hasSecurityStateReference)
                    {
                        abortLifetimeManager = true;
                        hasSecurityStateReference = false;
                    }
                }
                if (abortLifetimeManager)
                {
                    this.settingsLifetimeManager.Abort();
                }
            }
 
            protected virtual void CloseCore(TimeSpan timeout)
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 
                try
                {
                    if (this.channelBinder != null)
                    {
                        this.channelBinder.Close(timeoutHelper.RemainingTime());
                    }
                    if (this.securityProtocol != null)
                    {
                        this.securityProtocol.Close(false, timeoutHelper.RemainingTime());
                    }
                    bool closeLifetimeManager = false;
                    lock (ThisLock)
                    {
                        if (hasSecurityStateReference)
                        {
                            closeLifetimeManager = true;
                            hasSecurityStateReference = false;
                        }
                    }
                    if (closeLifetimeManager)
                    {
                        this.settingsLifetimeManager.Close(timeoutHelper.RemainingTime());
                    }
                }
                catch (CommunicationObjectAbortedException)
                {
                    if (this.State != CommunicationState.Closed)
                    {
                        throw;
                    }
                    // a parallel thread aborted the channel. Ignore the exception
                }
 
                this.Settings.SessionTokenCache.RemoveAllContexts(this.currentSessionToken.ContextId);
            }
 
            protected virtual IAsyncResult BeginCloseCore(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return new CloseCoreAsyncResult(this, timeout, callback, state);
            }
 
            protected virtual void EndCloseCore(IAsyncResult result)
            {
                CloseCoreAsyncResult.End(result);
            }
 
            protected abstract void OnCloseMessageReceived(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout);
 
            protected abstract void OnCloseResponseMessageReceived(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout);
 
            public void RenewSessionToken(SecurityContextSecurityToken newToken, SecurityContextSecurityToken supportingToken)
            {
                ThrowIfClosedOrNotOpen();
                // enforce that the token being renewed is the current session token
                lock (ThisLock)
                {
                    if (supportingToken.ContextId != this.currentSessionToken.ContextId || supportingToken.KeyGeneration != this.currentSessionToken.KeyGeneration)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.CurrentSessionTokenNotRenewed, supportingToken.KeyGeneration, this.currentSessionToken.KeyGeneration)));
                    }
                    if (this.futureSessionTokens.Count == this.Settings.MaximumPendingKeysPerSession)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.TooManyPendingSessionKeys)));
                    }
                    this.futureSessionTokens.Add(newToken);
                }
                SecurityTraceRecordHelper.TraceNewServerSessionKeyIssued(newToken, supportingToken, GetLocalUri());
            }
 
            protected Uri GetLocalUri()
            {
                if (this.channelBinder.LocalAddress == null)
                    return null;
                else
                    return this.channelBinder.LocalAddress.Uri;
            }
 
            void OnInnerFaulted(IReliableChannelBinder sender, Exception exception)
            {
                this.Fault(exception);
            }
 
            SecurityContextSecurityToken GetSessionToken(SecurityMessageProperty securityProperty)
            {
                SecurityContextSecurityToken sct = (securityProperty.ProtectionToken != null) ? securityProperty.ProtectionToken.SecurityToken as SecurityContextSecurityToken : null;
                if (sct != null && sct.ContextId == this.sessionId)
                {
                    return sct;
                }
                if (securityProperty.HasIncomingSupportingTokens)
                {
                    for (int i = 0; i < securityProperty.IncomingSupportingTokens.Count; ++i)
                    {
                        if (securityProperty.IncomingSupportingTokens[i].SecurityTokenAttachmentMode == SecurityTokenAttachmentMode.Endorsing)
                        {
                            sct = (securityProperty.IncomingSupportingTokens[i].SecurityToken as SecurityContextSecurityToken);
                            if (sct != null && sct.ContextId == this.sessionId)
                            {
                                return sct;
                            }
                        }
                    }
                }
                return null;
            }
 
            bool CheckIncomingToken(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
            {
                SecurityMessageProperty securityProperty = message.Properties.Security;
                // this is guaranteed to be non-null and matches the session ID since the binding checked it
                SecurityContextSecurityToken incomingToken = GetSessionToken(securityProperty);
                if (incomingToken == null)
                {
                    throw TraceUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.NoSessionTokenPresentInMessage)), message);
                }
                // the incoming token's key should have been issued within keyRenewalPeriod time in the past
                // if not, send back a renewal fault. However if this is a session close message then its ok to not require the client 
                // to renew the key in order to send the close.
                if (incomingToken.KeyExpirationTime < DateTime.UtcNow &&
                    message.Headers.Action != this.settings.SecurityStandardsManager.SecureConversationDriver.CloseAction.Value)
                {
                    if (this.settings.CanRenewSession)
                    {
                        SendRenewFault(requestContext, correlationState, timeout);
                        return false;
                    }
                    else
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new SessionKeyExpiredException(SR.GetString(SR.SecurityContextKeyExpired, incomingToken.ContextId, incomingToken.KeyGeneration)));
                    }
                }
                // this is a valid token. If it corresponds to a newly issued session token, make it the current
                // session token.
                lock (ThisLock)
                {
                    if (this.futureSessionTokens.Count > 0 && incomingToken.KeyGeneration != this.currentSessionToken.KeyGeneration)
                    {
                        bool changedCurrentSessionToken = false;
                        for (int i = 0; i < this.futureSessionTokens.Count; ++i)
                        {
                            if (futureSessionTokens[i].KeyGeneration == incomingToken.KeyGeneration)
                            {
                                // let the current token expire after KeyRollover time interval
                                DateTime keyRolloverTime = TimeoutHelper.Add(DateTime.UtcNow, this.settings.KeyRolloverInterval);
                                this.settings.SessionTokenCache.UpdateContextCachingTime(this.currentSessionToken, keyRolloverTime);
                                this.currentSessionToken = futureSessionTokens[i];
                                futureSessionTokens.RemoveAt(i);
                                ((IAcceptorSecuritySessionProtocol)this.securityProtocol).SetOutgoingSessionToken(this.currentSessionToken);
                                changedCurrentSessionToken = true;
                                break;
                            }
                        }
                        if (changedCurrentSessionToken)
                        {
                            SecurityTraceRecordHelper.TraceServerSessionKeyUpdated(this.currentSessionToken, GetLocalUri());
                            // remove all renewed tokens that will never be used.
                            for (int i = 0; i < futureSessionTokens.Count; ++i)
                            {
                                this.Settings.SessionTokenCache.RemoveContext(futureSessionTokens[i].ContextId, futureSessionTokens[i].KeyGeneration);
                            }
                            this.futureSessionTokens.Clear();
                        }
                    }
                }
 
                return true;
            }
 
            public void StartReceiving(RequestContext initialRequestContext)
            {
                if (this.initialRequestContext != null)
                {
                    Fx.Assert("The initial request context was already specified.");
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.AttemptToCreateMultipleRequestContext)));
                }
                this.initialRequestContext = initialRequestContext;
            }
 
            public RequestContext ReceiveRequest()
            {
                return this.ReceiveRequest(this.DefaultReceiveTimeout);
            }
 
            public RequestContext ReceiveRequest(TimeSpan timeout)
            {
                RequestContext requestContext;
                if (this.TryReceiveRequest(timeout, out requestContext))
                {
                    return requestContext;
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException());
                }
            }
 
            public IAsyncResult BeginReceiveRequest(AsyncCallback callback, object state)
            {
                return this.BeginReceiveRequest(this.DefaultReceiveTimeout, callback, state);
            }
 
            public IAsyncResult BeginReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return this.BeginTryReceiveRequest(timeout, callback, state);
            }
 
            public RequestContext EndReceiveRequest(IAsyncResult result)
            {
                RequestContext requestContext;
                if (this.EndTryReceiveRequest(result, out requestContext))
                {
                    return requestContext;
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException());
                }
            }
 
            public IAsyncResult BeginTryReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return new ReceiveRequestAsyncResult(this, timeout, callback, state);
            }
 
            public bool EndTryReceiveRequest(IAsyncResult result, out RequestContext requestContext)
            {
                return ReceiveRequestAsyncResult.EndAsRequestContext(result, out requestContext);
            }
 
            public bool TryReceiveRequest(TimeSpan timeout, out RequestContext requestContext)
            {
                ThrowIfFaulted();
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 
                if (!this.receiveLock.TryEnter(timeoutHelper.RemainingTime()))
                {
                    requestContext = null;
                    return false;
                }
                try
                {
                    while (true)
                    {
                        if (isInputClosed || this.State == CommunicationState.Faulted)
                        {
                            break;
                        }
 
                        // schedule another Receive if the timeout has not been reached
                        if (timeoutHelper.RemainingTime() == TimeSpan.Zero)
                        {
                            requestContext = null;
                            return false;
                        }
 
                        RequestContext innerRequestContext;
                        if (initialRequestContext != null)
                        {
                            innerRequestContext = initialRequestContext;
                            initialRequestContext = null;
                        }
                        else
                        {
                            if (!channelBinder.TryReceive(timeoutHelper.RemainingTime(), out innerRequestContext))
                            {
                                requestContext = null;
                                return false;
                            }
                        }
                        if (innerRequestContext == null)
                        {
                            // the channel could have been aborted or closed
                            break;
                        }
                        if (this.isInputClosed && innerRequestContext.RequestMessage != null)
                        {
                            Message message = innerRequestContext.RequestMessage;
                            try
                            {
                                ProtocolException error = ProtocolException.ReceiveShutdownReturnedNonNull(message);
                                throw TraceUtility.ThrowHelperWarning(error, message);
                            }
                            finally
                            {
                                message.Close();
                                innerRequestContext.Abort();
                            }
                        }
                        SecurityProtocolCorrelationState correlationState = null;
                        bool isSecurityProcessingFailure;
                        Message requestMessage = ProcessRequestContext(innerRequestContext, timeoutHelper.RemainingTime(), out correlationState, out isSecurityProcessingFailure);
                        if (requestMessage != null)
                        {
                            requestContext = new SecuritySessionRequestContext(innerRequestContext, requestMessage, correlationState, this);
                            return true;
                        }
                    }
                }
                finally
                {
                    this.receiveLock.Exit();
                }
                ThrowIfFaulted();
                requestContext = null;
                return true;
            }
 
            public Message Receive()
            {
                return this.Receive(this.DefaultReceiveTimeout);
            }
 
            public Message Receive(TimeSpan timeout)
            {
                Message message;
                if (this.TryReceive(timeout, out message))
                {
                    return message;
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException());
                }
            }
 
            public IAsyncResult BeginReceive(AsyncCallback callback, object state)
            {
                return this.BeginReceive(this.DefaultReceiveTimeout, callback, state);
            }
 
            public IAsyncResult BeginReceive(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return this.BeginTryReceive(timeout, callback, state);
            }
 
            public Message EndReceive(IAsyncResult result)
            {
                Message message;
                if (this.EndTryReceive(result, out message))
                {
                    return message;
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException());
                }
            }
 
            public IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return new ReceiveRequestAsyncResult(this, timeout, callback, state);
            }
 
            public bool EndTryReceive(IAsyncResult result, out Message message)
            {
                return ReceiveRequestAsyncResult.EndAsMessage(result, out message);
            }
 
            public bool TryReceive(TimeSpan timeout, out Message message)
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                RequestContext requestContext;
 
                if (this.TryReceiveRequest(timeoutHelper.RemainingTime(), out requestContext))
                {
                    if (requestContext != null)
                    {
                        message = requestContext.RequestMessage;
                        try
                        {
                            requestContext.Close(timeoutHelper.RemainingTime());
                        }
                        catch (TimeoutException e)
                        {
                            DiagnosticUtility.TraceHandledException(e, System.Diagnostics.TraceEventType.Information);
                        }
                    }
                    else
                    {
                        message = null;
                    }
                    return true;
                }
                else
                {
                    message = null;
                    return false;
                }
            }
 
            public override T GetProperty<T>()
            {
                if (typeof(T) == typeof(FaultConverter) && (this.channelBinder != null))
                {
                    return new SecurityChannelFaultConverter(this.channelBinder.Channel) as T;
                }
 
                T result = base.GetProperty<T>();
                if ((result == null) && (channelBinder != null) && (channelBinder.Channel != null))
                {
                    result = channelBinder.Channel.GetProperty<T>();
                }
 
                return result;
            }
 
            void SendFaultIfRequired(Exception e, Message unverifiedMessage, RequestContext requestContext, TimeSpan timeout)
            {
                try
                {
                    // return if the underlying channel does not implement IDuplexSession or IReply
                    if (!(this.channelBinder.Channel is IReplyChannel) && !(this.channelBinder.Channel is IDuplexSessionChannel))
                    {
                        return;
                    }
 
                    MessageFault fault = SecurityUtils.CreateSecurityMessageFault(e, this.securityProtocol.SecurityProtocolFactory.StandardsManager);
                    if (fault == null)
                    {
                        return;
                    }
                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                    try
                    {
                        using (Message faultMessage = Message.CreateMessage(unverifiedMessage.Version, fault, unverifiedMessage.Version.Addressing.DefaultFaultAction))
                        {
                            if (unverifiedMessage.Headers.MessageId != null)
                                faultMessage.InitializeReply(unverifiedMessage);
                            requestContext.Reply(faultMessage, timeoutHelper.RemainingTime());
                            requestContext.Close(timeoutHelper.RemainingTime());
                        }
                    }
                    catch (CommunicationException ex)
                    {
                        DiagnosticUtility.TraceHandledException(ex, TraceEventType.Information);
                    }
                    catch (TimeoutException ex)
                    {
                        if (TD.CloseTimeoutIsEnabled())
                        {
                            TD.CloseTimeout(e.Message);
                        }
                        DiagnosticUtility.TraceHandledException(ex, TraceEventType.Information);
                    }
                }
                finally
                {
                    unverifiedMessage.Close();
                    requestContext.Abort();
                }
            }
 
            bool ShouldWrapException(Exception e)
            {
                return ((e is FormatException) || (e is XmlException));
            }
 
            Message ProcessRequestContext(RequestContext requestContext, TimeSpan timeout, out SecurityProtocolCorrelationState correlationState, out bool isSecurityProcessingFailure)
            {
                correlationState = null;
                isSecurityProcessingFailure = false;
                if (requestContext == null)
                {
                    return null;
                }
 
                Message result = null;
                Message message = requestContext.RequestMessage;
                bool cleanupContextState = true;
                try
                {
                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                    Message unverifiedMessage = message;
                    Exception securityException = null;
                    try
                    {
                        correlationState = VerifyIncomingMessage(ref message, timeoutHelper.RemainingTime());
                    }
                    catch (MessageSecurityException e)
                    {
                        isSecurityProcessingFailure = true;
                        securityException = e;
                    }
                    if (securityException != null)
                    {
                        // SendFaultIfRequired closes the unverified message and context
                        SendFaultIfRequired(securityException, unverifiedMessage, requestContext, timeoutHelper.RemainingTime());
                        cleanupContextState = false;
                        return null;
                    }
                    else if (CheckIncomingToken(requestContext, message, correlationState, timeoutHelper.RemainingTime()))
                    {
                        if (message.Headers.Action == this.Settings.SecurityStandardsManager.SecureConversationDriver.CloseAction.Value)
                        {
                            SecurityTraceRecordHelper.TraceServerSessionCloseReceived(this.currentSessionToken, GetLocalUri());
                            this.isInputClosed = true;
                            // OnCloseMessageReceived is responsible for closing the message and requestContext if required.
                            this.OnCloseMessageReceived(requestContext, message, correlationState, timeoutHelper.RemainingTime());
                            correlationState = null;
                        }
                        else if (message.Headers.Action == this.Settings.SecurityStandardsManager.SecureConversationDriver.CloseResponseAction.Value)
                        {
                            SecurityTraceRecordHelper.TraceServerSessionCloseResponseReceived(this.currentSessionToken, GetLocalUri());
                            this.isInputClosed = true;
                            // OnCloseResponseMessageReceived is responsible for closing the message and requestContext if required.
                            this.OnCloseResponseMessageReceived(requestContext, message, correlationState, timeoutHelper.RemainingTime());
                            correlationState = null;
                        }
                        else
                        {
                            result = message;
                        }
                        cleanupContextState = false;
                    }
                }
#pragma warning suppress 56500 // covered by FxCOP
                catch (Exception e)
                {
                    if ((e is CommunicationException) || (e is TimeoutException) || (Fx.IsFatal(e)) || !ShouldWrapException(e))
                    {
                        throw;
                    }
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.MessageSecurityVerificationFailed), e));
                }
                finally
                {
                    if (cleanupContextState)
                    {
                        if (requestContext.RequestMessage != null)
                        {
                            requestContext.RequestMessage.Close();
                        }
                        requestContext.Abort();
                    }
                }
 
                return result;
            }
 
            internal void CheckOutgoingToken()
            {
                lock (ThisLock)
                {
                    if (this.currentSessionToken.KeyExpirationTime < DateTime.UtcNow)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SessionKeyExpiredException(SR.GetString(SR.SecuritySessionKeyIsStale)));
                    }
                }
            }
 
            internal void SecureApplicationMessage(ref Message message, TimeSpan timeout, SecurityProtocolCorrelationState correlationState)
            {
                ThrowIfFaulted();
                ThrowIfClosedOrNotOpen();
                CheckOutgoingToken();
                this.securityProtocol.SecureOutgoingMessage(ref message, timeout, correlationState);
            }
 
            internal SecurityProtocolCorrelationState VerifyIncomingMessage(ref Message message, TimeSpan timeout)
            {
                return this.securityProtocol.VerifyIncomingMessage(ref message, timeout, null);
            }
 
            void PrepareReply(Message request, Message reply)
            {
                if (request.Headers.ReplyTo != null)
                {
                    request.Headers.ReplyTo.ApplyTo(reply);
                }
                else if (request.Headers.From != null)
                {
                    request.Headers.From.ApplyTo(reply);
                }
                if (request.Headers.MessageId != null)
                {
                    reply.Headers.RelatesTo = request.Headers.MessageId;
                }
                TraceUtility.CopyActivity(request, reply);
                if (TraceUtility.PropagateUserActivity || TraceUtility.ShouldPropagateActivity)
                {
                    TraceUtility.AddActivityHeader(reply);
                }
            }
 
            protected void InitializeFaultCodesIfRequired()
            {
                if (!areFaultCodesInitialized)
                {
                    lock (ThisLock)
                    {
                        if (!areFaultCodesInitialized)
                        {
                            SecurityStandardsManager standardsManager = this.securityProtocol.SecurityProtocolFactory.StandardsManager;
                            SecureConversationDriver scDriver = standardsManager.SecureConversationDriver;
                            renewFaultCode = FaultCode.CreateSenderFaultCode(scDriver.RenewNeededFaultCode.Value, scDriver.Namespace.Value);
                            renewFaultReason = new FaultReason(SR.GetString(SR.SecurityRenewFaultReason), System.Globalization.CultureInfo.InvariantCulture);
                            sessionAbortedFaultCode = FaultCode.CreateSenderFaultCode(DotNetSecurityStrings.SecuritySessionAbortedFault, DotNetSecurityStrings.Namespace);
                            sessionAbortedFaultReason = new FaultReason(SR.GetString(SR.SecuritySessionAbortedFaultReason), System.Globalization.CultureInfo.InvariantCulture);
                            areFaultCodesInitialized = true;
                        }
                    }
                }
            }
 
            void SendRenewFault(RequestContext requestContext, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
            {
                Message message = requestContext.RequestMessage;
                try
                {
                    InitializeFaultCodesIfRequired();
                    MessageFault renewFault = MessageFault.CreateFault(renewFaultCode, renewFaultReason);
                    Message response;
                    if (message.Headers.MessageId != null)
                    {
                        response = Message.CreateMessage(message.Version, renewFault, DotNetSecurityStrings.SecuritySessionFaultAction);
                        response.InitializeReply(message);
                    }
                    else
                    {
                        response = Message.CreateMessage(message.Version, renewFault, DotNetSecurityStrings.SecuritySessionFaultAction);
                    }
                    try
                    {
                        PrepareReply(message, response);
                        TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                        this.securityProtocol.SecureOutgoingMessage(ref response, timeoutHelper.RemainingTime(), correlationState);
                        response.Properties.AllowOutputBatching = false;
                        SendMessage(requestContext, response, timeoutHelper.RemainingTime());
                    }
                    finally
                    {
                        response.Close();
                    }
                    SecurityTraceRecordHelper.TraceSessionRenewalFaultSent(this.currentSessionToken, GetLocalUri(), message);
                }
                catch (CommunicationException e)
                {
                    SecurityTraceRecordHelper.TraceRenewFaultSendFailure(this.currentSessionToken, GetLocalUri(), e);
                }
                catch (TimeoutException e)
                {
                    SecurityTraceRecordHelper.TraceRenewFaultSendFailure(this.currentSessionToken, GetLocalUri(), e);
                }
            }
 
            Message ProcessCloseRequest(Message request)
            {
                RequestSecurityToken rst;
                XmlDictionaryReader bodyReader = request.GetReaderAtBodyContents();
                using (bodyReader)
                {
                    rst = this.Settings.SecurityStandardsManager.TrustDriver.CreateRequestSecurityToken(bodyReader);
                    request.ReadFromBodyContentsToEnd(bodyReader);
                }
                if (rst.RequestType != null && rst.RequestType != this.Settings.SecurityStandardsManager.TrustDriver.RequestTypeClose)
                {
                    throw TraceUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.InvalidRstRequestType, rst.RequestType)), request);
                }
                if (rst.CloseTarget == null)
                {
                    throw TraceUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.NoCloseTargetSpecified)), request);
                }
                SecurityContextKeyIdentifierClause sctSkiClause = rst.CloseTarget as SecurityContextKeyIdentifierClause;
                if (sctSkiClause == null || !SecuritySessionSecurityTokenAuthenticator.DoesSkiClauseMatchSigningToken(sctSkiClause, request))
                {
                    throw TraceUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.BadCloseTarget, rst.CloseTarget)), request);
                }
                RequestSecurityTokenResponse rstr = new RequestSecurityTokenResponse(this.Settings.SecurityStandardsManager);
                rstr.Context = rst.Context;
                rstr.IsRequestedTokenClosed = true;
                rstr.MakeReadOnly();
                BodyWriter bodyWriter = rstr;
                if (this.Settings.SecurityStandardsManager.MessageSecurityVersion.TrustVersion == TrustVersion.WSTrust13)
                {
                    List<RequestSecurityTokenResponse> rstrList = new List<RequestSecurityTokenResponse>(1);
                    rstrList.Add(rstr);
                    RequestSecurityTokenResponseCollection rstrc = new RequestSecurityTokenResponseCollection(rstrList, this.Settings.SecurityStandardsManager);
                    bodyWriter = rstrc;
                }
                Message response = Message.CreateMessage(request.Version, ActionHeader.Create(this.Settings.SecurityStandardsManager.SecureConversationDriver.CloseResponseAction, request.Version.Addressing), bodyWriter);
                PrepareReply(request, response);
                return response;
            }
 
            internal Message CreateCloseResponse(Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
            {
                using (message)
                {
                    Message response = this.ProcessCloseRequest(message);
                    this.securityProtocol.SecureOutgoingMessage(ref response, timeout, correlationState);
                    response.Properties.AllowOutputBatching = false;
                    return response;
                }
            }
 
            internal void TraceSessionClosedResponseSuccess()
            {
                SecurityTraceRecordHelper.TraceSessionClosedResponseSent(this.currentSessionToken, GetLocalUri());
            }
 
            internal void TraceSessionClosedResponseFailure(Exception e)
            {
                SecurityTraceRecordHelper.TraceSessionClosedResponseSendFailure(this.currentSessionToken, GetLocalUri(), e);
            }
 
            internal void TraceSessionClosedSuccess()
            {
                SecurityTraceRecordHelper.TraceSessionClosedSent(this.currentSessionToken, GetLocalUri());
            }
 
            internal void TraceSessionClosedFailure(Exception e)
            {
                SecurityTraceRecordHelper.TraceSessionCloseSendFailure(this.currentSessionToken, GetLocalUri(), e);
            }
 
            // SendCloseResponse closes the message and underlying context if the operation completes successfully
            protected void SendCloseResponse(RequestContext requestContext, Message closeResponse, TimeSpan timeout)
            {
                try
                {
                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                    using (closeResponse)
                    {
                        SendMessage(requestContext, closeResponse, timeoutHelper.RemainingTime());
                    }
                    TraceSessionClosedResponseSuccess();
                }
                catch (CommunicationException e)
                {
                    TraceSessionClosedResponseFailure(e);
                }
                catch (TimeoutException e)
                {
                    TraceSessionClosedResponseFailure(e);
                }
            }
 
            // BeginSendCloseResponse closes the message and underlying context if the operation completes successfully
            internal IAsyncResult BeginSendCloseResponse(RequestContext requestContext, Message closeResponse, TimeSpan timeout, AsyncCallback callback, object state)
            {
                try
                {
                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                    return this.BeginSendMessage(requestContext, closeResponse, timeoutHelper.RemainingTime(), callback, state);
                }
                catch (CommunicationException e)
                {
                    TraceSessionClosedResponseFailure(e);
                }
                catch (TimeoutException e)
                {
                    TraceSessionClosedResponseFailure(e);
                }
                return new CompletedAsyncResult(callback, state);
            }
 
            // EndSendCloseResponse closes the message and underlying context if the operation completes successfully
            internal void EndSendCloseResponse(IAsyncResult result)
            {
                if (result is CompletedAsyncResult)
                {
                    CompletedAsyncResult.End(result);
                    return;
                }
                try
                {
                    this.EndSendMessage(result);
                }
                catch (CommunicationException e)
                {
                    TraceSessionClosedResponseFailure(e);
                }
                catch (TimeoutException e)
                {
                    TraceSessionClosedResponseFailure(e);
                }
            }
 
            internal Message CreateCloseMessage(TimeSpan timeout)
            {
                RequestSecurityToken rst = new RequestSecurityToken(this.Settings.SecurityStandardsManager);
                rst.RequestType = this.Settings.SecurityStandardsManager.TrustDriver.RequestTypeClose;
                rst.CloseTarget = this.Settings.IssuedSecurityTokenParameters.CreateKeyIdentifierClause(this.currentSessionToken, SecurityTokenReferenceStyle.External);
                rst.MakeReadOnly();
                Message closeMessage = Message.CreateMessage(this.messageVersion, ActionHeader.Create(this.Settings.SecurityStandardsManager.SecureConversationDriver.CloseAction, this.messageVersion.Addressing), rst);
                RequestReplyCorrelator.PrepareRequest(closeMessage);
                if (this.LocalAddress != null)
                {
                    closeMessage.Headers.ReplyTo = this.LocalAddress;
                }
                else
                {
                    if (closeMessage.Version.Addressing == AddressingVersion.WSAddressing10)
                    {
                        closeMessage.Headers.ReplyTo = null;
                    }
                    else if (closeMessage.Version.Addressing == AddressingVersion.WSAddressingAugust2004)
                    {
                        closeMessage.Headers.ReplyTo = EndpointAddress.AnonymousAddress;
                    }
                    else
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                            new ProtocolException(SR.GetString(SR.AddressingVersionNotSupported, closeMessage.Version.Addressing)));
                    }
                }
                this.securityProtocol.SecureOutgoingMessage(ref closeMessage, timeout, null);
                closeMessage.Properties.AllowOutputBatching = false;
                return closeMessage;
            }
 
            protected void SendClose(TimeSpan timeout)
            {
                try
                {
                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                    using (Message closeMessage = CreateCloseMessage(timeoutHelper.RemainingTime()))
                    {
                        SendMessage(null, closeMessage, timeoutHelper.RemainingTime());
                    }
                    TraceSessionClosedSuccess();
                }
                catch (CommunicationException e)
                {
                    TraceSessionClosedFailure(e);
                }
                catch (TimeoutException e)
                {
                    TraceSessionClosedFailure(e);
                }
            }
 
            internal IAsyncResult BeginSendClose(TimeSpan timeout, AsyncCallback callback, object state)
            {
                try
                {
                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                    Message closeMessage = CreateCloseMessage(timeoutHelper.RemainingTime());
                    return this.BeginSendMessage(null, closeMessage, timeoutHelper.RemainingTime(), callback, state);
                }
                catch (CommunicationException e)
                {
                    TraceSessionClosedFailure(e);
                }
                catch (TimeoutException e)
                {
                    TraceSessionClosedFailure(e);
                }
                return new CompletedAsyncResult(callback, state);
            }
 
            internal void EndSendClose(IAsyncResult result)
            {
                if (result is CompletedAsyncResult)
                {
                    CompletedAsyncResult.End(result);
                    return;
                }
                try
                {
                    this.EndSendMessage(result);
                }
                catch (CommunicationException e)
                {
                    TraceSessionClosedFailure(e);
                }
                catch (TimeoutException e)
                {
                    TraceSessionClosedFailure(e);
                }
            }
 
            protected void SendMessage(RequestContext requestContext, Message message, TimeSpan timeout)
            {
                if (this.channelBinder.CanSendAsynchronously)
                {
                    this.channelBinder.Send(message, timeout);
                }
                else if (requestContext != null)
                {
                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                    requestContext.Reply(message, timeoutHelper.RemainingTime());
                    requestContext.Close(timeoutHelper.RemainingTime());
                }
            }
 
            internal IAsyncResult BeginSendMessage(RequestContext requestContext, Message response, TimeSpan timeout, AsyncCallback callback, object state)
            {
                return new SendMessageAsyncResult(this, requestContext, response, timeout, callback, state);
            }
 
            internal void EndSendMessage(IAsyncResult result)
            {
                SendMessageAsyncResult.End(result);
            }
 
            class SendMessageAsyncResult : AsyncResult
            {
                static AsyncCallback sendCallback = Fx.ThunkCallback(new AsyncCallback(SendCallback));
                ServerSecuritySessionChannel sessionChannel;
                TimeoutHelper timeoutHelper;
                RequestContext requestContext;
                Message message;
 
                public SendMessageAsyncResult(ServerSecuritySessionChannel sessionChannel, RequestContext requestContext, Message message, TimeSpan timeout, AsyncCallback callback,
                    object state)
                    : base(callback, state)
                {
                    this.sessionChannel = sessionChannel;
                    this.timeoutHelper = new TimeoutHelper(timeout);
                    this.requestContext = requestContext;
                    this.message = message;
 
                    bool closeMessage = true;
                    try
                    {
                        IAsyncResult result = this.BeginSend(message);
                        if (!result.CompletedSynchronously)
                        {
                            closeMessage = false;
                            return;
                        }
                        this.EndSend(result);
                        closeMessage = false;
                    }
                    finally
                    {
                        if (closeMessage)
                        {
                            this.message.Close();
                        }
                    }
                    Complete(true);
                }
 
                IAsyncResult BeginSend(Message response)
                {
                    if (this.sessionChannel.channelBinder.CanSendAsynchronously)
                    {
                        return this.sessionChannel.channelBinder.BeginSend(response, timeoutHelper.RemainingTime(), sendCallback, this);
                    }
                    else if (requestContext != null)
                    {
                        return requestContext.BeginReply(response, sendCallback, this);
                    }
                    else
                    {
                        return new SendCompletedAsyncResult(sendCallback, this);
                    }
                }
 
                void EndSend(IAsyncResult result)
                {
                    try
                    {
                        if (result is SendCompletedAsyncResult)
                        {
                            SendCompletedAsyncResult.End(result);
                        }
                        else if (this.sessionChannel.channelBinder.CanSendAsynchronously)
                        {
                            this.sessionChannel.channelBinder.EndSend(result);
                        }
                        else
                        {
                            this.requestContext.EndReply(result);
                            this.requestContext.Close(timeoutHelper.RemainingTime());
                        }
                    }
                    finally
                    {
                        if (this.message != null)
                        {
                            this.message.Close();
                        }
                    }
                }
 
                static void SendCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    SendMessageAsyncResult self = (SendMessageAsyncResult)(result.AsyncState);
                    Exception completionException = null;
                    try
                    {
                        self.EndSend(result);
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        completionException = e;
                    }
                    self.Complete(false, completionException);
                }
 
                public static void End(IAsyncResult result)
                {
                    AsyncResult.End<SendMessageAsyncResult>(result);
                }
 
                class SendCompletedAsyncResult : CompletedAsyncResult
                {
                    public SendCompletedAsyncResult(AsyncCallback callback, object state)
                        : base(callback, state)
                    {
                    }
 
                    new public static void End(IAsyncResult result)
                    {
                        AsyncResult.End<SendCompletedAsyncResult>(result);
                    }
                }
            }
 
            class CloseCoreAsyncResult : AsyncResult
            {
                static AsyncCallback channelBinderCloseCallback = Fx.ThunkCallback(new AsyncCallback(ChannelBinderCloseCallback));
                static AsyncCallback settingsLifetimeManagerCloseCallback = Fx.ThunkCallback(new AsyncCallback(SettingsLifetimeManagerCloseCallback));
 
                ServerSecuritySessionChannel channel;
                TimeoutHelper timeoutHelper;
 
                public CloseCoreAsyncResult(ServerSecuritySessionChannel channel, TimeSpan timeout, AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    this.channel = channel;
                    this.timeoutHelper = new TimeoutHelper(timeout);
                    bool completeSelf = false;
                    if (this.channel.channelBinder != null)
                    {
                        try
                        {
                            IAsyncResult result = this.channel.channelBinder.BeginClose(timeoutHelper.RemainingTime(), channelBinderCloseCallback, this);
                            if (!result.CompletedSynchronously)
                            {
                                return;
                            }
                            this.channel.channelBinder.EndClose(result);
                        }
                        catch (CommunicationObjectAbortedException)
                        {
                            if (this.channel.State != CommunicationState.Closed)
                            {
                                throw;
                            }
                            else
                            {
                                completeSelf = true;
                            }
                        }
                    }
                    if (!completeSelf)
                    {
                        completeSelf = this.OnChannelBinderClosed();
                    }
                    if (completeSelf)
                    {
                        RemoveSessionTokenFromCache();
                        Complete(true);
                    }
                }
 
                void RemoveSessionTokenFromCache()
                {
                    this.channel.Settings.SessionTokenCache.RemoveAllContexts(this.channel.currentSessionToken.ContextId);
                }
 
                static void ChannelBinderCloseCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    CloseCoreAsyncResult self = (CloseCoreAsyncResult)(result.AsyncState);
                    bool completeSelf = false;
                    Exception completionException = null;
                    try
                    {
                        try
                        {
                            self.channel.channelBinder.EndClose(result);
                        }
                        catch (CommunicationObjectAbortedException)
                        {
                            if (self.channel.State != CommunicationState.Closed)
                            {
                                throw;
                            }
                            completeSelf = true;
                        }
                        if (!completeSelf)
                        {
                            completeSelf = self.OnChannelBinderClosed();
                        }
                        if (completeSelf)
                        {
                            self.RemoveSessionTokenFromCache();
                        }
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        completeSelf = true;
                        completionException = e;
                    }
                    if (completeSelf)
                    {
                        self.Complete(false, completionException);
                    }
                }
 
                bool OnChannelBinderClosed()
                {
                    try
                    {
                        if (this.channel.securityProtocol != null)
                        {
                            this.channel.securityProtocol.Close(false, timeoutHelper.RemainingTime());
                        }
                        bool closeLifetimeManager = false;
                        lock (this.channel.ThisLock)
                        {
                            if (this.channel.hasSecurityStateReference)
                            {
                                closeLifetimeManager = true;
                                this.channel.hasSecurityStateReference = false;
                            }
                        }
                        if (!closeLifetimeManager)
                        {
                            return true;
                        }
                        IAsyncResult result = this.channel.settingsLifetimeManager.BeginClose(timeoutHelper.RemainingTime(), settingsLifetimeManagerCloseCallback, this);
                        if (!result.CompletedSynchronously)
                        {
                            return false;
                        }
                        this.channel.settingsLifetimeManager.EndClose(result);
                        return true;
                    }
                    catch (CommunicationObjectAbortedException)
                    {
                        if (channel.State != CommunicationState.Closed)
                        {
                            throw;
                        }
                        return true;
                    }
                }
 
                static void SettingsLifetimeManagerCloseCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    CloseCoreAsyncResult self = (CloseCoreAsyncResult)(result.AsyncState);
                    bool removeSessionToken = false;
                    Exception completionException = null;
                    try
                    {
                        self.channel.settingsLifetimeManager.EndClose(result);
                        removeSessionToken = true;
                    }
                    catch (CommunicationObjectAbortedException)
                    {
                        if (self.channel.State != CommunicationState.Closed)
                        {
                            throw;
                        }
                        removeSessionToken = true;
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        completionException = e;
                    }
                    finally
                    {
                        if (removeSessionToken)
                        {
                            self.RemoveSessionTokenFromCache();
                        }
                    }
                    self.Complete(false, completionException);
                }
 
                public static void End(IAsyncResult result)
                {
                    AsyncResult.End<CloseCoreAsyncResult>(result);
                }
            }
 
            protected class SoapSecurityInputSession : ISecureConversationSession, IInputSession
            {
                ServerSecuritySessionChannel channel;
                UniqueId securityContextTokenId;
                EndpointIdentity remoteIdentity;
                SecurityKeyIdentifierClause sessionTokenIdentifier;
                SecurityStandardsManager standardsManager;
 
                public SoapSecurityInputSession(SecurityContextSecurityToken sessionToken,
                    SecuritySessionServerSettings settings, ServerSecuritySessionChannel channel)
                {
                    this.channel = channel;
                    this.securityContextTokenId = sessionToken.ContextId;
                    Claim identityClaim = SecurityUtils.GetPrimaryIdentityClaim(sessionToken.AuthorizationPolicies);
                    if (identityClaim != null)
                    {
                        this.remoteIdentity = EndpointIdentity.CreateIdentity(identityClaim);
                    }
                    this.sessionTokenIdentifier = settings.IssuedSecurityTokenParameters.CreateKeyIdentifierClause(sessionToken, SecurityTokenReferenceStyle.External);
                    this.standardsManager = settings.SessionProtocolFactory.StandardsManager;
                }
 
                public string Id
                {
                    get
                    {
                        return this.securityContextTokenId.ToString();
                    }
                }
 
                public EndpointIdentity RemoteIdentity
                {
                    get
                    {
                        return this.remoteIdentity;
                    }
                }
 
                public void WriteSessionTokenIdentifier(XmlDictionaryWriter writer)
                {
                    this.channel.ThrowIfDisposedOrNotOpen();
                    this.standardsManager.SecurityTokenSerializer.WriteKeyIdentifierClause(writer, this.sessionTokenIdentifier);
                }
 
                public bool TryReadSessionTokenIdentifier(XmlReader reader)
                {
                    this.channel.ThrowIfDisposedOrNotOpen();
                    if (!this.standardsManager.SecurityTokenSerializer.CanReadKeyIdentifierClause(reader))
                    {
                        return false;
                    }
                    SecurityContextKeyIdentifierClause incomingTokenIdentifier = this.standardsManager.SecurityTokenSerializer.ReadKeyIdentifierClause(reader) as SecurityContextKeyIdentifierClause;
                    return incomingTokenIdentifier != null && incomingTokenIdentifier.Matches(this.securityContextTokenId, null);
                }
            }
 
            class ReceiveRequestAsyncResult : AsyncResult
            {
                static FastAsyncCallback onWait = new FastAsyncCallback(OnWait);
                static AsyncCallback onReceive = Fx.ThunkCallback(new AsyncCallback(OnReceive));
                ServerSecuritySessionChannel channel;
                RequestContext innerRequestContext;
                Message requestMessage;
                SecurityProtocolCorrelationState correlationState;
                bool expired;
                TimeoutHelper timeoutHelper;
 
                public ReceiveRequestAsyncResult(ServerSecuritySessionChannel channel, TimeSpan timeout, AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    channel.ThrowIfFaulted();
                    this.timeoutHelper = new TimeoutHelper(timeout);
                    this.channel = channel;
                    if (!channel.receiveLock.EnterAsync(this.timeoutHelper.RemainingTime(), onWait, this))
                    {
                        return;
                    }
 
                    bool completeSelf = false;
                    bool throwing = true;
                    try
                    {
                        completeSelf = WaitComplete();
                        throwing = false;
                    }
                    finally
                    {
                        if (throwing)
                        {
                            this.channel.receiveLock.Exit();
                        }
                    }
 
                    if (completeSelf)
                    {
                        Complete(true);
                    }
                }
 
                static void OnWait(object state, Exception asyncException)
                {
                    ReceiveRequestAsyncResult self = (ReceiveRequestAsyncResult)state;
                    bool completeSelf = false;
                    Exception completionException = asyncException;
                    if (completionException != null)
                    {
                        completeSelf = true;
                    }
                    else
                    {
                        try
                        {
                            completeSelf = self.WaitComplete();
                        }
#pragma warning suppress 56500 // covered by FxCOP
                        catch (Exception e)
                        {
                            if (Fx.IsFatal(e))
                            {
                                throw;
                            }
 
                            completeSelf = true;
                            completionException = e;
                        }
                    }
 
                    if (completeSelf)
                    {
                        self.Complete(false, completionException);
                    }
                }
 
                bool WaitComplete()
                {
                    if (channel.isInputClosed)
                    {
                        return true;
                    }
                    channel.ThrowIfFaulted();
 
                    ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity &&
                        channel.initialRequestContext != null ?
                        TraceUtility.ExtractActivity(channel.initialRequestContext.RequestMessage) : null;
 
                    using (ServiceModelActivity.BoundOperation(activity))
                    {
                        if (channel.initialRequestContext != null)
                        {
                            innerRequestContext = channel.initialRequestContext;
                            channel.initialRequestContext = null;
                            bool isSecurityProcessingFailure;
                            requestMessage = channel.ProcessRequestContext(innerRequestContext, timeoutHelper.RemainingTime(), out this.correlationState, out isSecurityProcessingFailure);
                            if (requestMessage != null || channel.isInputClosed)
                            {
                                this.expired = false;
                                return true;
                            }
                        }
                        if (this.timeoutHelper.RemainingTime() == TimeSpan.Zero)
                        {
                            this.expired = true;
                            return true;
                        }
                        IAsyncResult result = channel.ChannelBinder.BeginTryReceive(this.timeoutHelper.RemainingTime(), onReceive, this);
                        if (!result.CompletedSynchronously)
                            return false;
 
                        return CompleteReceive(result);
                    }
                }
 
                bool CompleteReceive(IAsyncResult result)
                {
                    while (true)
                    {
                        this.expired = !channel.ChannelBinder.EndTryReceive(result, out this.innerRequestContext);
                        if (this.expired || innerRequestContext == null)
                            break;
 
                        bool isSecurityProcessingFailure;
                        requestMessage = channel.ProcessRequestContext(innerRequestContext, timeoutHelper.RemainingTime(), out this.correlationState, out isSecurityProcessingFailure);
                        if (requestMessage != null)
                        {
                            if (channel.isInputClosed)
                            {
                                ProtocolException error = ProtocolException.ReceiveShutdownReturnedNonNull(requestMessage);
                                try
                                {
                                    throw TraceUtility.ThrowHelperWarning(error, requestMessage);
                                }
                                finally
                                {
                                    requestMessage.Close();
                                    innerRequestContext.Abort();
                                }
                            }
                            break;
                        }
 
                        if (channel.isInputClosed || channel.State == CommunicationState.Faulted)
                            break;
 
                        // retry the receive unless the timeout is reached
                        if (this.timeoutHelper.RemainingTime() == TimeSpan.Zero)
                        {
                            this.expired = true;
                            break;
                        }
 
                        result = channel.ChannelBinder.BeginTryReceive(this.timeoutHelper.RemainingTime(), onReceive, this);
 
                        if (!result.CompletedSynchronously)
                            return false;
                    }
                    this.channel.ThrowIfFaulted();
                    return true;
                }
 
                new void Complete(bool synchronous)
                {
                    try
                    {
                        this.channel.receiveLock.Exit();
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
 
                        if (DiagnosticUtility.ShouldTraceWarning)
                        {
                            TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.AsyncCallbackThrewException, SR.GetString(SR.TraceCodeAsyncCallbackThrewException), e.ToString());
                        }
 
                    }
 
                    base.Complete(synchronous);
                }
 
                new void Complete(bool synchronous, Exception exception)
                {
                    try
                    {
                        this.channel.receiveLock.Exit();
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
 
                        if (DiagnosticUtility.ShouldTraceWarning)
                        {
                            TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.AsyncCallbackThrewException, SR.GetString(SR.TraceCodeAsyncCallbackThrewException), e.ToString());
                        }
 
                    }
 
                    base.Complete(synchronous, exception);
                }
 
                static ReceiveRequestAsyncResult End(IAsyncResult result)
                {
                    return AsyncResult.End<ReceiveRequestAsyncResult>(result);
                }
 
                public static bool EndAsMessage(IAsyncResult result, out Message message)
                {
                    ReceiveRequestAsyncResult receiveResult = End(result);
                    message = receiveResult.requestMessage;
                    // if the message is not null, then dispose the inner request context
                    // if the message is null its either a close or protocol fault in which case the request context
                    // will be closed by the channel
                    if (message != null)
                    {
                        if (receiveResult.innerRequestContext != null)
                        {
                            try
                            {
                                receiveResult.innerRequestContext.Close(receiveResult.timeoutHelper.RemainingTime());
                            }
                            catch (TimeoutException e)
                            {
                                DiagnosticUtility.TraceHandledException(e, System.Diagnostics.TraceEventType.Information);
                            }
                        }
                    }
                    return !receiveResult.expired;
                }
 
                public static bool EndAsRequestContext(IAsyncResult result, out RequestContext requestContext)
                {
                    ReceiveRequestAsyncResult receiveResult = End(result);
 
                    if (receiveResult.requestMessage == null)
                    {
                        requestContext = null;
                    }
                    else
                    {
                        requestContext = new SecuritySessionRequestContext(receiveResult.innerRequestContext, receiveResult.requestMessage, receiveResult.correlationState, receiveResult.channel);
                    }
 
                    return !receiveResult.expired;
                }
 
                static void OnReceive(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                        return;
 
                    ReceiveRequestAsyncResult self = (ReceiveRequestAsyncResult)result.AsyncState;
                    bool completeSelf = false;
                    Exception completionException = null;
                    try
                    {
                        completeSelf = self.CompleteReceive(result);
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
 
                        completeSelf = true;
                        completionException = e;
                    }
                    if (completeSelf)
                    {
                        self.Complete(false, completionException);
                    }
                }
            }
        }
 
        abstract class ServerSecuritySimplexSessionChannel : ServerSecuritySessionChannel
        {
            SoapSecurityInputSession session;
            bool receivedClose;
            bool canSendCloseResponse;
            bool sentCloseResponse;
            RequestContext closeRequestContext;
            Message closeResponse;
            InterruptibleWaitObject inputSessionClosedHandle = new InterruptibleWaitObject(false);
 
            public ServerSecuritySimplexSessionChannel(
                SecuritySessionServerSettings settings,
                IServerReliableChannelBinder channelBinder,
                SecurityContextSecurityToken sessionToken,
                object listenerSecurityState, SecurityListenerSettingsLifetimeManager settingsLifetimeManager)
                : base(settings, channelBinder, sessionToken, listenerSecurityState, settingsLifetimeManager)
            {
                this.session = new SoapSecurityInputSession(sessionToken, settings, this);
            }
 
            public IInputSession Session
            {
                get
                {
                    return this.session;
                }
            }
 
            void CleanupPendingCloseState()
            {
                lock (ThisLock)
                {
                    if (this.closeResponse != null)
                    {
                        this.closeResponse.Close();
                        this.closeResponse = null;
                    }
                    if (this.closeRequestContext != null)
                    {
                        this.closeRequestContext.Abort();
                        this.closeRequestContext = null;
                    }
                }
            }
 
            protected override void AbortCore()
            {
                base.AbortCore();
                this.Settings.RemoveSessionChannel(this.session.Id);
                CleanupPendingCloseState();
            }
 
            protected override void CloseCore(TimeSpan timeout)
            {
                base.CloseCore(timeout);
                this.inputSessionClosedHandle.Abort(this);
                this.Settings.RemoveSessionChannel(this.session.Id);
            }
 
            protected override void EndCloseCore(IAsyncResult result)
            {
                base.EndCloseCore(result);
                this.inputSessionClosedHandle.Abort(this);
                this.Settings.RemoveSessionChannel(this.session.Id);
            }
 
            protected override void OnAbort()
            {
                AbortCore();
                this.inputSessionClosedHandle.Abort(this);
            }
 
            protected override void OnFaulted()
            {
                this.AbortCore();
                this.inputSessionClosedHandle.Fault(this);
                base.OnFaulted();
            }
 
            bool ShouldSendCloseResponseOnClose(out RequestContext pendingCloseRequestContext, out Message pendingCloseResponse)
            {
                bool sendCloseResponse = false;
                lock (ThisLock)
                {
                    this.canSendCloseResponse = true;
                    if (!this.sentCloseResponse && this.receivedClose && this.closeResponse != null)
                    {
                        this.sentCloseResponse = true;
                        sendCloseResponse = true;
                        pendingCloseRequestContext = this.closeRequestContext;
                        pendingCloseResponse = this.closeResponse;
                        this.closeResponse = null;
                        this.closeRequestContext = null;
                    }
                    else
                    {
                        canSendCloseResponse = false;
                        pendingCloseRequestContext = null;
                        pendingCloseResponse = null;
                    }
                }
                return sendCloseResponse;
            }
 
            bool SendCloseResponseOnCloseIfRequired(TimeSpan timeout)
            {
                bool aborted = false;
                RequestContext pendingCloseRequestContext;
                Message pendingCloseResponse;
                bool sendCloseResponse = ShouldSendCloseResponseOnClose(out pendingCloseRequestContext, out pendingCloseResponse);
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                bool cleanupCloseState = true;
                if (sendCloseResponse)
                {
                    try
                    {
                        this.SendCloseResponse(pendingCloseRequestContext, pendingCloseResponse, timeoutHelper.RemainingTime());
                        this.inputSessionClosedHandle.Set();
                        cleanupCloseState = false;
                    }
                    catch (CommunicationObjectAbortedException)
                    {
                        if (this.State != CommunicationState.Closed)
                        {
                            throw;
                        }
                        aborted = true;
                    }
                    finally
                    {
                        if (cleanupCloseState)
                        {
                            if (pendingCloseResponse != null)
                            {
                                pendingCloseResponse.Close();
                            }
                            if (pendingCloseRequestContext != null)
                            {
                                pendingCloseRequestContext.Abort();
                            }
                        }
                    }
                }
 
                return aborted;
            }
 
            protected override void OnClose(TimeSpan timeout)
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 
                // send a close response if one was not sent yet
                bool wasAborted = SendCloseResponseOnCloseIfRequired(timeoutHelper.RemainingTime());
                if (wasAborted)
                {
                    return;
                }
 
                bool wasInputSessionClosed = this.WaitForInputSessionClose(timeoutHelper.RemainingTime(), out wasAborted);
                if (wasAborted)
                {
                    return;
                }
                if (!wasInputSessionClosed)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, timeoutHelper.OriginalTimeout)));
                }
                else
                {
                    this.CloseCore(timeoutHelper.RemainingTime());
                }
            }
 
            protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
            {
                RequestContext pendingCloseRequestContext;
                Message pendingCloseResponse;
                bool sendCloseResponse = ShouldSendCloseResponseOnClose(out pendingCloseRequestContext, out pendingCloseResponse);
                return new CloseAsyncResult(this, sendCloseResponse, pendingCloseRequestContext, pendingCloseResponse, timeout, callback, state);
            }
 
            protected override void OnEndClose(IAsyncResult result)
            {
                CloseAsyncResult.End(result);
            }
 
            bool WaitForInputSessionClose(TimeSpan timeout, out bool wasAborted)
            {
                Message message;
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                wasAborted = false;
                try
                {
                    if (this.TryReceive(timeoutHelper.RemainingTime(), out message))
                    {
                        if (message != null)
                        {
                            using (message)
                            {
                                ProtocolException error = ProtocolException.ReceiveShutdownReturnedNonNull(message);
                                throw TraceUtility.ThrowHelperWarning(error, message);
                            }
                        }
                        return this.inputSessionClosedHandle.Wait(timeoutHelper.RemainingTime(), false);
                    }
                }
                catch (CommunicationObjectAbortedException)
                {
                    if (this.State != CommunicationState.Closed)
                    {
                        throw;
                    }
                    wasAborted = true;
                }
                return false;
            }
 
            protected override void OnCloseResponseMessageReceived(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
            {
                // we dont expect a close-response for non-duplex security session
                message.Close();
                requestContext.Abort();
                this.Fault(new ProtocolException(SR.GetString(SR.UnexpectedSecuritySessionCloseResponse)));
            }
 
            protected override void OnCloseMessageReceived(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
            {
                if (this.State == CommunicationState.Created)
                {
                    Fx.Assert("ServerSecuritySimplexSessionChannel.OnCloseMessageReceived (this.State == Created)");
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ServerReceivedCloseMessageStateIsCreated, this.GetType().ToString())));
                }
 
                if (SendCloseResponseOnCloseReceivedIfRequired(requestContext, message, correlationState, timeout))
                {
                    this.inputSessionClosedHandle.Set();
                }
            }
 
            bool SendCloseResponseOnCloseReceivedIfRequired(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
            {
                bool sendCloseResponse = false;
                ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? TraceUtility.ExtractActivity(message) : null;
                bool cleanupContext = true;
                try
                {
                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                    Message localCloseResponse = null;
                    lock (ThisLock)
                    {
                        if (!this.receivedClose)
                        {
                            this.receivedClose = true;
                            localCloseResponse = CreateCloseResponse(message, correlationState, timeoutHelper.RemainingTime());
                            if (canSendCloseResponse)
                            {
                                this.sentCloseResponse = true;
                                sendCloseResponse = true;
                            }
                            else
                            {
                                // save the close requestContext to reply later
                                this.closeRequestContext = requestContext;
                                this.closeResponse = localCloseResponse;
                                cleanupContext = false;
                            }
                        }
                    }
                    if (sendCloseResponse)
                    {
                        this.SendCloseResponse(requestContext, localCloseResponse, timeoutHelper.RemainingTime());
                        cleanupContext = false;
                    }
                    else if (cleanupContext)
                    {
                        requestContext.Close(timeoutHelper.RemainingTime());
                        cleanupContext = false;
                    }
                    return sendCloseResponse;
                }
                finally
                {
                    message.Close();
                    if (cleanupContext)
                    {
                        requestContext.Abort();
                    }
                    if (DiagnosticUtility.ShouldUseActivity && (activity != null))
                    {
                        activity.Stop();
                    }
                }
            }
 
            class CloseAsyncResult : AsyncResult
            {
                static readonly AsyncCallback sendCloseResponseCallback = Fx.ThunkCallback(new AsyncCallback(SendCloseResponseCallback));
                static readonly AsyncCallback receiveCallback = Fx.ThunkCallback(new AsyncCallback(ReceiveCallback));
                static readonly AsyncCallback waitCallback = Fx.ThunkCallback(new AsyncCallback(WaitForInputSessionCloseCallback));
                static readonly AsyncCallback closeCoreCallback = Fx.ThunkCallback(new AsyncCallback(CloseCoreCallback));
 
                ServerSecuritySimplexSessionChannel sessionChannel;
                TimeoutHelper timeoutHelper;
                RequestContext closeRequestContext;
                Message closeResponse;
 
                public CloseAsyncResult(ServerSecuritySimplexSessionChannel sessionChannel, bool sendCloseResponse, RequestContext closeRequestContext, Message closeResponse, TimeSpan timeout, AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    this.timeoutHelper = new TimeoutHelper(timeout);
                    this.sessionChannel = sessionChannel;
                    this.closeRequestContext = closeRequestContext;
                    this.closeResponse = closeResponse;
                    bool wasChannelAborted = false;
                    bool completeSelf = this.OnSendCloseResponse(sendCloseResponse, out wasChannelAborted);
                    if (wasChannelAborted || completeSelf)
                    {
                        Complete(true);
                    }
                }
 
                bool OnSendCloseResponse(bool shouldSendCloseResponse, out bool wasChannelAborted)
                {
                    wasChannelAborted = false;
                    try
                    {
                        if (shouldSendCloseResponse)
                        {
                            bool cleanupCloseState = true;
                            try
                            {
                                IAsyncResult result = this.sessionChannel.BeginSendCloseResponse(closeRequestContext, closeResponse, timeoutHelper.RemainingTime(), sendCloseResponseCallback, this);
                                if (!result.CompletedSynchronously)
                                {
                                    cleanupCloseState = false;
                                    return false;
                                }
                                this.sessionChannel.EndSendCloseResponse(result);
                                this.sessionChannel.inputSessionClosedHandle.Set();
                            }
                            finally
                            {
                                if (cleanupCloseState)
                                {
                                    CleanupCloseState();
                                }
                            }
                        }
                    }
                    catch (CommunicationObjectAbortedException)
                    {
                        if (this.sessionChannel.State != CommunicationState.Closed)
                        {
                            throw;
                        }
                        wasChannelAborted = true;
                    }
                    if (wasChannelAborted)
                    {
                        return true;
                    }
                    return this.OnReceiveNullMessage(out wasChannelAborted);
                }
 
                void CleanupCloseState()
                {
                    if (this.closeResponse != null)
                    {
                        this.closeResponse.Close();
                    }
                    if (this.closeRequestContext != null)
                    {
                        this.closeRequestContext.Abort();
                    }
                }
 
                static void SendCloseResponseCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    CloseAsyncResult thisResult = (CloseAsyncResult)result.AsyncState;
                    bool completeSelf = false;
                    Exception completionException = null;
                    try
                    {
                        bool wasAborted = false;
                        try
                        {
                            thisResult.sessionChannel.EndSendCloseResponse(result);
                            thisResult.sessionChannel.inputSessionClosedHandle.Set();
                        }
                        catch (CommunicationObjectAbortedException)
                        {
                            if (thisResult.sessionChannel.State != CommunicationState.Closed)
                            {
                                throw;
                            }
                            wasAborted = true;
                            completeSelf = true;
                        }
                        finally
                        {
                            thisResult.CleanupCloseState();
                        }
                        if (!wasAborted)
                        {
                            completeSelf = thisResult.OnReceiveNullMessage(out wasAborted);
                        }
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
 
                        completeSelf = true;
                        completionException = e;
                    }
                    if (completeSelf)
                    {
                        thisResult.Complete(false, completionException);
                    }
                }
 
                bool OnReceiveNullMessage(out bool wasChannelAborted)
                {
                    wasChannelAborted = false;
                    bool receivedMessage = false;
                    Message message = null;
                    try
                    {
                        IAsyncResult result = this.sessionChannel.BeginTryReceive(this.timeoutHelper.RemainingTime(), receiveCallback, this);
                        if (!result.CompletedSynchronously)
                        {
                            return false;
                        }
                        receivedMessage = this.sessionChannel.EndTryReceive(result, out message);
                    }
                    catch (CommunicationObjectAbortedException)
                    {
                        if (this.sessionChannel.State != CommunicationState.Closed)
                        {
                            throw;
                        }
                        // another thread aborted the channel
                        wasChannelAborted = true;
                    }
                    if (wasChannelAborted)
                    {
                        return true;
                    }
 
                    if (receivedMessage)
                    {
                        return this.OnMessageReceived(message);
                    }
                    else
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, timeoutHelper.OriginalTimeout)));
                    }
                }
 
                static void ReceiveCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    CloseAsyncResult thisResult = (CloseAsyncResult)result.AsyncState;
                    bool completeSelf = false;
                    Exception completionException = null;
                    try
                    {
                        Message message = null;
                        bool wasAborted = false;
                        bool receivedMessage = false;
                        try
                        {
                            receivedMessage = thisResult.sessionChannel.EndTryReceive(result, out message);
                        }
                        catch (CommunicationObjectAbortedException)
                        {
                            if (thisResult.sessionChannel.State != CommunicationState.Closed)
                            {
                                throw;
                            }
                            wasAborted = true;
                            completeSelf = true;
                        }
                        if (!wasAborted)
                        {
                            if (receivedMessage)
                            {
                                completeSelf = thisResult.OnMessageReceived(message);
                            }
                            else
                            {
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, thisResult.timeoutHelper.OriginalTimeout)));
                            }
                        }
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
 
                        completeSelf = true;
                        completionException = e;
                    }
                    if (completeSelf)
                    {
                        thisResult.Complete(false, completionException);
                    }
                }
 
                bool OnMessageReceived(Message message)
                {
                    if (message != null)
                    {
                        using (message)
                        {
                            ProtocolException error = ProtocolException.ReceiveShutdownReturnedNonNull(message);
                            throw TraceUtility.ThrowHelperWarning(error, message);
                        }
                    }
                    bool inputSessionClosed = false;
                    try
                    {
                        IAsyncResult result = this.sessionChannel.inputSessionClosedHandle.BeginWait(this.timeoutHelper.RemainingTime(), true, waitCallback, this);
                        if (!result.CompletedSynchronously)
                        {
                            return false;
                        }
                        this.sessionChannel.inputSessionClosedHandle.EndWait(result);
                        inputSessionClosed = true;
                    }
                    catch (CommunicationObjectAbortedException)
                    {
                        if (this.sessionChannel.State != CommunicationState.Closed)
                        {
                            throw;
                        }
                        // a parallel thread aborted the channel
                        return true;
                    }
                    catch (TimeoutException)
                    {
                        inputSessionClosed = false;
                    }
 
                    return this.OnWaitOver(inputSessionClosed);
                }
 
                static void WaitForInputSessionCloseCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    CloseAsyncResult thisResult = (CloseAsyncResult)result.AsyncState;
                    bool completeSelf = false;
                    Exception completionException = null;
                    try
                    {
                        bool inputSessionClosed = false;
                        bool wasChannelAborted = false;
                        try
                        {
                            thisResult.sessionChannel.inputSessionClosedHandle.EndWait(result);
                            inputSessionClosed = true;
                        }
                        catch (TimeoutException)
                        {
                            inputSessionClosed = false;
                        }
                        catch (CommunicationObjectAbortedException)
                        {
                            if (thisResult.sessionChannel.State != CommunicationState.Closed)
                            {
                                throw;
                            }
                            wasChannelAborted = true;
                            completeSelf = true;
                        }
                        if (!wasChannelAborted)
                        {
                            completeSelf = thisResult.OnWaitOver(inputSessionClosed);
                        }
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        completeSelf = true;
                        completionException = e;
                    }
                    if (completeSelf)
                    {
                        thisResult.Complete(false, completionException);
                    }
                }
 
                bool OnWaitOver(bool closeCompleted)
                {
                    if (closeCompleted)
                    {
                        IAsyncResult result = this.sessionChannel.BeginCloseCore(this.timeoutHelper.RemainingTime(), closeCoreCallback, this);
                        if (!result.CompletedSynchronously)
                        {
                            return false;
                        }
                        this.sessionChannel.EndCloseCore(result);
                        return true;
                    }
                    else
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, this.timeoutHelper.OriginalTimeout)));
                    }
                }
 
                static void CloseCoreCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    CloseAsyncResult self = (CloseAsyncResult)(result.AsyncState);
                    Exception completionException = null;
                    try
                    {
                        self.sessionChannel.EndCloseCore(result);
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        completionException = e;
                    }
                    self.Complete(false, completionException);
                }
 
                public static void End(IAsyncResult result)
                {
                    AsyncResult.End<CloseAsyncResult>(result);
                }
            }
        }
 
        class SecurityReplySessionChannel : ServerSecuritySimplexSessionChannel, IReplySessionChannel
        {
            public SecurityReplySessionChannel(
                SecuritySessionServerSettings settings,
                IServerReliableChannelBinder channelBinder,
                SecurityContextSecurityToken sessionToken,
                object listenerSecurityState, SecurityListenerSettingsLifetimeManager settingsLifetimeManager)
                : base(settings, channelBinder, sessionToken, listenerSecurityState, settingsLifetimeManager)
            {
            }
 
            protected override bool CanDoSecurityCorrelation
            {
                get
                {
                    return true;
                }
            }
 
            public bool WaitForRequest(TimeSpan timeout)
            {
                return this.ChannelBinder.WaitForRequest(timeout);
            }
 
            public IAsyncResult BeginWaitForRequest(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return this.ChannelBinder.BeginWaitForRequest(timeout, callback, state);
            }
 
            public bool EndWaitForRequest(IAsyncResult result)
            {
                return this.ChannelBinder.EndWaitForRequest(result);
            }
        }
 
        class SecuritySessionRequestContext : RequestContextBase
        {
            RequestContext requestContext;
            ServerSecuritySessionChannel channel;
            SecurityProtocolCorrelationState correlationState;
 
            public SecuritySessionRequestContext(RequestContext requestContext, Message requestMessage, SecurityProtocolCorrelationState correlationState, ServerSecuritySessionChannel channel)
                : base(requestMessage, channel.InternalCloseTimeout, channel.InternalSendTimeout)
            {
                this.requestContext = requestContext;
                this.correlationState = correlationState;
                this.channel = channel;
            }
 
            protected override void OnAbort()
            {
                this.requestContext.Abort();
            }
 
            protected override void OnClose(TimeSpan timeout)
            {
                this.requestContext.Close(timeout);
            }
 
            protected override void OnReply(Message message, TimeSpan timeout)
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                if (message != null)
                {
                    this.channel.SecureApplicationMessage(ref message, timeoutHelper.RemainingTime(), correlationState);
                }
                this.requestContext.Reply(message, timeoutHelper.RemainingTime());
            }
 
            protected override IAsyncResult OnBeginReply(Message message, TimeSpan timeout, AsyncCallback callback, object state)
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                if (message != null)
                {
                    this.channel.SecureApplicationMessage(ref message, timeoutHelper.RemainingTime(), correlationState);
                }
                return this.requestContext.BeginReply(message, timeoutHelper.RemainingTime(), callback, state);
            }
 
            protected override void OnEndReply(IAsyncResult result)
            {
                this.requestContext.EndReply(result);
            }
        }
 
        class ServerSecurityDuplexSessionChannel : ServerSecuritySessionChannel, IDuplexSessionChannel
        {
            SoapSecurityServerDuplexSession session;
            bool isInputClosed;
            bool isOutputClosed;
            bool sentClose;
            bool receivedClose;
            RequestContext closeRequestContext;
            Message closeResponseMessage;
            InterruptibleWaitObject outputSessionCloseHandle = new InterruptibleWaitObject(true);
            InterruptibleWaitObject inputSessionCloseHandle = new InterruptibleWaitObject(false);
 
            public ServerSecurityDuplexSessionChannel(
                SecuritySessionServerSettings settings,
                IServerReliableChannelBinder channelBinder,
                SecurityContextSecurityToken sessionToken,
                object listenerSecurityState, SecurityListenerSettingsLifetimeManager settingsLifetimeManager)
                : base(settings, channelBinder, sessionToken, listenerSecurityState, settingsLifetimeManager)
            {
                this.session = new SoapSecurityServerDuplexSession(sessionToken, settings, this);
            }
 
            public EndpointAddress RemoteAddress
            {
                get
                {
                    return this.ChannelBinder.RemoteAddress;
                }
            }
 
            public Uri Via
            {
                get
                {
                    return this.RemoteAddress.Uri;
                }
            }
 
            public IDuplexSession Session
            {
                get
                {
                    return this.session;
                }
            }
 
            public void Send(Message message)
            {
                this.Send(message, this.DefaultSendTimeout);
            }
 
            public void Send(Message message, TimeSpan timeout)
            {
                CheckOutputOpen();
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                this.SecureApplicationMessage(ref message, timeoutHelper.RemainingTime(), null);
                this.ChannelBinder.Send(message, timeoutHelper.RemainingTime());
            }
 
            public IAsyncResult BeginSend(Message message, AsyncCallback callback, object state)
            {
                return this.BeginSend(message, this.DefaultSendTimeout, callback, state);
            }
 
            public IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
            {
                CheckOutputOpen();
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                this.SecureApplicationMessage(ref message, timeoutHelper.RemainingTime(), null);
                return this.ChannelBinder.BeginSend(message, timeoutHelper.RemainingTime(), callback, state);
            }
 
            public void EndSend(IAsyncResult result)
            {
                this.ChannelBinder.EndSend(result);
            }
 
            protected override void AbortCore()
            {
                base.AbortCore();
                this.Settings.RemoveSessionChannel(this.session.Id);
                CleanupPendingCloseState();
            }
 
            void CleanupPendingCloseState()
            {
                lock (ThisLock)
                {
                    if (this.closeResponseMessage != null)
                    {
                        this.closeResponseMessage.Close();
                        this.closeResponseMessage = null;
                    }
                    if (this.closeRequestContext != null)
                    {
                        this.closeRequestContext.Abort();
                        this.closeRequestContext = null;
                    }
                }
            }
 
            protected override void OnAbort()
            {
                AbortCore();
                this.inputSessionCloseHandle.Abort(this);
                this.outputSessionCloseHandle.Abort(this);
            }
 
            protected override void OnFaulted()
            {
                this.AbortCore();
                this.inputSessionCloseHandle.Fault(this);
                this.outputSessionCloseHandle.Fault(this);
                base.OnFaulted();
            }
 
            protected override void CloseCore(TimeSpan timeout)
            {
                base.CloseCore(timeout);
                this.inputSessionCloseHandle.Abort(this);
                this.outputSessionCloseHandle.Abort(this);
                this.Settings.RemoveSessionChannel(this.session.Id);
            }
 
            protected override void EndCloseCore(IAsyncResult result)
            {
                base.EndCloseCore(result);
                this.inputSessionCloseHandle.Abort(this);
                this.outputSessionCloseHandle.Abort(this);
                this.Settings.RemoveSessionChannel(this.session.Id);
            }
 
            protected void CheckOutputOpen()
            {
                ThrowIfClosedOrNotOpen();
                lock (ThisLock)
                {
                    if (this.isOutputClosed)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new CommunicationException(SR.GetString(SR.OutputNotExpected)));
                    }
                }
            }
 
            protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return new CloseAsyncResult(this, timeout, callback, state);
            }
 
            protected override void OnEndClose(IAsyncResult result)
            {
                CloseAsyncResult.End(result);
            }
 
            internal bool WaitForOutputSessionClose(TimeSpan timeout, out bool wasAborted)
            {
                wasAborted = false;
                try
                {
                    return this.outputSessionCloseHandle.Wait(timeout, false);
                }
                catch (CommunicationObjectAbortedException)
                {
                    if (this.State != CommunicationState.Closed) throw;
                    wasAborted = true;
                    return true;
                }
            }
 
            protected override void OnClose(TimeSpan timeout)
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 
                // step 1: close output session
                this.CloseOutputSession(timeoutHelper.RemainingTime());
 
                // if the channel was aborted while closing the output session, return
                if (this.State == CommunicationState.Closed)
                {
                    return;
                }
 
                // step 2: wait for input session to be closed
                bool wasAborted;
                bool didInputSessionClose = this.WaitForInputSessionClose(timeoutHelper.RemainingTime(), out wasAborted);
                if (wasAborted)
                {
                    return;
                }
                if (!didInputSessionClose)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, timeoutHelper.OriginalTimeout)));
                }
 
                // wait for any concurrent CloseOutputSessions to finish
                bool didOutputSessionClose = this.WaitForOutputSessionClose(timeoutHelper.RemainingTime(), out wasAborted);
                if (wasAborted)
                {
                    return;
                }
 
                if (!didOutputSessionClose)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseOutputSessionTimeout, timeoutHelper.OriginalTimeout)));
                }
 
                this.CloseCore(timeoutHelper.RemainingTime());
            }
 
            bool WaitForInputSessionClose(TimeSpan timeout, out bool wasAborted)
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                Message message;
                wasAborted = false;
                try
                {
                    if (!this.TryReceive(timeoutHelper.RemainingTime(), out message))
                    {
                        return false;
                    }
 
                    if (message != null)
                    {
                        using (message)
                        {
                            ProtocolException error = ProtocolException.ReceiveShutdownReturnedNonNull(message);
                            throw TraceUtility.ThrowHelperWarning(error, message);
                        }
                    }
 
                    // wait for remote close
                    if (!this.inputSessionCloseHandle.Wait(timeoutHelper.RemainingTime(), false))
                    {
                        return false;
                    }
                    else
                    {
                        lock (ThisLock)
                        {
                            if (!(this.isInputClosed))
                            {
                                Fx.Assert("Shutdown request was not received.");
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ShutdownRequestWasNotReceived)));
                            }
                        }
                        return true;
                    }
                }
                catch (CommunicationObjectAbortedException)
                {
                    if (this.State != CommunicationState.Closed)
                    {
                        throw;
                    }
                    wasAborted = true;
                }
                return false;
            }
 
            protected override void OnCloseMessageReceived(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
            {
                if (this.State == CommunicationState.Created)
                {
                    Fx.Assert("ServerSecurityDuplexSessionChannel.OnCloseMessageReceived (this.State == Created)");
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ServerReceivedCloseMessageStateIsCreated, this.GetType().ToString())));
                }
 
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                bool setInputSessionCloseHandle = false;
                bool cleanupContext = true;
                try
                {
                    lock (ThisLock)
                    {
                        this.receivedClose = true;
                        if (!this.isInputClosed)
                        {
                            this.isInputClosed = true;
                            setInputSessionCloseHandle = true;
 
                            if (!this.isOutputClosed)
                            {
                                this.closeRequestContext = requestContext;
                                // CreateCloseResponse closes the message passed in
                                this.closeResponseMessage = CreateCloseResponse(message, null, timeoutHelper.RemainingTime());
                                cleanupContext = false;
                            }
                        }
                    }
 
                    if (setInputSessionCloseHandle)
                    {
                        this.inputSessionCloseHandle.Set();
                    }
                    if (cleanupContext)
                    {
                        requestContext.Close(timeoutHelper.RemainingTime());
                        cleanupContext = false;
                    }
                }
                finally
                {
                    message.Close();
                    if (cleanupContext)
                    {
                        requestContext.Abort();
                    }
                }
            }
 
            protected override void OnCloseResponseMessageReceived(RequestContext requestContext, Message message, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
            {
                bool cleanupContext = true;
                try
                {
                    bool isCloseResponseExpected = false;
                    bool setInputSessionCloseHandle = false;
                    lock (ThisLock)
                    {
                        isCloseResponseExpected = this.sentClose;
                        if (isCloseResponseExpected && !this.isInputClosed)
                        {
                            this.isInputClosed = true;
                            setInputSessionCloseHandle = true;
                        }
                    }
                    if (!isCloseResponseExpected)
                    {
                        this.Fault(new ProtocolException(SR.GetString(SR.UnexpectedSecuritySessionCloseResponse)));
                        return;
                    }
                    if (setInputSessionCloseHandle)
                    {
                        this.inputSessionCloseHandle.Set();
                    }
 
                    requestContext.Close(timeout);
                    cleanupContext = false;
                }
                finally
                {
                    message.Close();
                    if (cleanupContext)
                    {
                        requestContext.Abort();
                    }
                }
            }
 
            void DetermineCloseOutputSessionMessage(out bool sendClose, out bool sendCloseResponse, out Message pendingCloseResponseMessage, out RequestContext pendingCloseRequestContext)
            {
                sendClose = false;
                sendCloseResponse = false;
                pendingCloseResponseMessage = null;
                pendingCloseRequestContext = null;
                lock (ThisLock)
                {
                    if (!this.isOutputClosed)
                    {
                        this.isOutputClosed = true;
                        if (this.receivedClose)
                        {
                            if (this.closeResponseMessage != null)
                            {
                                pendingCloseResponseMessage = this.closeResponseMessage;
                                pendingCloseRequestContext = this.closeRequestContext;
                                this.closeResponseMessage = null;
                                this.closeRequestContext = null;
                                sendCloseResponse = true;
                            }
                        }
                        else
                        {
                            sendClose = true;
                            this.sentClose = true;
                        }
                        this.outputSessionCloseHandle.Reset();
                    }
                }
            }
 
            void CloseOutputSession(TimeSpan timeout)
            {
                bool sendClose = false;
                bool sendCloseResponse = false;
                Message pendingCloseResponseMessage;
                RequestContext pendingCloseRequestContext;
                try
                {
                    DetermineCloseOutputSessionMessage(out sendClose, out sendCloseResponse, out pendingCloseResponseMessage, out pendingCloseRequestContext);
                    if (sendCloseResponse)
                    {
                        bool cleanupCloseState = true;
                        try
                        {
                            this.SendCloseResponse(pendingCloseRequestContext, pendingCloseResponseMessage, timeout);
                            cleanupCloseState = false;
                        }
                        finally
                        {
                            if (cleanupCloseState)
                            {
                                pendingCloseResponseMessage.Close();
                                pendingCloseRequestContext.Abort();
                            }
                        }
                    }
                    else if (sendClose)
                    {
                        this.SendClose(timeout);
                    }
                }
                catch (CommunicationObjectAbortedException)
                {
                    if (this.State != CommunicationState.Closed) throw;
                    // a parallel thread aborted the channel. ignore the exception
                }
                finally
                {
                    if (sendClose || sendCloseResponse)
                    {
                        this.outputSessionCloseHandle.Set();
                    }
                }
            }
 
            IAsyncResult BeginCloseOutputSession(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return new CloseOutputSessionAsyncResult(this, timeout, callback, state);
            }
 
            void EndCloseOutputSession(IAsyncResult result)
            {
                CloseOutputSessionAsyncResult.End(result);
            }
 
            public bool WaitForMessage(TimeSpan timeout)
            {
                return this.ChannelBinder.WaitForRequest(timeout);
            }
 
            public IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return this.ChannelBinder.BeginWaitForRequest(timeout, callback, state);
            }
 
            public bool EndWaitForMessage(IAsyncResult result)
            {
                return this.ChannelBinder.EndWaitForRequest(result);
            }
 
            class CloseOutputSessionAsyncResult : AsyncResult
            {
                static AsyncCallback sendCallback = Fx.ThunkCallback(new AsyncCallback(SendCallback));
                ServerSecurityDuplexSessionChannel sessionChannel;
                TimeoutHelper timeoutHelper;
                bool sendClose;
                bool sendCloseResponse;
                Message closeResponseMessage;
                RequestContext closeRequestContext;
 
                public CloseOutputSessionAsyncResult(ServerSecurityDuplexSessionChannel sessionChannel, TimeSpan timeout, AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    this.sessionChannel = sessionChannel;
                    this.timeoutHelper = new TimeoutHelper(timeout);
                    this.sessionChannel.DetermineCloseOutputSessionMessage(out sendClose, out sendCloseResponse, out closeResponseMessage, out closeRequestContext);
                    if (!sendClose && !sendCloseResponse)
                    {
                        Complete(true);
                        return;
                    }
                    bool doCleanup = true;
                    try
                    {
                        IAsyncResult result = this.BeginSend(sendCallback, this);
                        if (!result.CompletedSynchronously)
                        {
                            doCleanup = false;
                            return;
                        }
                        this.EndSend(result);
                    }
                    finally
                    {
                        if (doCleanup)
                        {
                            Cleanup();
                        }
                    }
                    Complete(true);
                }
 
                static void SendCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    CloseOutputSessionAsyncResult self = (CloseOutputSessionAsyncResult)(result.AsyncState);
                    Exception completionException = null;
                    try
                    {
                        self.EndSend(result);
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        completionException = e;
                    }
                    self.Cleanup();
                    self.Complete(false, completionException);
                }
 
                IAsyncResult BeginSend(AsyncCallback callback, object state)
                {
                    if (this.sendClose)
                    {
                        return this.sessionChannel.BeginSendClose(timeoutHelper.RemainingTime(), callback, state);
                    }
                    else
                    {
                        return this.sessionChannel.BeginSendCloseResponse(this.closeRequestContext, this.closeResponseMessage, this.timeoutHelper.RemainingTime(), callback, state);
                    }
                }
 
                void EndSend(IAsyncResult result)
                {
                    if (this.sendClose)
                    {
                        this.sessionChannel.EndSendClose(result);
                    }
                    else
                    {
                        this.sessionChannel.EndSendCloseResponse(result);
                    }
                }
 
                void Cleanup()
                {
                    if (this.closeResponseMessage != null)
                    {
                        this.closeResponseMessage.Close();
                    }
                    if (this.closeRequestContext != null)
                    {
                        this.closeRequestContext.Abort();
                    }
                    this.sessionChannel.outputSessionCloseHandle.Set();
                }
 
                public static void End(IAsyncResult result)
                {
                    AsyncResult.End<CloseOutputSessionAsyncResult>(result);
                }
            }
 
            class CloseAsyncResult : AsyncResult
            {
                static readonly AsyncCallback receiveCallback = Fx.ThunkCallback(new AsyncCallback(ReceiveCallback));
                static readonly AsyncCallback inputSessionWaitCallback = Fx.ThunkCallback(new AsyncCallback(WaitForInputSessionCloseCallback));
                static readonly AsyncCallback closeOutputSessionCallback = Fx.ThunkCallback(new AsyncCallback(CloseOutputSessionCallback));
                static readonly AsyncCallback outputSessionWaitCallback = Fx.ThunkCallback(new AsyncCallback(WaitForOutputSessionCloseCallback));
                static readonly AsyncCallback closeCoreCallback = Fx.ThunkCallback(new AsyncCallback(CloseCoreCallback));
                ServerSecurityDuplexSessionChannel sessionChannel;
                TimeoutHelper timeoutHelper;
 
                public CloseAsyncResult(ServerSecurityDuplexSessionChannel sessionChannel, TimeSpan timeout, AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    this.timeoutHelper = new TimeoutHelper(timeout);
                    this.sessionChannel = sessionChannel;
 
                    bool wasAborted = false;
                    try
                    {
                        IAsyncResult result = this.sessionChannel.BeginCloseOutputSession(timeoutHelper.RemainingTime(), closeOutputSessionCallback, this);
                        if (!result.CompletedSynchronously)
                        {
                            return;
                        }
                        this.sessionChannel.EndCloseOutputSession(result);
                    }
                    catch (CommunicationObjectAbortedException)
                    {
                        if (sessionChannel.State != CommunicationState.Closed) throw;
                        // a parallel thread must have aborted the channel. No need to close 
                        wasAborted = true;
                    }
                    if (wasAborted || this.OnOutputSessionClosed())
                    {
                        Complete(true);
                    }
                }
 
                static void CloseOutputSessionCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    CloseAsyncResult thisResult = (CloseAsyncResult)result.AsyncState;
                    bool completeSelf = false;
                    Exception completionException = null;
                    try
                    {
                        bool wasAborted = false;
                        try
                        {
                            thisResult.sessionChannel.Session.EndCloseOutputSession(result);
                        }
                        catch (CommunicationObjectAbortedException)
                        {
                            if (thisResult.sessionChannel.State != CommunicationState.Closed)
                            {
                                throw;
                            }
                            completeSelf = true;
                            wasAborted = true;
                        }
                        if (!wasAborted)
                        {
                            completeSelf = thisResult.OnOutputSessionClosed();
                        }
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
 
                        completeSelf = true;
                        completionException = e;
                    }
                    if (completeSelf)
                    {
                        thisResult.Complete(false, completionException);
                    }
                }
 
                bool OnOutputSessionClosed()
                {
                    bool wasAborted = false;
                    Message message = null;
                    bool receivedMessage = false;
                    try
                    {
                        IAsyncResult result = this.sessionChannel.BeginTryReceive(this.timeoutHelper.RemainingTime(), receiveCallback, this);
                        if (!result.CompletedSynchronously)
                        {
                            return false;
                        }
                        receivedMessage = this.sessionChannel.EndTryReceive(result, out message);
                    }
                    catch (CommunicationObjectAbortedException)
                    {
                        if (this.sessionChannel.State != CommunicationState.Closed)
                        {
                            throw;
                        }
                        wasAborted = true;
                    }
                    if (wasAborted)
                    {
                        return true;
                    }
 
                    if (receivedMessage)
                    {
                        return this.OnMessageReceived(message);
                    }
                    else
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, this.timeoutHelper.OriginalTimeout)));
                    }
                }
 
                static void ReceiveCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    CloseAsyncResult thisResult = (CloseAsyncResult)result.AsyncState;
                    bool completeSelf = false;
                    Exception completionException = null;
                    try
                    {
                        Message message = null;
                        bool receivedRequest = false;
                        bool wasAborted = false;
                        try
                        {
                            receivedRequest = thisResult.sessionChannel.EndTryReceive(result, out message);
                        }
                        catch (CommunicationObjectAbortedException)
                        {
                            if (thisResult.sessionChannel.State != CommunicationState.Closed)
                            {
                                throw;
                            }
                            completeSelf = true;
                            wasAborted = true;
                        }
                        if (!wasAborted)
                        {
                            if (receivedRequest)
                            {
                                completeSelf = thisResult.OnMessageReceived(message);
                            }
                            else
                            {
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, thisResult.timeoutHelper.OriginalTimeout)));
                            }
                        }
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
 
                        completeSelf = true;
                        completionException = e;
                    }
                    if (completeSelf)
                    {
                        thisResult.Complete(false, completionException);
                    }
                }
 
                bool OnMessageReceived(Message message)
                {
                    if (message != null)
                    {
                        using (message)
                        {
                            ProtocolException error = ProtocolException.ReceiveShutdownReturnedNonNull(message);
                            throw TraceUtility.ThrowHelperWarning(error, message);
                        }
                    }
                    bool wasAborted = false;
                    bool inputSessionClosed = false;
                    try
                    {
                        IAsyncResult result = this.sessionChannel.inputSessionCloseHandle.BeginWait(this.timeoutHelper.RemainingTime(), inputSessionWaitCallback, this);
                        if (!result.CompletedSynchronously)
                        {
                            return false;
                        }
                        try
                        {
                            this.sessionChannel.inputSessionCloseHandle.EndWait(result);
                            inputSessionClosed = true;
                        }
                        catch (TimeoutException)
                        {
                            inputSessionClosed = false;
                        }
                    }
                    catch (CommunicationObjectAbortedException)
                    {
                        if (this.sessionChannel.State != CommunicationState.Closed)
                        {
                            throw;
                        }
                        wasAborted = true;
                    }
                    if (wasAborted)
                    {
                        return true;
                    }
                    return this.OnInputSessionWaitOver(inputSessionClosed);
                }
 
                static void WaitForInputSessionCloseCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    CloseAsyncResult thisResult = (CloseAsyncResult)result.AsyncState;
                    bool completeSelf = false;
                    Exception completionException = null;
                    bool inputSessionClosed = false;
                    try
                    {
                        bool wasAborted = false;
                        try
                        {
                            thisResult.sessionChannel.inputSessionCloseHandle.EndWait(result);
                            inputSessionClosed = true;
                        }
                        catch (TimeoutException)
                        {
                            inputSessionClosed = false;
                        }
                        catch (CommunicationObjectAbortedException)
                        {
                            if (thisResult.sessionChannel.State != CommunicationState.Closed)
                            {
                                throw;
                            }
                            wasAborted = true;
                            completeSelf = true;
                        }
                        if (!wasAborted)
                        {
                            completeSelf = thisResult.OnInputSessionWaitOver(inputSessionClosed);
                        }
 
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
 
                        completeSelf = true;
                        completionException = e;
                    }
                    if (completeSelf)
                    {
                        thisResult.Complete(false, completionException);
                    }
                }
 
                bool OnInputSessionWaitOver(bool inputSessionClosed)
                {
                    if (inputSessionClosed)
                    {
                        lock (this.sessionChannel.ThisLock)
                        {
                            if (!(this.sessionChannel.isInputClosed))
                            {
                                Fx.Assert("Shutdown request was not received.");
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ShutdownRequestWasNotReceived)));
                            }
                        }
                        bool outputSessionClosed = false;
                        bool wasAborted = false;
                        try
                        {
                            IAsyncResult result = this.sessionChannel.outputSessionCloseHandle.BeginWait(timeoutHelper.RemainingTime(), true, outputSessionWaitCallback, this);
                            if (!result.CompletedSynchronously)
                            {
                                return false;
                            }
                            this.sessionChannel.outputSessionCloseHandle.EndWait(result);
                            outputSessionClosed = true;
                        }
                        catch (CommunicationObjectAbortedException)
                        {
                            if (this.sessionChannel.State != CommunicationState.Closed) throw;
                            wasAborted = true;
                        }
                        catch (TimeoutException)
                        {
                            outputSessionClosed = false;
                        }
                        if (wasAborted)
                        {
                            return true;
                        }
                        else
                        {
                            return this.OnOutputSessionWaitOver(outputSessionClosed);
                        }
                    }
                    else
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseTimeout, timeoutHelper.OriginalTimeout)));
                    }
                }
 
                static void WaitForOutputSessionCloseCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    CloseAsyncResult thisResult = (CloseAsyncResult)result.AsyncState;
                    bool completeSelf = false;
                    Exception completionException = null;
                    bool outputSessionClosed = false;
                    try
                    {
                        bool wasAborted = false;
                        try
                        {
                            thisResult.sessionChannel.outputSessionCloseHandle.EndWait(result);
                            outputSessionClosed = true;
                        }
                        catch (CommunicationObjectAbortedException)
                        {
                            if (thisResult.sessionChannel.State != CommunicationState.Closed)
                            {
                                throw;
                            }
                            wasAborted = true;
                            completeSelf = true;
                        }
                        catch (TimeoutException)
                        {
                            outputSessionClosed = false;
                        }
                        if (!wasAborted)
                        {
                            completeSelf = thisResult.OnOutputSessionWaitOver(outputSessionClosed);
                        }
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
 
                        completeSelf = true;
                        completionException = e;
                    }
                    if (completeSelf)
                    {
                        thisResult.Complete(false, completionException);
                    }
                }
 
                bool OnOutputSessionWaitOver(bool outputSessionClosed)
                {
                    if (outputSessionClosed)
                    {
                        IAsyncResult result = this.sessionChannel.BeginCloseCore(this.timeoutHelper.RemainingTime(), closeCoreCallback, this);
                        if (!result.CompletedSynchronously)
                        {
                            return false;
                        }
                        this.sessionChannel.EndCloseCore(result);
                        return true;
                    }
                    else
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new TimeoutException(SR.GetString(SR.ServiceSecurityCloseOutputSessionTimeout, timeoutHelper.OriginalTimeout)));
                    }
                }
 
                static void CloseCoreCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    CloseAsyncResult self = (CloseAsyncResult)(result.AsyncState);
                    Exception completionException = null;
                    try
                    {
                        self.sessionChannel.EndCloseCore(result);
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        completionException = e;
                    }
                    self.Complete(false, completionException);
                }
 
                public static void End(IAsyncResult result)
                {
                    AsyncResult.End<CloseAsyncResult>(result);
                }
            }
 
            class SoapSecurityServerDuplexSession : SoapSecurityInputSession, IDuplexSession
            {
                ServerSecurityDuplexSessionChannel channel;
 
                public SoapSecurityServerDuplexSession(SecurityContextSecurityToken sessionToken, SecuritySessionServerSettings settings, ServerSecurityDuplexSessionChannel channel)
                    : base(sessionToken, settings, channel)
                {
                    this.channel = channel;
                }
 
                public void CloseOutputSession()
                {
                    this.CloseOutputSession(this.channel.DefaultCloseTimeout);
                }
 
                public void CloseOutputSession(TimeSpan timeout)
                {
                    this.channel.ThrowIfFaulted();
                    this.channel.ThrowIfNotOpened();
                    Exception pendingException = null;
                    try
                    {
                        this.channel.CloseOutputSession(timeout);
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        pendingException = e;
                    }
                    if (pendingException != null)
                    {
                        this.channel.Fault(pendingException);
                        if (pendingException is CommunicationException)
                        {
                            throw pendingException;
                        }
                        else
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(pendingException);
                        }
                    }
                }
 
                public IAsyncResult BeginCloseOutputSession(AsyncCallback callback, object state)
                {
                    return this.BeginCloseOutputSession(this.channel.DefaultCloseTimeout, callback, state);
                }
 
                public IAsyncResult BeginCloseOutputSession(TimeSpan timeout, AsyncCallback callback, object state)
                {
                    this.channel.ThrowIfFaulted();
                    this.channel.ThrowIfNotOpened();
                    Exception pendingException = null;
                    try
                    {
                        return this.channel.BeginCloseOutputSession(timeout, callback, state);
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        pendingException = e;
                    }
                    if (pendingException != null)
                    {
                        this.channel.Fault(pendingException);
                        if (pendingException is CommunicationException)
                        {
                            throw pendingException;
                        }
                        else
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(pendingException);
                        }
                    }
                    return null;
                }
 
                public void EndCloseOutputSession(IAsyncResult result)
                {
                    Exception pendingException = null;
                    try
                    {
                        this.channel.EndCloseOutputSession(result);
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
                        pendingException = e;
                    }
                    if (pendingException != null)
                    {
                        this.channel.Fault(pendingException);
                        if (pendingException is CommunicationException)
                        {
                            throw pendingException;
                        }
                        else
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(pendingException);
                        }
                    }
                }
            }
        }
 
        internal class SecuritySessionDemuxFailureHandler : IChannelDemuxFailureHandler
        {
            SecurityStandardsManager standardsManager;
 
            public SecuritySessionDemuxFailureHandler(SecurityStandardsManager standardsManager)
            {
                if (standardsManager == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("standardsManager");
                }
                this.standardsManager = standardsManager;
            }
 
            public void HandleDemuxFailure(Message message)
            {
                if (message == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
                }
                if (DiagnosticUtility.ShouldTraceWarning)
                {
                    TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.SecuritySessionDemuxFailure, SR.GetString(SR.TraceCodeSecuritySessionDemuxFailure), message);
                }
            }
 
            public Message CreateSessionDemuxFaultMessage(Message message)
            {
                MessageFault fault = SecurityUtils.CreateSecurityContextNotFoundFault(this.standardsManager, message.Headers.Action);
                Message faultMessage = Message.CreateMessage(message.Version, fault, message.Version.Addressing.DefaultFaultAction);
                if (message.Headers.MessageId != null)
                {
                    faultMessage.InitializeReply(message);
                }
                return faultMessage;
            }
 
            IAsyncResult BeginHandleDemuxFailure<TFaultContext>(Message message, TFaultContext faultContext, AsyncCallback callback, object state)
            {
                this.HandleDemuxFailure(message);
                Message fault = CreateSessionDemuxFaultMessage(message);
                return new SendFaultAsyncResult<TFaultContext>(fault, faultContext, callback, state);
            }
 
            public IAsyncResult BeginHandleDemuxFailure(Message message, RequestContext faultContext, AsyncCallback callback, object state)
            {
                return BeginHandleDemuxFailure<RequestContext>(message, faultContext, callback, state);
            }
 
            public IAsyncResult BeginHandleDemuxFailure(Message message, IOutputChannel faultContext, AsyncCallback callback, object state)
            {
                return BeginHandleDemuxFailure<IOutputChannel>(message, faultContext, callback, state);
            }
 
            public void EndHandleDemuxFailure(IAsyncResult result)
            {
                if (result is SendFaultAsyncResult<RequestContext>)
                {
                    SendFaultAsyncResult<RequestContext>.End(result);
                }
                else if (result is SendFaultAsyncResult<IOutputChannel>)
                {
                    SendFaultAsyncResult<IOutputChannel>.End(result);
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidAsyncResult), "result"));
                }
            }
 
            class SendFaultAsyncResult<TFaultContext> : AsyncResult
            {
                Message message;
                static AsyncCallback sendCallback = Fx.ThunkCallback(new AsyncCallback(SendCallback));
                TFaultContext faultContext;
 
                public SendFaultAsyncResult(Message fault, TFaultContext faultContext, AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    this.faultContext = faultContext;
                    this.message = fault;
                    IAsyncResult result = BeginSend(fault);
                    if (!result.CompletedSynchronously)
                    {
                        return;
                    }
                    EndSend(result);
                    Complete(true);
                }
 
                IAsyncResult BeginSend(Message message)
                {
                    bool throwing = true;
                    try
                    {
                        IAsyncResult result = null;
                        if (faultContext is RequestContext)
                        {
                            result = ((RequestContext)(object)faultContext).BeginReply(message, sendCallback, this);
                        }
                        else
                        {
                            result = ((IOutputChannel)faultContext).BeginSend(message, sendCallback, this);
                        }
                        throwing = false;
                        return result;
                    }
                    finally
                    {
                        if (throwing && message != null)
                        {
                            message.Close();
                        }
                    }
                }
 
                void EndSend(IAsyncResult result)
                {
                    using (this.message)
                    {
                        if (faultContext is RequestContext)
                        {
                            ((RequestContext)(object)faultContext).EndReply(result);
                        }
                        else
                        {
                            ((IOutputChannel)faultContext).EndSend(result);
                        }
                    }
                }
 
                static void SendCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    SendFaultAsyncResult<TFaultContext> self = (SendFaultAsyncResult<TFaultContext>)result.AsyncState;
                    Exception completionException = null;
                    try
                    {
                        self.EndSend(result);
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception e)
                    {
                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }
 
                        completionException = e;
                    }
                    self.Complete(false, completionException);
                }
 
                internal static void End(IAsyncResult result)
                {
                    AsyncResult.End<SendFaultAsyncResult<TFaultContext>>(result);
                }
            }
        }
    }
}