File: System\ServiceModel\Channels\PeerMessageDispatcher.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;
    using System.Runtime;
    using System.ServiceModel;
    using System.ServiceModel.Security;
 
    class PeerMessageDispatcher<ChannelInterfaceType, TChannel> : CommunicationObject
        where ChannelInterfaceType : class, IChannel
        where TChannel : InputQueueChannel<Message>
    {
        public class PeerMessageQueueAdapter
        {
            SingletonChannelAcceptor<ChannelInterfaceType, TChannel, Message> singletonChannelAcceptor;
            InputQueueChannel<Message> inputQueueChannel;
 
            public PeerMessageQueueAdapter(SingletonChannelAcceptor<ChannelInterfaceType, TChannel, Message> singletonChannelAcceptor)
            {
                this.singletonChannelAcceptor = singletonChannelAcceptor;
            }
 
            public PeerMessageQueueAdapter(InputQueueChannel<Message> inputQueueChannel)
            {
                this.inputQueueChannel = inputQueueChannel;
            }
 
            public void EnqueueAndDispatch(Message message, Action callback)
            {
                if (singletonChannelAcceptor != null)
                {
                    singletonChannelAcceptor.Enqueue(message, callback);
                }
                else if (inputQueueChannel != null)
                {
                    inputQueueChannel.EnqueueAndDispatch(message, callback);
                }
            }
        }
 
        Uri via;
        EndpointAddress to;
        SecurityProtocol securityProtocol;
        PeerNodeImplementation peerNode;
        PeerMessageQueueAdapter queueHandler;
        ChannelManagerBase channelManager;
        PeerQuotaHelper quotaHelper = new PeerQuotaHelper(Int32.MaxValue);
        bool registered;
 
        public PeerMessageDispatcher(PeerMessageQueueAdapter queueHandler, PeerNodeImplementation peerNode, ChannelManagerBase channelManager, EndpointAddress to, Uri via)
        {
            PeerNodeImplementation.ValidateVia(via);
 
            this.queueHandler = queueHandler;
            this.peerNode = peerNode;
            this.to = to;
            this.via = via;
            this.channelManager = channelManager;
            EndpointAddress filterTo = null;
 
            this.securityProtocol = ((IPeerFactory)channelManager).SecurityManager.CreateSecurityProtocol<ChannelInterfaceType>(to, ServiceDefaults.SendTimeout);
 
            if (typeof(IDuplexChannel).IsAssignableFrom(typeof(ChannelInterfaceType)))
                filterTo = to;
 
            //Register this handler
            PeerMessageFilter[] filters = new PeerMessageFilter[] { new PeerMessageFilter(via, filterTo) };
            peerNode.RegisterMessageFilter(this, this.via, filters, (ITransportFactorySettings)this.channelManager,
                                           new PeerNodeImplementation.MessageAvailableCallback(OnMessageAvailable), securityProtocol);
            registered = true;
        }
 
        protected override TimeSpan DefaultCloseTimeout
        {
            get { return channelManager.InternalCloseTimeout; }
        }
 
        protected override TimeSpan DefaultOpenTimeout
        {
            get { return channelManager.InternalOpenTimeout; }
        }
 
        public SecurityProtocol SecurityProtocol
        {
            get { return securityProtocol; }
        }
 
        protected override void OnAbort()
        {
        }
 
        protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
        {
            this.OnClose(timeout);
            return new CompletedAsyncResult(callback, state);
        }
 
        protected override void OnEndClose(IAsyncResult result)
        {
            CompletedAsyncResult.End(result);
        }
 
        protected override void OnClose(TimeSpan timeout)
        {
            Unregister(true);
        }
 
        internal void Unregister()
        {
            Unregister(false);
        }
 
        internal void Unregister(bool release)
        {
            PeerNodeImplementation node = this.peerNode;
            if (node != null)
            {
                if (registered)
                {
                    node.UnregisterMessageFilter(this, via);
                    registered = false;
                }
                if (release)
                    node.Release();
            }
        }
 
        protected override void OnOpen(TimeSpan timeout)
        {
        }
 
        protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return new CompletedAsyncResult(callback, state);
        }
 
        protected override void OnEndOpen(IAsyncResult result)
        {
            CompletedAsyncResult.End(result);
        }
 
        public void OnMessageAvailable(Message message)
        {
            quotaHelper.ReadyToEnqueueItem();
            queueHandler.EnqueueAndDispatch(message, quotaHelper.ItemDequeued);
        }
    }
    class PeerMessageFilter
    {
        Uri via;
        Uri actingAs;
 
        public PeerMessageFilter(Uri via) : this(via, null) { }
        public PeerMessageFilter(Uri via, EndpointAddress to)
        {
            Fx.Assert(via != null, "PeerMessageFilter via can not be set to null");
            this.via = via;
            if (to != null)
                this.actingAs = to.Uri;
        }
 
        public bool Match(Uri peerVia, Uri toCond)
        {
            bool result = false;
            if (peerVia == null)
            {
                result = false;
            }
            else if (Uri.Compare(this.via, peerVia,
               (UriComponents.Scheme | UriComponents.UserInfo | UriComponents.Host | UriComponents.Port | UriComponents.Path),
               UriFormat.SafeUnescaped, StringComparison.OrdinalIgnoreCase) != 0)
            {
                result = false;
            }
            else if (this.actingAs != null)
            {
                result = Uri.Compare(this.actingAs, toCond,
               (UriComponents.Scheme | UriComponents.UserInfo | UriComponents.Host | UriComponents.Port | UriComponents.Path),
               UriFormat.SafeUnescaped, StringComparison.OrdinalIgnoreCase) == 0;
            }
            else
                result = true;
 
            return result;
        }
 
    }
}