File: FrameworkFork\System.ServiceModel\System\ServiceModel\Channels\ConnectionOrientedTransportChannelFactory.cs
Web Access
Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.Runtime;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
 
namespace System.ServiceModel.Channels
{
    internal abstract class ConnectionOrientedTransportChannelFactory<TChannel> : TransportChannelFactory<TChannel>, IConnectionOrientedTransportChannelFactorySettings
    {
        private int _connectionBufferSize;
        private IConnectionInitiator _connectionInitiator;
 
        private ConnectionPool _connectionPool;
        private string _connectionPoolGroupName;
        private bool _exposeConnectionProperty;
        private TimeSpan _idleTimeout;
        private int _maxBufferSize;
        private int _maxOutboundConnectionsPerEndpoint;
        private TimeSpan _maxOutputDelay;
        private TransferMode _transferMode;
        private ISecurityCapabilities _securityCapabilities;
        private StreamUpgradeProvider _upgrade;
        private bool _flowIdentity;
 
        internal ConnectionOrientedTransportChannelFactory(
            ConnectionOrientedTransportBindingElement bindingElement, BindingContext context,
            string connectionPoolGroupName, TimeSpan idleTimeout, int maxOutboundConnectionsPerEndpoint, bool supportsImpersonationDuringAsyncOpen)
            : base(bindingElement, context)
        {
            if (bindingElement.TransferMode == TransferMode.Buffered && bindingElement.MaxReceivedMessageSize > int.MaxValue)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new ArgumentOutOfRangeException("bindingElement.MaxReceivedMessageSize",
                    SRServiceModel.MaxReceivedMessageSizeMustBeInIntegerRange));
            }
 
            _connectionBufferSize = bindingElement.ConnectionBufferSize;
            _connectionPoolGroupName = connectionPoolGroupName;
            _exposeConnectionProperty = bindingElement.ExposeConnectionProperty;
            _idleTimeout = idleTimeout;
            _maxBufferSize = bindingElement.MaxBufferSize;
            _maxOutboundConnectionsPerEndpoint = maxOutboundConnectionsPerEndpoint;
            _maxOutputDelay = bindingElement.MaxOutputDelay;
            _transferMode = bindingElement.TransferMode;
 
            Collection<StreamUpgradeBindingElement> upgradeBindingElements =
                context.BindingParameters.FindAll<StreamUpgradeBindingElement>();
 
