File: System\ServiceModel\Channels\SecurityChannelListener.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//----------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.ServiceModel.Channels
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Runtime;
    using System.Security;
    using System.Security.Authentication.ExtendedProtection;
    using System.ServiceModel;
    using System.ServiceModel.Activation;
    using System.ServiceModel.Security;
    using System.ServiceModel.Security.Tokens;
    using System.Threading;
    using System.ServiceModel.Dispatcher;
 
    sealed class SecurityChannelListener<TChannel> : DelegatingChannelListener<TChannel> where TChannel : class, IChannel
    {
        ChannelBuilder channelBuilder;
        SecurityProtocolFactory securityProtocolFactory;
        SecuritySessionServerSettings sessionServerSettings;
        bool sessionMode;
        // this will be disabled by negotiation when doing request/reply over composite duplex
        bool sendUnsecuredFaults = true;
        SecurityListenerSettingsLifetimeManager settingsLifetimeManager;
        bool hasSecurityStateReference;
        bool extendedProtectionPolicyHasSupport;
        ISecurityCapabilities securityCapabilities;
        EndpointIdentity identity;
 
        public SecurityChannelListener(SecurityBindingElement bindingElement, BindingContext context)
            : base(true, context.Binding)
        {
            this.securityCapabilities = bindingElement.GetProperty<ISecurityCapabilities>(context);
            extendedProtectionPolicyHasSupport = SecurityUtils.IsSecurityBindingSuitableForChannelBinding(bindingElement as TransportSecurityBindingElement);
        }
 
        // used by internal test code
        internal SecurityChannelListener(SecurityProtocolFactory protocolFactory, IChannelListener innerChannelListener)
            : base(true, null, innerChannelListener)
        {
            this.securityProtocolFactory = protocolFactory;
        }
 
        public ChannelBuilder ChannelBuilder
        {
            get
            {
                ThrowIfDisposed();
                return this.channelBuilder;
            }
        }
 
        public SecurityProtocolFactory SecurityProtocolFactory
        {
            get
            {
                ThrowIfDisposed();
                return this.securityProtocolFactory;
            }
            set
            {
                if (value == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
                }
                ThrowIfDisposedOrImmutable();
                this.securityProtocolFactory = value;
            }
        }
 
        public bool SessionMode
        {
            get
            {
                return this.sessionMode;
            }
            set
            {
                ThrowIfDisposedOrImmutable();
                this.sessionMode = value;
            }
        }
 
        public SecuritySessionServerSettings SessionServerSettings
        {
            get
            {
                ThrowIfDisposed();
                if (this.sessionServerSettings == null)
                {
                    lock (ThisLock)
                    {
                        if (this.sessionServerSettings == null)
                        {
                            SecuritySessionServerSettings tmp = new SecuritySessionServerSettings();
                            System.Threading.Thread.MemoryBarrier();
                            this.sessionServerSettings = tmp;
                        }
                    }
                }
                return this.sessionServerSettings;
            }
        }
 
        bool SupportsDuplex
        {
            get
            {
                ThrowIfProtocolFactoryNotSet();
                return this.securityProtocolFactory.SupportsDuplex;
            }
        }
 
        bool SupportsRequestReply
        {
            get
            {
                ThrowIfProtocolFactoryNotSet();
                return this.securityProtocolFactory.SupportsRequestReply;
            }
        }
 
        public bool SendUnsecuredFaults
        {
            get
            {
                return this.sendUnsecuredFaults;
            }
            set
            {
                ThrowIfDisposedOrImmutable();
                this.sendUnsecuredFaults = value;
            }
        }
 
        // This method should only be called at Open time, since it looks up the identity based on the 
        // thread token
        void ComputeEndpointIdentity()
        {
            EndpointIdentity result = null;
            if (this.State == CommunicationState.Opened)
            {
                if (this.SecurityProtocolFactory != null)
                {
                    result = this.SecurityProtocolFactory.GetIdentityOfSelf();
                }
                else if (this.SessionServerSettings != null && this.SessionServerSettings.SessionProtocolFactory != null)
                {
                    result = this.SessionServerSettings.SessionProtocolFactory.GetIdentityOfSelf();
                }
            }
            if (result == null)
            {
                result = base.GetProperty<EndpointIdentity>();
            }
            this.identity = result;
        }
 
        public override T GetProperty<T>()
        {
            if (typeof(T) == typeof(SecurityProtocolFactory))
            {
                return (T)(object)this.SecurityProtocolFactory;
            }
            else if (this.SessionMode && (typeof(T) == typeof(IListenerSecureConversationSessionSettings)))
            {
                return (T)(object)this.SessionServerSettings;
            }
            else if (typeof(T) == typeof(EndpointIdentity))
            {
                return (T)(object)(this.identity);
            }
            else if (typeof(T) == typeof(Collection<ISecurityContextSecurityTokenCache>))
            {
                if (this.SecurityProtocolFactory != null)
                {
                    return (T)(object)this.SecurityProtocolFactory.GetProperty<Collection<ISecurityContextSecurityTokenCache>>();
                }
                else
                {
                    return (T)(object)base.GetProperty<Collection<ISecurityContextSecurityTokenCache>>();
                }
            }
            else if (typeof(T) == typeof(ISecurityCapabilities))
            {
                return (T)(object)this.securityCapabilities;
            }
            else if (typeof(T) == typeof(ILogonTokenCacheManager))
            {
                List<ILogonTokenCacheManager> cacheManagers = new List<ILogonTokenCacheManager>();
 
                if (this.SecurityProtocolFactory != null && this.securityProtocolFactory.ChannelSupportingTokenAuthenticatorSpecification.Count > 0)
                {
                    foreach (SupportingTokenAuthenticatorSpecification spec in this.securityProtocolFactory.ChannelSupportingTokenAuthenticatorSpecification)
                    {
                        if (spec.TokenAuthenticator is ILogonTokenCacheManager)
                            cacheManagers.Add(spec.TokenAuthenticator as ILogonTokenCacheManager);
                    }
                }
 
                if (this.SessionServerSettings.SessionProtocolFactory != null && this.SessionServerSettings.SessionTokenAuthenticator is ILogonTokenCacheManager)
                    cacheManagers.Add(this.SessionServerSettings.SessionTokenAuthenticator as ILogonTokenCacheManager);
 
                return (T)(object)(new AggregateLogonTokenCacheManager(new ReadOnlyCollection<ILogonTokenCacheManager>(cacheManagers)));
            }
 
            return base.GetProperty<T>();
        }
 
        protected override void OnAbort()
        {
            lock (ThisLock)
            {
                if (this.hasSecurityStateReference)
                {
                    hasSecurityStateReference = false;
                    if (this.settingsLifetimeManager != null)
                    {
                        this.settingsLifetimeManager.Abort();
                    }
                }
            }
            base.OnAbort();
        }
 
        protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
        {
            if (this.SessionMode)
            {
                if (this.sessionServerSettings != null)
                {
                    this.sessionServerSettings.StopAcceptingNewWork();
                }
            }
 
            return new ChainedAsyncResult(timeout, callback, state, this.OnBeginCloseSharedState, this.OnEndCloseSharedState, base.OnBeginClose, base.OnEndClose);
        }
 
        protected override void OnEndClose(IAsyncResult result)
        {
            ChainedAsyncResult.End(result);
        }
 
        IAsyncResult OnBeginCloseSharedState(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return new CloseSharedStateAsyncResult(this, timeout, callback, state);
        }
 
        void OnEndCloseSharedState(IAsyncResult result)
        {
            CloseSharedStateAsyncResult.End(result);
        }
 
        internal IAsyncResult OnBeginOpenListenerState(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return new OpenListenerStateAsyncResult(this, timeout, callback, state);
        }
 
        internal void OnEndOpenListenerState(IAsyncResult result)
        {
            OpenListenerStateAsyncResult.End(result);
        }
 
        protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            ThrowIfInnerListenerNotSet();
            EnableChannelBindingSupport();
 
            return new ChainedAsyncResult(timeout, callback, state, base.OnBeginOpen, base.OnEndOpen, this.OnBeginOpenListenerState, this.OnEndOpenListenerState);
        }
 
        protected override void OnEndOpen(IAsyncResult result)
        {
            ChainedAsyncResult.End(result);
        }
 
        protected override void OnOpened()
        {
            base.OnOpened();
            ComputeEndpointIdentity();
        }
 
        protected override void OnClose(TimeSpan timeout)
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            if (this.sessionServerSettings != null)
            {
                this.sessionServerSettings.StopAcceptingNewWork();
            }
            lock (ThisLock)
            {
                if (this.hasSecurityStateReference)
                {
                    hasSecurityStateReference = false;
                    this.settingsLifetimeManager.Close(timeoutHelper.RemainingTime());
                }
            }
            base.OnClose(timeoutHelper.RemainingTime());
        }
 
        internal void InitializeListener(ChannelBuilder channelBuilder)
        {
            this.channelBuilder = channelBuilder;
 
            if (this.SessionMode)
            {
                this.sessionServerSettings.ChannelBuilder = this.ChannelBuilder;
                this.InnerChannelListener = this.sessionServerSettings.CreateInnerChannelListener();
                this.Acceptor = this.sessionServerSettings.CreateAcceptor<TChannel>();
            }
            else
            {
                this.InnerChannelListener = this.ChannelBuilder.BuildChannelListener<TChannel>();
                this.Acceptor = (IChannelAcceptor<TChannel>)new SecurityChannelAcceptor(this,
                    (IChannelListener<TChannel>)InnerChannelListener, this.securityProtocolFactory.CreateListenerSecurityState());
            }
        }
 
        void InitializeListenerSecurityState()
        {
            if (this.SessionMode)
            {
                this.SessionServerSettings.SessionProtocolFactory.ListenUri = this.Uri;
                this.SessionServerSettings.SecurityChannelListener = this;
            }
            else
            {
                ThrowIfProtocolFactoryNotSet();
                this.securityProtocolFactory.ListenUri = this.Uri;
            }
            this.settingsLifetimeManager = new SecurityListenerSettingsLifetimeManager(this.securityProtocolFactory, this.sessionServerSettings, this.sessionMode, this.InnerChannelListener);
            if (this.sessionServerSettings != null)
            {
                this.sessionServerSettings.SettingsLifetimeManager = this.settingsLifetimeManager;
            }
            this.hasSecurityStateReference = true;
        }
 
        protected override void OnOpen(TimeSpan timeout)
        {
            ThrowIfInnerListenerNotSet();
            EnableChannelBindingSupport();
 
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            base.OnOpen(timeoutHelper.RemainingTime());
            lock (ThisLock)
            {
                // if an abort happened before the Open, return
                if (this.State == CommunicationState.Closing && this.State == CommunicationState.Closed)
                {
                    return;
                }
                InitializeListenerSecurityState();
            }
            this.settingsLifetimeManager.Open(timeoutHelper.RemainingTime());
        }
 
        void EnableChannelBindingSupport()
        {
 
            ExtendedProtectionPolicy extendedProtectionPolicy = InnerChannelListener.GetProperty<ExtendedProtectionPolicy>();
 
            // If extendedProtectionPolicy is set we need to check if necessary pieces are in place
            if (extendedProtectionPolicy != null)
            {
                // we do not support custom channel bindings in Win7
                if (extendedProtectionPolicy.CustomChannelBinding != null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.ExtendedProtectionPolicyCustomChannelBindingNotSupported)));
                }
 
                if (extendedProtectionPolicy.PolicyEnforcement == PolicyEnforcement.Never)
                    return;
 
                IChannelBindingProvider cbp = InnerChannelListener.GetProperty<IChannelBindingProvider>();
 
                if (extendedProtectionPolicy.PolicyEnforcement == PolicyEnforcement.Always)
                {
                    // If the securityBinding does not support ExtendedProtectionPolicy OR { there is no channel-binding-provider and we are not in TrustedProxy scenario } then we throw.
                    // For NetFXw7, we only suppport SPNego and Kerb.
                    if (SecurityUtils.IsChannelBindingDisabled || !this.extendedProtectionPolicyHasSupport || (cbp == null && extendedProtectionPolicy.ProtectionScenario != ProtectionScenario.TrustedProxy))
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecurityChannelListenerChannelExtendedProtectionNotSupported)));
                    }
                }
 
                // Do not enable channel binding if there is no reason as it sets http in chunking mode.
                if ((SecurityUtils.IsChannelBindingDisabled) || (!this.extendedProtectionPolicyHasSupport))
                    return;
 
                if (cbp != null)
                {
                    cbp.EnableChannelBindingSupport();
                }
 
            }
 
            if (this.securityProtocolFactory != null)
            {
                this.securityProtocolFactory.ExtendedProtectionPolicy = extendedProtectionPolicy;
            }
 
        }
 
        void ThrowIfProtocolFactoryNotSet()
        {
            if (this.securityProtocolFactory == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecurityProtocolFactoryShouldBeSetBeforeThisOperation)));
            }
        }
 
        protected override void OnFaulted()
        {
            lock (ThisLock)
            {
                if (this.hasSecurityStateReference)
                {
                    this.hasSecurityStateReference = false;
                    if (this.settingsLifetimeManager != null)
                    {
                        this.settingsLifetimeManager.Abort();
                    }
                }
            }
            base.OnFaulted();
        }
 
        class AggregateLogonTokenCacheManager : ILogonTokenCacheManager
        {
            ReadOnlyCollection<ILogonTokenCacheManager> cacheManagers;
 
            public AggregateLogonTokenCacheManager(ReadOnlyCollection<ILogonTokenCacheManager> cacheManagers)
            {
                if (cacheManagers == null)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("cacheManagers");
 
                this.cacheManagers = cacheManagers;
            }
 
            public bool RemoveCachedLogonToken(string username)
            {
                bool removed = false;
 
                if (!removed && this.cacheManagers != null)
                {
                    for (int i = 0; i < this.cacheManagers.Count; ++i)
                    {
                        removed = this.cacheManagers[i].RemoveCachedLogonToken(username);
                        if (removed)
                            break;
                    }
                }
 
                return removed;
            }
 
            public void FlushLogonTokenCache()
            {
                if (this.cacheManagers != null)
                {
                    for (int i = 0; i < this.cacheManagers.Count; ++i)
                    {
                        this.cacheManagers[i].FlushLogonTokenCache();
                    }
                }
            }
        }
 
        internal sealed class SecurityChannelAcceptor : LayeredChannelAcceptor<TChannel, TChannel>
        {
            readonly object listenerSecurityProtocolState;
 
            public SecurityChannelAcceptor(ChannelManagerBase channelManager, IChannelListener<TChannel> innerListener,
                object listenerSecurityProtocolState)
                : base(channelManager, innerListener)
            {
                this.listenerSecurityProtocolState = listenerSecurityProtocolState;
            }
 
            SecurityChannelListener<TChannel> SecurityChannelListener
            {
                get
                {
                    return (SecurityChannelListener<TChannel>)base.ChannelManager;
                }
            }
 
            protected override TChannel OnAcceptChannel(TChannel innerChannel)
            {
                SecurityChannelListener<TChannel> listener = this.SecurityChannelListener;
                SecurityProtocol securityProtocol = listener.SecurityProtocolFactory.CreateSecurityProtocol(
                    null,
                    null,
                    this.listenerSecurityProtocolState,
                    typeof(TChannel) == typeof(IReplyChannel) || typeof(TChannel) == typeof(IReplySessionChannel), TimeSpan.Zero);
                object securityChannel;
                if (typeof(TChannel) == typeof(IInputChannel))
                {
                    securityChannel = new SecurityInputChannel(listener, (IInputChannel)innerChannel, securityProtocol, listener.settingsLifetimeManager);
                }
                else if (typeof(TChannel) == typeof(IInputSessionChannel))
                {
                    securityChannel = new SecurityInputSessionChannel(listener, (IInputSessionChannel)innerChannel, securityProtocol, listener.settingsLifetimeManager);
                }
                else if (listener.SupportsDuplex && typeof(TChannel) == typeof(IDuplexChannel))
                {
                    securityChannel = new SecurityDuplexChannel(listener, (IDuplexChannel)innerChannel, securityProtocol, listener.settingsLifetimeManager);
                }
                else if (listener.SupportsDuplex && typeof(TChannel) == typeof(IDuplexSessionChannel))
                {
                    securityChannel = new SecurityDuplexSessionChannel(listener, (IDuplexSessionChannel)innerChannel, securityProtocol, listener.settingsLifetimeManager);
                }
                else if (listener.SupportsRequestReply && typeof(TChannel) == typeof(IReplyChannel))
                {
                    securityChannel = new SecurityReplyChannel(listener, (IReplyChannel)innerChannel, securityProtocol, listener.settingsLifetimeManager);
                }
                else if (listener.SupportsRequestReply && typeof(TChannel) == typeof(IReplySessionChannel))
                {
                    securityChannel = new SecurityReplySessionChannel(listener, (IReplySessionChannel)innerChannel, securityProtocol, listener.settingsLifetimeManager);
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.UnsupportedChannelInterfaceType, typeof(TChannel))));
                }
 
                return (TChannel)securityChannel;
            }
        }
 
        class CloseSharedStateAsyncResult : AsyncResult
        {
            static AsyncCallback lifetimeManagerCloseCallback = Fx.ThunkCallback(new AsyncCallback(LifetimeManagerCloseCallback));
            SecurityChannelListener<TChannel> securityListener;
 
            public CloseSharedStateAsyncResult(SecurityChannelListener<TChannel> securityListener, TimeSpan timeout, AsyncCallback callback, object state)
                : base(callback, state)
            {
                this.securityListener = securityListener;
                lock (this.securityListener.ThisLock)
                {
                    if (this.securityListener.hasSecurityStateReference)
                    {
                        this.securityListener.hasSecurityStateReference = false;
                        IAsyncResult result = this.securityListener.settingsLifetimeManager.BeginClose(timeout, lifetimeManagerCloseCallback, this);
                        if (!result.CompletedSynchronously)
                        {
                            return;
                        }
                        this.securityListener.settingsLifetimeManager.EndClose(result);
                    }
                }
                Complete(true);
            }
 
            static void LifetimeManagerCloseCallback(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                {
                    return;
                }
                CloseSharedStateAsyncResult self = (CloseSharedStateAsyncResult)(result.AsyncState);
                Exception completionException = null;
                try
                {
                    self.securityListener.settingsLifetimeManager.EndClose(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<CloseSharedStateAsyncResult>(result);
            }
        }
 
        class OpenListenerStateAsyncResult : AsyncResult
        {
            static AsyncCallback lifetimeManagerOpenCallback = Fx.ThunkCallback(new AsyncCallback(LifetimeManagerOpenCallback));
            SecurityChannelListener<TChannel> securityListener;
 
            public OpenListenerStateAsyncResult(SecurityChannelListener<TChannel> securityListener, TimeSpan timeout, AsyncCallback callback, object state)
                : base(callback, state)
            {
                this.securityListener = securityListener;
 
                bool openState;
                lock (this.securityListener.ThisLock)
                {
                    // if an abort happened during the Open, return
                    if (this.securityListener.State == CommunicationState.Closed || this.securityListener.State == CommunicationState.Closing)
                    {
                        openState = false;
                    }
                    else
                    {
                        openState = true;
                        this.securityListener.InitializeListenerSecurityState();
                    }
                }
                if (openState)
                {
                    IAsyncResult result = this.securityListener.settingsLifetimeManager.BeginOpen(timeout, lifetimeManagerOpenCallback, this);
                    if (!result.CompletedSynchronously)
                    {
                        return;
                    }
                    this.securityListener.settingsLifetimeManager.EndOpen(result);
                }
                Complete(true);
            }
 
            static void LifetimeManagerOpenCallback(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                {
                    return;
                }
                OpenListenerStateAsyncResult self = (OpenListenerStateAsyncResult)(result.AsyncState);
                Exception completionException = null;
                try
                {
                    self.securityListener.settingsLifetimeManager.EndOpen(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<OpenListenerStateAsyncResult>(result);
            }
        }
 
        abstract class ServerSecurityChannel<UChannel> : SecurityChannel<UChannel> where UChannel : class, IChannel
        {
            static MessageFault secureConversationCloseNotSupportedFault;
            string secureConversationCloseAction;
            SecurityListenerSettingsLifetimeManager settingsLifetimeManager;
            bool hasSecurityStateReference;
 
            protected ServerSecurityChannel(ChannelManagerBase channelManager, UChannel innerChannel, SecurityProtocol securityProtocol, SecurityListenerSettingsLifetimeManager settingsLifetimeManager)
                : base(channelManager, innerChannel, securityProtocol)
            {
                if (settingsLifetimeManager == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("settingsLifetimeManager");
                }
                this.settingsLifetimeManager = settingsLifetimeManager;
            }
 
            internal void InternalThrowIfFaulted()
            {
                this.ThrowIfFaulted();
            }
 
            protected override void OnOpened()
            {
                base.OnOpened();
                this.secureConversationCloseAction = this.SecurityProtocol.SecurityProtocolFactory.StandardsManager.SecureConversationDriver.CloseAction.Value;
            }
 
            protected override void OnOpen(TimeSpan timeout)
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                this.SecurityProtocol.Open(timeoutHelper.RemainingTime());
                base.OnOpen(timeoutHelper.RemainingTime());
                lock (ThisLock)
                {
                    // if an abort happened concurrently with the Open, then dont add a reference
                    if (this.State == CommunicationState.Closed || this.State == CommunicationState.Closing)
                    {
                        return;
                    }
                    this.hasSecurityStateReference = true;
                    this.settingsLifetimeManager.AddReference();
                }
            }
 
            protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                this.SecurityProtocol.Open(timeoutHelper.RemainingTime());
                return base.OnBeginOpen(timeoutHelper.RemainingTime(), callback, state);
            }
 
            protected override void OnEndOpen(IAsyncResult result)
            {
                base.OnEndOpen(result);
                lock (ThisLock)
                {
                    // if an abort happened concurrently with the Open, then dont add a reference
                    if (this.State == CommunicationState.Closed || this.State == CommunicationState.Closing)
                    {
                        return;
                    }
                    this.hasSecurityStateReference = true;
                    this.settingsLifetimeManager.AddReference();
                }
            }
 
            protected override void OnAbort()
            {
                lock (ThisLock)
                {
                    if (this.hasSecurityStateReference)
                    {
                        hasSecurityStateReference = false;
                        this.settingsLifetimeManager.Abort();
                    }
                }
                base.OnAbort();
            }
 
            protected override void OnFaulted()
            {
                lock (ThisLock)
                {
                    if (this.hasSecurityStateReference)
                    {
                        hasSecurityStateReference = false;
                        this.settingsLifetimeManager.Abort();
                    }
                }
                base.OnFaulted();
            }
 
            protected override void OnClose(TimeSpan timeout)
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                lock (ThisLock)
                {
                    if (this.hasSecurityStateReference)
                    {
                        hasSecurityStateReference = false;
                        this.settingsLifetimeManager.Close(timeoutHelper.RemainingTime());
                    }
                }
                base.OnClose(timeoutHelper.RemainingTime());
            }
 
            protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return new ChainedAsyncResult(timeout, callback, state, this.OnBeginCloseSharedState, this.OnEndCloseSharedState, base.OnBeginClose, base.OnEndClose);
            }
 
            protected override void OnEndClose(IAsyncResult result)
            {
                ChainedAsyncResult.End(result);
            }
 
            IAsyncResult OnBeginCloseSharedState(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return new CloseSharedStateAsyncResult(this, timeout, callback, state);
            }
 
            void OnEndCloseSharedState(IAsyncResult result)
            {
                CloseSharedStateAsyncResult.End(result);
            }
 
            static MessageFault GetSecureConversationCloseNotSupportedFault()
            {
                if (secureConversationCloseNotSupportedFault == null)
                {
                    FaultCode faultCode = FaultCode.CreateSenderFaultCode(DotNetSecurityStrings.SecureConversationCancelNotAllowedFault, DotNetSecurityStrings.Namespace);
                    FaultReason faultReason = new FaultReason(SR.GetString(SR.SecureConversationCancelNotAllowedFaultReason), System.Globalization.CultureInfo.InvariantCulture);
                    secureConversationCloseNotSupportedFault = MessageFault.CreateFault(faultCode, faultReason);
                }
                return secureConversationCloseNotSupportedFault;
            }
 
            void ThrowIfSecureConversationCloseMessage(Message message)
            {
                if (message.Headers.Action == this.secureConversationCloseAction)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.SecureConversationCancelNotAllowedFaultReason), null, GetSecureConversationCloseNotSupportedFault()));
                }
            }
 
            [Fx.Tag.SecurityNote(Critical = "Delegates to a SecurityCritical method in HostedThreadData." +
                "Caller must ensure that function is called appropriately and result is guarded and Dispose()'d correctly.")]
            [SecurityCritical]
            IDisposable ApplyHostingIntegrationContext(Message message)
            {
                IDisposable hostingContext = null;
                IAspNetMessageProperty hostingProperty = AspNetEnvironment.Current.GetHostingProperty(message);
                if (hostingProperty != null)
                {
                    hostingContext = hostingProperty.ApplyIntegrationContext();
                }
                return hostingContext;
            }
 
            [Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical method ApplyHostingIntegrationContext.",
                Safe = "Does call properly and calls Dispose, doesn't leak control of the IDisposable out of the function.")]
            [SecuritySafeCritical]
            internal SecurityProtocolCorrelationState VerifyIncomingMessage(ref Message message, TimeSpan timeout, params SecurityProtocolCorrelationState[] correlationState)
            {
                if (message == null)
                {
                    return null;
                }
                ThrowIfSecureConversationCloseMessage(message);
                using (this.ApplyHostingIntegrationContext(message))
                {
                    return this.SecurityProtocol.VerifyIncomingMessage(ref message, timeout, correlationState);
                }
            }
 
            [Fx.Tag.SecurityNote(Critical = "Calls SecurityCritical method ApplyHostingIntegrationContext.",
                Safe = "Does call properly and calls Dispose, doesn't leak control of the IDisposable out of the function.")]
            [SecuritySafeCritical]
            internal void VerifyIncomingMessage(ref Message message, TimeSpan timeout)
            {
                if (message == null)
                {
                    return;
                }
                ThrowIfSecureConversationCloseMessage(message);
                using (this.ApplyHostingIntegrationContext(message))
                {
                    this.SecurityProtocol.VerifyIncomingMessage(ref message, timeout);
                }
            }
 
            class CloseSharedStateAsyncResult : AsyncResult
            {
                static AsyncCallback lifetimeManagerCloseCallback = Fx.ThunkCallback(new AsyncCallback(LifetimeManagerCloseCallback));
                ServerSecurityChannel<UChannel> securityChannel;
 
                public CloseSharedStateAsyncResult(ServerSecurityChannel<UChannel> securityChannel, TimeSpan timeout, AsyncCallback callback, object state)
                    : base(callback, state)
                {
                    this.securityChannel = securityChannel;
                    lock (this.securityChannel.ThisLock)
                    {
                        if (this.securityChannel.hasSecurityStateReference)
                        {
                            this.securityChannel.hasSecurityStateReference = false;
                            IAsyncResult result = this.securityChannel.settingsLifetimeManager.BeginClose(timeout, lifetimeManagerCloseCallback, this);
                            if (!result.CompletedSynchronously)
                            {
                                return;
                            }
                            this.securityChannel.settingsLifetimeManager.EndClose(result);
                        }
                    }
                    Complete(true);
                }
 
                static void LifetimeManagerCloseCallback(IAsyncResult result)
                {
                    if (result.CompletedSynchronously)
                    {
                        return;
                    }
                    CloseSharedStateAsyncResult self = (CloseSharedStateAsyncResult)(result.AsyncState);
                    Exception completionException = null;
                    try
                    {
                        self.securityChannel.settingsLifetimeManager.EndClose(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<CloseSharedStateAsyncResult>(result);
                }
            }
        }
 
        class SecurityInputChannel : ServerSecurityChannel<IInputChannel>, IInputChannel
        {
            public SecurityInputChannel(ChannelManagerBase channelManager, IInputChannel innerChannel, SecurityProtocol securityProtocol, SecurityListenerSettingsLifetimeManager settingsLifetimeManager)
                : base(channelManager, innerChannel, securityProtocol, settingsLifetimeManager)
            {
            }
 
            public EndpointAddress LocalAddress
            {
                get { return this.InnerChannel.LocalAddress; }
            }
 
            public Message Receive()
            {
                return this.Receive(this.DefaultReceiveTimeout);
            }
 
            public Message Receive(TimeSpan timeout)
            {
                return InputChannel.HelpReceive(this, timeout);
            }
 
            public IAsyncResult BeginReceive(AsyncCallback callback, object state)
            {
                return this.BeginReceive(this.DefaultReceiveTimeout, callback, state);
            }
 
            public IAsyncResult BeginReceive(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return InputChannel.HelpBeginReceive(this, timeout, callback, state);
            }
 
            public Message EndReceive(IAsyncResult result)
            {
                return InputChannel.HelpEndReceive(result);
            }
 
            public virtual IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state)
            {
                if (DoneReceivingInCurrentState())
                {
                    return new DoneReceivingAsyncResult(callback, state);
                }
 
                return new InputChannelReceiveMessageAndVerifySecurityAsyncResult(this, this.InnerChannel, timeout, callback, state);
            }
 
            public virtual bool EndTryReceive(IAsyncResult result, out Message message)
            {
                DoneReceivingAsyncResult doneRecevingResult = result as DoneReceivingAsyncResult;
                if (doneRecevingResult != null)
                {
                    return DoneReceivingAsyncResult.End(doneRecevingResult, out message);
                }
 
                return InputChannelReceiveMessageAndVerifySecurityAsyncResult.End(result, out message);
            }
 
            public virtual bool TryReceive(TimeSpan timeout, out Message message)
            {
                if (DoneReceivingInCurrentState())
                {
                    message = null;
                    return true;
                }
 
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                while (true)
                {
                    if (this.State == CommunicationState.Closed || this.State == CommunicationState.Faulted)
                    {
                        message = null;
                        break;
                    }
 
                    if (!this.InnerChannel.TryReceive(timeoutHelper.RemainingTime(), out message))
                    {
                        return false;
                    }
 
                    try
                    {
                        this.VerifyIncomingMessage(ref message, timeoutHelper.RemainingTime());
                        break;
                    }
                    catch (MessageSecurityException)
                    {
                        message = null;
                        if (timeoutHelper.RemainingTime() == TimeSpan.Zero)
                        {
                            return false;
                        }
                    }
                }
                ThrowIfFaulted();
                return true;
            }
 
            public bool WaitForMessage(TimeSpan timeout)
            {
                return this.InnerChannel.WaitForMessage(timeout);
            }
 
            public IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return this.InnerChannel.BeginWaitForMessage(timeout, callback, state);
            }
 
            public bool EndWaitForMessage(IAsyncResult result)
            {
                return this.InnerChannel.EndWaitForMessage(result);
            }
        }
 
        sealed class SecurityInputSessionChannel : SecurityInputChannel, IInputSessionChannel
        {
            public SecurityInputSessionChannel(ChannelManagerBase channelManager, IInputSessionChannel innerChannel, SecurityProtocol securityProtocol, SecurityListenerSettingsLifetimeManager settingsLifetimeManager)
                : base(channelManager, innerChannel, securityProtocol, settingsLifetimeManager)
            {
            }
 
            public IInputSession Session
            {
                get { return ((IInputSessionChannel)this.InnerChannel).Session; }
            }
        }
 
        class SecurityDuplexChannel : SecurityInputChannel, IDuplexChannel
        {
            readonly IDuplexChannel innerDuplexChannel;
 
            public SecurityDuplexChannel(ChannelManagerBase channelManager, IDuplexChannel innerChannel, SecurityProtocol securityProtocol, SecurityListenerSettingsLifetimeManager settingsLifetimeManager)
                : base(channelManager, innerChannel, securityProtocol, settingsLifetimeManager)
            {
                this.innerDuplexChannel = innerChannel;
            }
 
            public EndpointAddress RemoteAddress
            {
                get { return this.innerDuplexChannel.RemoteAddress; }
            }
 
            public Uri Via
            {
                get { return this.innerDuplexChannel.Via; }
            }
 
            protected IDuplexChannel InnerDuplexChannel
            {
                get { return this.innerDuplexChannel; }
            }
 
            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)
            {
                ThrowIfFaulted();
                ThrowIfDisposedOrNotOpen(message);
                return new OutputChannelSendAsyncResult(message, this.SecurityProtocol, this.innerDuplexChannel, timeout, callback, state);
            }
 
            public void EndSend(IAsyncResult result)
            {
                OutputChannelSendAsyncResult.End(result);
            }
 
            public void Send(Message message)
            {
                this.Send(message, this.DefaultSendTimeout);
            }
 
            public void Send(Message message, TimeSpan timeout)
            {
                ThrowIfFaulted();
                ThrowIfDisposedOrNotOpen(message);
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                this.SecurityProtocol.SecureOutgoingMessage(ref message, timeoutHelper.RemainingTime());
                this.innerDuplexChannel.Send(message, timeoutHelper.RemainingTime());
            }
        }
 
        sealed class SecurityDuplexSessionChannel : SecurityDuplexChannel, IDuplexSessionChannel
        {
            bool sendUnsecuredFaults;
 
            public SecurityDuplexSessionChannel(SecurityChannelListener<TChannel> channelManager, IDuplexSessionChannel innerChannel, SecurityProtocol securityProtocol, SecurityListenerSettingsLifetimeManager settingsLifetimeManager)
                : base(channelManager, innerChannel, securityProtocol, settingsLifetimeManager)
            {
                sendUnsecuredFaults = channelManager.SendUnsecuredFaults;
            }
 
            public IDuplexSession Session
            {
                get { return ((IDuplexSessionChannel)this.InnerChannel).Session; }
            }
 
            public bool SendUnsecuredFaults
            {
                get { return this.sendUnsecuredFaults; }
            }
 
            void SendFaultIfRequired(Exception e, Message unverifiedMessage, TimeSpan timeout)
            {
                if (!sendUnsecuredFaults)
                {
                    return;
                }
                MessageFault fault = SecurityUtils.CreateSecurityMessageFault(e, this.SecurityProtocol.SecurityProtocolFactory.StandardsManager);
                if (fault == null)
                {
                    return;
                }
                try
                {
                    using (Message faultMessage = Message.CreateMessage(unverifiedMessage.Version, fault, unverifiedMessage.Version.Addressing.DefaultFaultAction))
                    {
                        if (unverifiedMessage.Headers.MessageId != null)
                            faultMessage.InitializeReply(unverifiedMessage);
 
                        ((IDuplexChannel)this.InnerChannel).Send(faultMessage, timeout);
                    }
                }
#pragma warning suppress 56500 // covered by FxCOP
                catch (Exception ex)
                {
                    if (Fx.IsFatal(ex))
                        throw;
 
                    // ---- exceptions
                }
            }
 
            public override bool TryReceive(TimeSpan timeout, out Message message)
            {
                if (DoneReceivingInCurrentState())
                {
                    message = null;
                    return true;
                }
 
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                while (true)
                {
                    if (this.State == CommunicationState.Closed || this.State == CommunicationState.Faulted)
                    {
                        message = null;
                        break;
                    }
 
                    if (!this.InnerChannel.TryReceive(timeoutHelper.RemainingTime(), out message))
                    {
                        return false;
                    }
 
                    Message unverifiedMessage = message;
                    Exception securityException = null;
                    try
                    {
                        this.VerifyIncomingMessage(ref message, timeoutHelper.RemainingTime());
                        break;
                    }
                    catch (MessageSecurityException e)
                    {
                        message = null;
                        securityException = e;
                    }
                    if (securityException != null)
                    {
                        SendFaultIfRequired(securityException, unverifiedMessage, timeoutHelper.RemainingTime());
                        if (timeoutHelper.RemainingTime() == TimeSpan.Zero)
                        {
                            return false;
                        }
                    }
                }
                ThrowIfFaulted();
                return true;
            }
 
            public override IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state)
            {
                if (DoneReceivingInCurrentState())
                {
                    return new DoneReceivingAsyncResult(callback, state);
                }
 
                return new DuplexSessionReceiveMessageAndVerifySecurityAsyncResult(this, this.InnerDuplexChannel, timeout, callback, state);
            }
 
            public override bool EndTryReceive(IAsyncResult result, out Message message)
            {
                DoneReceivingAsyncResult doneRecevingResult = result as DoneReceivingAsyncResult;
                if (doneRecevingResult != null)
                {
                    return DoneReceivingAsyncResult.End(doneRecevingResult, out message);
                }
 
                return DuplexSessionReceiveMessageAndVerifySecurityAsyncResult.End(result, out message);
            }
        }
 
        class SecurityReplyChannel : ServerSecurityChannel<IReplyChannel>, IReplyChannel
        {
            bool sendUnsecuredFaults;
 
            public SecurityReplyChannel(SecurityChannelListener<TChannel> channelManager, IReplyChannel innerChannel, SecurityProtocol securityProtocol, SecurityListenerSettingsLifetimeManager settingsLifetimeManager)
                : base(channelManager, innerChannel, securityProtocol, settingsLifetimeManager)
            {
                sendUnsecuredFaults = channelManager.SendUnsecuredFaults;
            }
 
            public EndpointAddress LocalAddress
            {
                get { return this.InnerChannel.LocalAddress; }
            }
 
            public bool SendUnsecuredFaults
            {
                get { return this.sendUnsecuredFaults; }
            }
 
            public RequestContext ReceiveRequest()
            {
                return this.ReceiveRequest(this.DefaultReceiveTimeout);
            }
 
            public RequestContext ReceiveRequest(TimeSpan timeout)
            {
                return ReplyChannel.HelpReceiveRequest(this, timeout);
            }
 
            public IAsyncResult BeginReceiveRequest(AsyncCallback callback, object state)
            {
                return this.BeginReceiveRequest(this.DefaultReceiveTimeout, callback, state);
            }
 
            public IAsyncResult BeginReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return ReplyChannel.HelpBeginReceiveRequest(this, timeout, callback, state);
            }
 
            public RequestContext EndReceiveRequest(IAsyncResult result)
            {
                return ReplyChannel.HelpEndReceiveRequest(result);
            }
 
            public IAsyncResult BeginTryReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)
            {
                if (DoneReceivingInCurrentState())
                {
                    return new DoneReceivingAsyncResult(callback, state);
                }
 
                return new ReceiveRequestAndVerifySecurityAsyncResult(this, this.InnerChannel, timeout, callback, state);
            }
 
            public bool EndTryReceiveRequest(IAsyncResult result, out RequestContext requestContext)
            {
                DoneReceivingAsyncResult doneRecevingResult = result as DoneReceivingAsyncResult;
                if (doneRecevingResult != null)
                {
                    return DoneReceivingAsyncResult.End(doneRecevingResult, out requestContext);
                }
 
                return ReceiveRequestAndVerifySecurityAsyncResult.End(result, out requestContext);
            }
 
            internal RequestContext ProcessReceivedRequest(RequestContext requestContext, TimeSpan timeout)
            {
                if (requestContext == null)
                {
                    return null;
                }
                Message message = requestContext.RequestMessage;
                if (message == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.ReceivedMessageInRequestContextNull, this.InnerChannel)));
                }
                SecurityProtocolCorrelationState correlationState = this.VerifyIncomingMessage(ref message, timeout, null);
                return new SecurityRequestContext(message, requestContext, this.SecurityProtocol, correlationState, this.DefaultSendTimeout, this.DefaultCloseTimeout);
            }
 
            void SendFaultIfRequired(Exception e, RequestContext innerContext, TimeSpan timeout)
            {
                if (!sendUnsecuredFaults)
                {
                    return;
                }
                MessageFault fault = SecurityUtils.CreateSecurityMessageFault(e, this.SecurityProtocol.SecurityProtocolFactory.StandardsManager);
                if (fault == null)
                {
                    return;
                }
                Message requestMessage = innerContext.RequestMessage;
                Message faultMessage = Message.CreateMessage(requestMessage.Version, fault, requestMessage.Version.Addressing.DefaultFaultAction);
                if (requestMessage.Headers.MessageId != null)
                    faultMessage.InitializeReply(requestMessage);
 
                try
                {
                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                    innerContext.Reply(faultMessage, timeoutHelper.RemainingTime());
                    innerContext.Close(timeoutHelper.RemainingTime());
                }
#pragma warning suppress 56500 // covered by FxCOP
                catch (Exception ex)
                {
                    if (Fx.IsFatal(ex))
                    {
                        throw;
                    }
 
                    // eat up exceptions
                }
                finally
                {
                    faultMessage.Close();
                    innerContext.Abort();
                }
            }
 
            public bool TryReceiveRequest(TimeSpan timeout, out RequestContext requestContext)
            {
                if (DoneReceivingInCurrentState())
                {
                    requestContext = null;
                    return true;
                }
 
                requestContext = null;
                RequestContext innerContext;
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                while (true)
                {
                    if (this.State == CommunicationState.Closed || this.State == CommunicationState.Faulted)
                    {
                        requestContext = null;
                        break;
                    }
 
                    if (!this.InnerChannel.TryReceiveRequest(timeoutHelper.RemainingTime(), out innerContext))
                    {
                        requestContext = null;
                        return false;
                    }
                    Exception securityException = null;
                    try
                    {
                        requestContext = ProcessReceivedRequest(innerContext, timeoutHelper.RemainingTime());
                        break;
                    }
                    catch (MessageSecurityException e)
                    {
                        securityException = e;
                    }
                    if (securityException != null)
                    {
                        SendFaultIfRequired(securityException, innerContext, timeoutHelper.RemainingTime());
                        if (timeoutHelper.RemainingTime() == TimeSpan.Zero)
                        {
                            return false;
                        }
                    }
                }
                ThrowIfFaulted();
                return true;
            }
 
            public bool WaitForRequest(TimeSpan timeout)
            {
                return this.InnerChannel.WaitForRequest(timeout);
            }
 
            public IAsyncResult BeginWaitForRequest(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return this.InnerChannel.BeginWaitForRequest(timeout, callback, state);
            }
 
            public bool EndWaitForRequest(IAsyncResult result)
            {
                return this.InnerChannel.EndWaitForRequest(result);
            }
        }
 
        sealed class SecurityReplySessionChannel : SecurityReplyChannel, IReplySessionChannel
        {
            public SecurityReplySessionChannel(SecurityChannelListener<TChannel> channelManager, IReplySessionChannel innerChannel, SecurityProtocol securityProtocol, SecurityListenerSettingsLifetimeManager settingsLifetimeManager)
                : base(channelManager, innerChannel, securityProtocol, settingsLifetimeManager)
            {
            }
 
            public IInputSession Session
            {
                get { return ((IReplySessionChannel)this.InnerChannel).Session; }
            }
        }
 
        sealed class SecurityRequestContext : RequestContextBase
        {
            readonly RequestContext innerContext;
            readonly SecurityProtocol securityProtocol;
            readonly SecurityProtocolCorrelationState correlationState;
 
            public SecurityRequestContext(Message requestMessage, RequestContext innerContext,
                SecurityProtocol securityProtocol, SecurityProtocolCorrelationState correlationState,
                TimeSpan defaultSendTimeout, TimeSpan defaultCloseTimeout)
                : base(requestMessage, defaultCloseTimeout, defaultSendTimeout)
            {
                this.innerContext = innerContext;
                this.securityProtocol = securityProtocol;
                this.correlationState = correlationState;
            }
 
            protected override void OnAbort()
            {
                this.innerContext.Abort();
            }
 
            protected override void OnClose(TimeSpan timeout)
            {
                this.innerContext.Close(timeout);
            }
 
            protected override IAsyncResult OnBeginReply(Message message, TimeSpan timeout, AsyncCallback callback, object state)
            {
                if (message != null)
                {
                    return new RequestContextSendAsyncResult(message, this.securityProtocol, this.innerContext, timeout,
                        callback, state, correlationState);
                }
                else
                {
                    return this.innerContext.BeginReply(message, timeout, callback, state);
                }
            }
 
            protected override void OnEndReply(IAsyncResult result)
            {
                if (result is RequestContextSendAsyncResult)
                {
                    RequestContextSendAsyncResult.End(result);
                }
                else
                {
                    this.innerContext.EndReply(result);
                }
            }
 
            protected override void OnReply(Message message, TimeSpan timeout)
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
                if (message != null)
                {
                    this.securityProtocol.SecureOutgoingMessage(ref message, timeoutHelper.RemainingTime(), correlationState);
                }
                this.innerContext.Reply(message, timeoutHelper.RemainingTime());
            }
 
            sealed class RequestContextSendAsyncResult : ApplySecurityAndSendAsyncResult<RequestContext>
            {
                public RequestContextSendAsyncResult(Message message, SecurityProtocol protocol, RequestContext context, TimeSpan timeout,
                    AsyncCallback callback, object state, SecurityProtocolCorrelationState correlationState)
                    : base(protocol, context, timeout, callback, state)
                {
                    this.Begin(message, correlationState);
                }
 
                protected override IAsyncResult BeginSendCore(RequestContext context, Message message, TimeSpan timeout, AsyncCallback callback, object state)
                {
                    return context.BeginReply(message, timeout, callback, state);
                }
 
                internal static void End(IAsyncResult result)
                {
                    RequestContextSendAsyncResult self = result as RequestContextSendAsyncResult;
                    OnEnd(self);
                }
 
                protected override void EndSendCore(RequestContext context, IAsyncResult result)
                {
                    context.EndReply(result);
                }
 
                protected override void OnSendCompleteCore(TimeSpan timeout)
                {
                }
            }
        }
 
        abstract class ReceiveItemAndVerifySecurityAsyncResult<TItem, UChannel> : AsyncResult
            where UChannel : class, IChannel
            where TItem : class
        {
            static AsyncCallback innerTryReceiveCompletedCallback = Fx.ThunkCallback(new AsyncCallback(InnerTryReceiveCompletedCallback));
            protected bool receiveCompleted;
            protected TimeoutHelper timeoutHelper;
            TItem innerItem;
            TItem item;
            ServerSecurityChannel<UChannel> channel;
            Message faultMessage;
 
            public ReceiveItemAndVerifySecurityAsyncResult(ServerSecurityChannel<UChannel> channel, TimeSpan timeout, AsyncCallback callback, object state)
                : base(callback, state)
            {
                this.timeoutHelper = new TimeoutHelper(timeout);
                this.channel = channel;
            }
 
            protected void Start()
            {
                bool completeSelf = false;
                Exception completeException = null;
 
                try
                {
                    completeSelf = StartInnerReceive();
                }
                catch (Exception ex)
                {
                    if (Fx.IsFatal(ex))
                    {
                        throw;
                    }
 
                    completeException = ex;
                }
 
                if (completeSelf || completeException != null)
                {
                    this.Complete(false, completeException);
                }
            }
 
            protected TItem Item
            {
                get { return this.item; }
            }
 
            protected bool ReceiveCompleted
            {
                get { return this.receiveCompleted; }
            }
 
            protected abstract bool CanSendFault { get; }
            protected abstract SecurityStandardsManager StandardsManager { get; }
            protected abstract IAsyncResult BeginTryReceiveItem(TimeSpan timeout, AsyncCallback callback, object state);
            protected abstract bool EndTryReceiveItem(IAsyncResult result, out TItem innerItem);
            protected abstract TItem ProcessInnerItem(TItem innerItem, TimeSpan timeout);
            protected abstract Message CreateFaultMessage(MessageFault fault, TItem innerItem);
            protected abstract IAsyncResult BeginSendFault(TItem innerItem, Message faultMessage, TimeSpan timeout, AsyncCallback callback, object state);
            protected abstract void EndSendFault(TItem innerItem, IAsyncResult result);
            protected abstract void CloseInnerItem(TItem innerItem, TimeSpan timeout);
            protected abstract void AbortInnerItem(TItem innerItem);
 
            bool StartInnerReceive()
            {
                try
                {
                    this.channel.InternalThrowIfFaulted();
                    if (this.channel.State == CommunicationState.Closed)
                    {
                        this.item = null;
                        this.receiveCompleted = true;
                        return true;
                    }
 
                    IAsyncResult asyncResult = BeginTryReceiveItem(timeoutHelper.RemainingTime(), innerTryReceiveCompletedCallback, this);
                    if (!asyncResult.CompletedSynchronously)
                    {
                        return false;
                    }
 
                    bool innerReceiveCompleted = this.EndTryReceiveItem(asyncResult, out this.innerItem);
                    if (!innerReceiveCompleted)
                    {
                        receiveCompleted = false;
                        return true;
                    }
                    else
                    {
                        return this.OnInnerReceiveDone();
                    }
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
 
                    this.Complete(false, e);
                    return false;
                }
            }
 
            static void InnerTryReceiveCompletedCallback(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                {
                    return;
                }
                ReceiveItemAndVerifySecurityAsyncResult<TItem, UChannel> thisResult = (ReceiveItemAndVerifySecurityAsyncResult<TItem, UChannel>)result.AsyncState;
                bool completeSelf = false;
                Exception completionException = null;
                try
                {
                    bool innerReceiveCompleted = thisResult.EndTryReceiveItem(result, out thisResult.innerItem);
                    if (!innerReceiveCompleted)
                    {
                        thisResult.receiveCompleted = false;
                        completeSelf = true;
                    }
                    else
                    {
                        completeSelf = thisResult.OnInnerReceiveDone();
                    }
                }
#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 OnInnerReceiveDone()
            {
                this.channel.InternalThrowIfFaulted();
                Exception securityException = null;
                try
                {
                    this.item = ProcessInnerItem(this.innerItem, this.timeoutHelper.RemainingTime());
                    this.receiveCompleted = true;
                }
#pragma warning suppress 56500 // covered by FxCOP
                catch (MessageSecurityException e)
                {
                    securityException = e;
                }
                if (securityException != null)
                {
                    if (CanSendFault)
                    {
                        bool sentFaultSync = this.OnSecurityException(securityException);
                        if (!sentFaultSync)
                        {
                            return false;
                        }
                    }
                    return OnFaultSent();
                }
                else
                {
                    return true;
                }
            }
 
            bool OnFaultSent()
            {
                this.innerItem = null;
                if (this.timeoutHelper.RemainingTime() == TimeSpan.Zero)
                {
                    this.receiveCompleted = false;
                    return true;
                }
                else
                {
                    return this.StartInnerReceive();
                }
            }
 
            bool OnSecurityException(Exception e)
            {
                MessageFault fault = SecurityUtils.CreateSecurityMessageFault(e, this.StandardsManager);
                if (fault == null)
                {
                    return true;
                }
                else
                {
                    this.faultMessage = CreateFaultMessage(fault, this.innerItem);
                    return this.SendFault(faultMessage, e);
                }
            }
 
            bool SendFault(Message faultMessage, Exception e)
            {
                bool wasFaultSentSync = false;
                try
                {
                    IAsyncResult result = this.BeginSendFault(this.innerItem, faultMessage, this.timeoutHelper.RemainingTime(), Fx.ThunkCallback(new AsyncCallback(SendFaultCallback)), e);
                    if (!result.CompletedSynchronously)
                    {
                        return false;
                    }
                    wasFaultSentSync = true;
                    this.EndSendFault(innerItem, result);
                    CloseInnerItem(innerItem, timeoutHelper.RemainingTime());
                }
#pragma warning suppress 56500 // covered by FxCOP
                catch (Exception ex)
                {
                    if (faultMessage != null)
                    {
                        faultMessage.Close();
                    }
 
                    if (Fx.IsFatal(ex))
                    {
                        throw;
                    }
                    // ---- exceptions
                }
                finally
                {
                    if (wasFaultSentSync)
                    {
                        AbortInnerItem(innerItem);
                        if (faultMessage != null)
                        {
                            faultMessage.Close();
                        }
                    }
                }
                return true;
            }
 
            void SendFaultCallback(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                {
                    return;
                }
                Exception e = (Exception)result.AsyncState;
                try
                {
                    this.EndSendFault(innerItem, result);
                    this.CloseInnerItem(this.innerItem, timeoutHelper.RemainingTime());
                }
#pragma warning suppress 56500 // covered by FxCOP
                catch (Exception ex)
                {
                    if (Fx.IsFatal(ex))
                    {
                        throw;
                    }
                    // ---- exceptions
                }
                finally
                {
                    if (this.faultMessage != null)
                    {
                        this.faultMessage.Close();
                    }
 
                    this.AbortInnerItem(this.innerItem);
                }
                // start off another receive
                bool completeSelf = false;
                Exception completionException = null;
                try
                {
                    completeSelf = this.OnFaultSent();
                }
                catch (Exception e2)
                {
                    if (Fx.IsFatal(e2))
                        throw;
                    completeSelf = true;
                    completionException = e2;
                }
                if (completeSelf)
                {
                    Complete(false, completionException);
                }
            }
        }
 
 
        sealed class ReceiveRequestAndVerifySecurityAsyncResult : ReceiveItemAndVerifySecurityAsyncResult<RequestContext, IReplyChannel>
        {
            SecurityReplyChannel channel;
            IReplyChannel innerChannel;
 
            public ReceiveRequestAndVerifySecurityAsyncResult(SecurityReplyChannel channel, IReplyChannel innerChannel, TimeSpan timeout, AsyncCallback callback, object state)
                : base(channel, timeout, callback, state)
            {
                this.channel = channel;
                this.innerChannel = innerChannel;
                ActionItem.Schedule(ReceiveMessage, this);
            }
 
            protected override bool CanSendFault
            {
                get { return this.channel.SendUnsecuredFaults; }
            }
 
            protected override SecurityStandardsManager StandardsManager
            {
                get { return this.channel.SecurityProtocol.SecurityProtocolFactory.StandardsManager; }
            }
 
            static void ReceiveMessage(object state)
            {
                ReceiveRequestAndVerifySecurityAsyncResult securityAsyncResult = state as ReceiveRequestAndVerifySecurityAsyncResult;
                if (securityAsyncResult == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException());
                }
 
                securityAsyncResult.Start();
            }
 
            protected override void AbortInnerItem(RequestContext innerItem)
            {
                innerItem.Abort();
            }
 
            protected override void CloseInnerItem(RequestContext innerItem, TimeSpan timeout)
            {
                innerItem.Close(timeout);
            }
 
            protected override IAsyncResult BeginTryReceiveItem(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return this.innerChannel.BeginTryReceiveRequest(timeout, callback, state);
            }
 
            protected override bool EndTryReceiveItem(IAsyncResult result, out RequestContext innerItem)
            {
                return this.innerChannel.EndTryReceiveRequest(result, out innerItem);
            }
 
            protected override RequestContext ProcessInnerItem(RequestContext innerItem, TimeSpan timeout)
            {
                return this.channel.ProcessReceivedRequest(innerItem, timeout);
            }
 
            protected override Message CreateFaultMessage(MessageFault fault, RequestContext innerItem)
            {
                Message requestMessage = innerItem.RequestMessage;
                Message faultMessage = Message.CreateMessage(requestMessage.Version, fault, requestMessage.Version.Addressing.DefaultFaultAction);
                if (requestMessage.Headers.MessageId != null)
                    faultMessage.InitializeReply(requestMessage);
                return faultMessage;
            }
 
            protected override IAsyncResult BeginSendFault(RequestContext innerItem, Message faultMessage, TimeSpan timeout, AsyncCallback callback, object state)
            {
                return innerItem.BeginReply(faultMessage, timeout, callback, state);
            }
 
            protected override void EndSendFault(RequestContext innerItem, IAsyncResult result)
            {
                innerItem.EndReply(result);
            }
 
            public static bool End(IAsyncResult result, out RequestContext requestContext)
            {
                ReceiveRequestAndVerifySecurityAsyncResult thisResult = AsyncResult.End<ReceiveRequestAndVerifySecurityAsyncResult>(result);
                requestContext = thisResult.Item;
                return thisResult.ReceiveCompleted;
            }
        }
 
        sealed class DuplexSessionReceiveMessageAndVerifySecurityAsyncResult : ReceiveItemAndVerifySecurityAsyncResult<Message, IInputChannel>
        {
            IDuplexChannel innerChannel;
            SecurityDuplexSessionChannel channel;
 
            public DuplexSessionReceiveMessageAndVerifySecurityAsyncResult(SecurityDuplexSessionChannel channel, IDuplexChannel innerChannel, TimeSpan timeout, AsyncCallback callback, object state)
                : base(channel, timeout, callback, state)
            {
                this.innerChannel = innerChannel;
                this.channel = channel;
                ActionItem.Schedule(ReceiveMessage, this);
            }
 
            protected override bool CanSendFault
            {
                get { return this.channel.SendUnsecuredFaults; }
            }
 
            protected override SecurityStandardsManager StandardsManager
            {
                get { return this.channel.SecurityProtocol.SecurityProtocolFactory.StandardsManager; }
            }
 
            static void ReceiveMessage(object state)
            {
                DuplexSessionReceiveMessageAndVerifySecurityAsyncResult securityAsyncResult = state as DuplexSessionReceiveMessageAndVerifySecurityAsyncResult;
                if (securityAsyncResult != null)
                {
                    securityAsyncResult.Start();
                }
            }
 
            protected override void AbortInnerItem(Message innerItem)
            {
            }
 
            protected override void CloseInnerItem(Message innerItem, TimeSpan timeout)
            {
                innerItem.Close();
            }
 
            protected override IAsyncResult BeginTryReceiveItem(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return this.innerChannel.BeginTryReceive(timeout, callback, state);
            }
 
            protected override bool EndTryReceiveItem(IAsyncResult result, out Message innerItem)
            {
                return this.innerChannel.EndTryReceive(result, out innerItem);
            }
 
            protected override Message ProcessInnerItem(Message innerItem, TimeSpan timeout)
            {
                if (innerItem == null)
                {
                    return null;
                }
                Message item = innerItem;
                this.channel.VerifyIncomingMessage(ref item, timeout);
                return item;
            }
 
            protected override Message CreateFaultMessage(MessageFault fault, Message innerItem)
            {
                Message faultMessage = Message.CreateMessage(innerItem.Version, fault, innerItem.Version.Addressing.DefaultFaultAction);
                if (innerItem.Headers.MessageId != null)
                    faultMessage.InitializeReply(innerItem);
                return faultMessage;
            }
 
            protected override IAsyncResult BeginSendFault(Message innerItem, Message faultMessage, TimeSpan timeout, AsyncCallback callback, object state)
            {
                return this.innerChannel.BeginSend(faultMessage, timeout, callback, state);
            }
 
            protected override void EndSendFault(Message innerItem, IAsyncResult result)
            {
                this.innerChannel.EndSend(result);
            }
 
            public static bool End(IAsyncResult result, out Message message)
            {
                DuplexSessionReceiveMessageAndVerifySecurityAsyncResult thisResult = AsyncResult.End<DuplexSessionReceiveMessageAndVerifySecurityAsyncResult>(result);
                message = thisResult.Item;
                return thisResult.ReceiveCompleted;
            }
        }
 
 
        sealed class InputChannelReceiveMessageAndVerifySecurityAsyncResult : ReceiveItemAndVerifySecurityAsyncResult<Message, IInputChannel>
        {
            IInputChannel innerChannel;
            SecurityInputChannel channel;
 
            public InputChannelReceiveMessageAndVerifySecurityAsyncResult(SecurityInputChannel channel, IInputChannel innerChannel, TimeSpan timeout, AsyncCallback callback, object state)
                : base(channel, timeout, callback, state)
            {
                this.innerChannel = innerChannel;
                this.channel = channel;
                ActionItem.Schedule(ReceiveMessage, this);
            }
 
            protected override SecurityStandardsManager StandardsManager
            {
                get { return this.channel.SecurityProtocol.SecurityProtocolFactory.StandardsManager; }
            }
 
            static void ReceiveMessage(object state)
            {
                InputChannelReceiveMessageAndVerifySecurityAsyncResult securityAsyncResult = state as InputChannelReceiveMessageAndVerifySecurityAsyncResult;
                if (securityAsyncResult == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException());
                }
 
                securityAsyncResult.Start();
            }
 
            protected override bool CanSendFault
            {
                get
                {
                    return false;
                }
            }
 
            protected override void AbortInnerItem(Message innerItem)
            {
            }
 
            protected override void CloseInnerItem(Message innerItem, TimeSpan timeout)
            {
                innerItem.Close();
            }
 
            protected override IAsyncResult BeginTryReceiveItem(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return this.innerChannel.BeginTryReceive(timeout, callback, state);
            }
 
            protected override bool EndTryReceiveItem(IAsyncResult result, out Message innerItem)
            {
                return this.innerChannel.EndTryReceive(result, out innerItem);
            }
 
            protected override Message ProcessInnerItem(Message innerItem, TimeSpan timeout)
            {
                if (innerItem == null)
                {
                    return null;
                }
                Message item = innerItem;
                this.channel.VerifyIncomingMessage(ref item, timeout);
                return item;
            }
 
            protected override Message CreateFaultMessage(MessageFault fault, Message innerItem)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
            }
 
            protected override IAsyncResult BeginSendFault(Message innerItem, Message faultMessage, TimeSpan timeout, AsyncCallback callback, object state)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
            }
 
            protected override void EndSendFault(Message innerItem, IAsyncResult result)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
            }
 
            public static bool End(IAsyncResult result, out Message message)
            {
                InputChannelReceiveMessageAndVerifySecurityAsyncResult thisResult = AsyncResult.End<InputChannelReceiveMessageAndVerifySecurityAsyncResult>(result);
                message = thisResult.Item;
                return thisResult.ReceiveCompleted;
            }
        }
    }
}