File: System\ServiceModel\Activation\HostedNamedPipeTransportManager.cs
Project: ndp\cdf\src\WCF\System.ServiceModel.Activation\System.ServiceModel.Activation.csproj (System.ServiceModel.Activation)
//----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//----------------------------------------------------------------------------
 
namespace System.ServiceModel.Activation
{
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Diagnostics;
 
    class HostedNamedPipeTransportManager : NamedPipeTransportManager
    {
        // Double-checked locking pattern requires volatile for read/write synchronization
        volatile bool settingsApplied;
        Action<Uri> onViaCallback;
        SharedConnectionListener listener;
        ConnectionDemuxer connectionDemuxer;
        int queueId;
        Guid token;
        Func<Uri, int> onDuplicatedViaCallback;
 
        // Double-checked locking pattern requires volatile for read/write synchronization
        volatile bool demuxerCreated;
 
        public HostedNamedPipeTransportManager(BaseUriWithWildcard baseAddress)
            : base(baseAddress.BaseAddress)
        {
            this.HostNameComparisonMode = baseAddress.HostNameComparisonMode;
            this.onViaCallback = new Action<Uri>(OnVia);
            this.onDuplicatedViaCallback = new Func<Uri, int>(OnDuplicatedVia);
        }
 
        protected override bool IsCompatible(NamedPipeChannelListener channelListener)
        {
            if (channelListener.HostedVirtualPath == null)
            {
                return false;
            }
 
            return base.IsCompatible(channelListener);
        }
 
        internal void Start(int queueId, Guid token, Action messageReceivedCallback)
        {
            SetMessageReceivedCallback(messageReceivedCallback);
            OnOpenInternal(queueId, token);
        }
 
        internal override void OnOpen()
        {
            // This is intentionally empty.
        }
 
        internal override void OnAbort()
        {
        }
 
        internal void Stop(TimeSpan timeout)
        {
            Cleanup(false, timeout);
        }
 
        void Cleanup(bool aborting, TimeSpan timeout)
        {
            lock (ThisLock)
            {
                if (listener != null)
                {
                    if (!aborting)
                    {
                        listener.Stop(timeout);
                    }
                    else
                    {
                        listener.Abort();
                    }
 
                    // The listener will be closed by the demuxer.
                    listener = null;
                }
 
                if (connectionDemuxer != null)
                {
                    connectionDemuxer.Dispose();
                }
 
                demuxerCreated = false;
                settingsApplied = false;
            }
        }
 
        void CreateConnectionDemuxer()
        {
            IConnectionListener connectionListener = new BufferedConnectionListener(listener, MaxOutputDelay, ConnectionBufferSize);
            if (DiagnosticUtility.ShouldUseActivity)
            {
                connectionListener = new TracingConnectionListener(connectionListener, this.ListenUri);
            }
 
            connectionDemuxer = new ConnectionDemuxer(connectionListener,
                MaxPendingAccepts, MaxPendingConnections, ChannelInitializationTimeout,
                IdleTimeout, MaxPooledConnections,
                OnGetTransportFactorySettings,
                OnGetSingletonMessageHandler,
                OnHandleServerSessionPreamble,
                OnDemuxerError);
 
            connectionDemuxer.StartDemuxing(onViaCallback);
        }
 
        void OnOpenInternal(int queueId, Guid token)
        {
            lock (ThisLock)
            {
                this.queueId = queueId;
                this.token = token;
 
                BaseUriWithWildcard path = new BaseUriWithWildcard(this.ListenUri, this.HostNameComparisonMode);
 
                listener = new SharedConnectionListener(path, queueId, token, this.onDuplicatedViaCallback);
            }
        }
 
        internal override void OnClose(TimeSpan timeout)
        {
        }
 
        void OnVia(Uri address)
        {
            Debug.Print("HostedNamedPipeTransportManager.OnVia() address: " + address + " calling EnsureServiceAvailable()");
            ServiceHostingEnvironment.EnsureServiceAvailable(address.LocalPath);
        }
 
        protected override void OnSelecting(NamedPipeChannelListener channelListener)
        {
            if (settingsApplied)
            {
                return;
            }
 
            lock (ThisLock)
            {
                if (settingsApplied)
                {
                    // Use the setting for the first one.
                    return;
                }
 
                this.ApplyListenerSettings(channelListener);
                settingsApplied = true;
            }
        }
 
        // This method is called only for the first via of the current proxy.
        int OnDuplicatedVia(Uri via)
        {
            OnVia(via);
            
            if (!demuxerCreated)
            {
                lock (ThisLock)
                {
                    if (listener == null)
                    {
                        // The listener has been stopped.
                        throw FxTrace.Exception.AsError(new CommunicationObjectAbortedException(SR.PipeListenerProxyStopped));
                    }
 
                    if (!demuxerCreated)
                    {
                        CreateConnectionDemuxer();
                        demuxerCreated = true;
                    }
                }
            }
 
            return this.ConnectionBufferSize;
        }
    }
}