            if (upgradeBindingElements.Count > 1)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRServiceModel.MultipleStreamUpgradeProvidersInParameters));
            }
            else if ((upgradeBindingElements.Count == 1) && this.SupportsUpgrade(upgradeBindingElements[0]))
            {
                _upgrade = upgradeBindingElements[0].BuildClientStreamUpgradeProvider(context);
                context.BindingParameters.Remove<StreamUpgradeBindingElement>();
                _securityCapabilities = upgradeBindingElements[0].GetProperty<ISecurityCapabilities>(context);
                // flow the identity only if the channel factory supports impersonating during an async open AND
                // there is the binding is configured with security
                _flowIdentity = supportsImpersonationDuringAsyncOpen;
            }
        }
 
        public int ConnectionBufferSize
        {
            get
            {
                return _connectionBufferSize;
            }
        }
 
        internal IConnectionInitiator ConnectionInitiator
        {
            get
            {
                if (_connectionInitiator == null)
                {
                    lock (ThisLock)
                    {
                        if (_connectionInitiator == null)
                        {
                            _connectionInitiator = GetConnectionInitiator();
                        }
                    }
                }
 
                return _connectionInitiator;
            }
        }
 
        public string ConnectionPoolGroupName
        {
            get
            {
                return _connectionPoolGroupName;
            }
        }
 
        public TimeSpan IdleTimeout
        {
            get
            {
                return _idleTimeout;
            }
        }
 
        public int MaxBufferSize
        {
            get
            {
                return _maxBufferSize;
            }
        }
 
        public int MaxOutboundConnectionsPerEndpoint
        {
            get
            {
                return _maxOutboundConnectionsPerEndpoint;
            }
        }
 
        public TimeSpan MaxOutputDelay
        {
            get
            {
                return _maxOutputDelay;
            }
        }
 
        public StreamUpgradeProvider Upgrade
        {
            get
            {
                StreamUpgradeProvider localUpgrade = _upgrade;
                CommunicationObjectInternal.ThrowIfDisposed(this);
                return localUpgrade;
            }
        }
 
        public TransferMode TransferMode
        {
            get
            {
                return _transferMode;
            }
        }
 
        int IConnectionOrientedTransportFactorySettings.MaxBufferSize
        {
            get { return MaxBufferSize; }
        }
 
        TransferMode IConnectionOrientedTransportFactorySettings.TransferMode
        {
            get { return TransferMode; }
        }
 
        StreamUpgradeProvider IConnectionOrientedTransportFactorySettings.Upgrade
        {
            get { return Upgrade; }
        }
 
        public override T GetProperty<T>()
        {
            if (typeof(T) == typeof(ISecurityCapabilities))
            {
                return (T)(object)_securityCapabilities;
            }
 
            T result = base.GetProperty<T>();
            if (result == null && _upgrade != null)
            {
                result = _upgrade.GetProperty<T>();
            }
 
            return result;
        }
 
        public override int GetMaxBufferSize()
        {
            return this.MaxBufferSize;
        }
 
        internal abstract IConnectionInitiator GetConnectionInitiator();
 
        internal abstract ConnectionPool GetConnectionPool();
 
        internal abstract void ReleaseConnectionPool(ConnectionPool pool, TimeSpan timeout);
 
        protected override TChannel OnCreateChannel(EndpointAddress address, Uri via)
        {
            base.ValidateScheme(via);
 
 
            if (TransferMode == TransferMode.Buffered)
            {
                // typeof(TChannel) == typeof(IDuplexSessionChannel)
                return (TChannel)(object)new ClientFramingDuplexSessionChannel(this, this, address, via,
                    ConnectionInitiator, _connectionPool, _exposeConnectionProperty, _flowIdentity);
            }
 
            throw ExceptionHelper.PlatformNotSupported("StreamedFramingRequestChannel not yet implemented");
        }
 
        private bool GetUpgradeAndConnectionPool(out StreamUpgradeProvider upgradeCopy, out ConnectionPool poolCopy)
        {
            if (_upgrade != null || _connectionPool != null)
            {
                lock (ThisLock)
                {
                    if (_upgrade != null || _connectionPool != null)
                    {
                        upgradeCopy = _upgrade;
                        poolCopy = _connectionPool;
                        _upgrade = null;
                        _connectionPool = null;
                        return true;
                    }
                }
            }
 
            upgradeCopy = null;
            poolCopy = null;
            return false;
        }
 
        protected override void OnAbort()
        {
            StreamUpgradeProvider localUpgrade;
            ConnectionPool localConnectionPool;
            if (GetUpgradeAndConnectionPool(out localUpgrade, out localConnectionPool))
            {
                if (localConnectionPool != null)
                {
                    ReleaseConnectionPool(localConnectionPool, TimeSpan.Zero);
                }
 
                if (localUpgrade != null)
                {
                    localUpgrade.Abort();
                }
            }
        }
 
        protected override void OnClose(TimeSpan timeout)
        {
            StreamUpgradeProvider localUpgrade;
            ConnectionPool localConnectionPool;
 
            if (GetUpgradeAndConnectionPool(out localUpgrade, out localConnectionPool))
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 
                if (localConnectionPool != null)
                {
                    ReleaseConnectionPool(localConnectionPool, timeoutHelper.RemainingTime());
                }
 
                if (localUpgrade != null)
                {
                    localUpgrade.Close(timeoutHelper.RemainingTime());
                }
            }
        }
 
        protected override void OnOpening()
        {
            base.OnOpening();
            _connectionPool = GetConnectionPool(); // returns an already opened pool
            Contract.Assert(_connectionPool != null, "ConnectionPool should always be found");
        }
 
        protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            throw ExceptionHelper.PlatformNotSupported("ConnectionOrientedTransportChannelFactory async open path");
        }
 
        protected override void OnEndOpen(IAsyncResult result)
        {
            throw ExceptionHelper.PlatformNotSupported("ConnectionOrientedTransportChannelFactory async open path");
        }
 
        protected override void OnOpen(TimeSpan timeout)
        {
            StreamUpgradeProvider localUpgrade = this.Upgrade;
            if (localUpgrade != null)
            {
                localUpgrade.Open(timeout);
            }
        }
 
        protected internal override async Task OnOpenAsync(TimeSpan timeout)
        {
            StreamUpgradeProvider localUpgrade = this.Upgrade;
            if (localUpgrade != null)
            {
                await ((IAsyncCommunicationObject)localUpgrade).OpenAsync(timeout);
            }
        }
 
        protected internal override async Task OnCloseAsync(TimeSpan timeout)
        {
            StreamUpgradeProvider localUpgrade;
            ConnectionPool localConnectionPool;
 
            if (this.GetUpgradeAndConnectionPool(out localUpgrade, out localConnectionPool))
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 
                if (localConnectionPool != null)
                {
                    this.ReleaseConnectionPool(localConnectionPool, timeoutHelper.RemainingTime());
                }
 
                if (localUpgrade != null)
                {
                    await ((IAsyncCommunicationObject)localUpgrade).CloseAsync(timeoutHelper.RemainingTime());
                }
            }
        }
 
        protected virtual bool SupportsUpgrade(StreamUpgradeBindingElement upgradeBindingElement)
        {
            return true;
        }
    }
}