File: System\ServiceModel\Channels\PeerTransportBindingElement.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.ObjectModel;
    using System.Net;
    using System.Net.Security;
    using System.ServiceModel.Description;
    using System.ServiceModel;
    using System.ServiceModel.PeerResolvers;
    using System.Xml;
 
 
 
    static class PeerTransportPolicyConstants
    {
        public const string PeerTransportSecurityMode = "PeerTransportSecurityMode";
        public const string PeerTransportCredentialType = "PeerTransportCredentialType";
        public const string PeerTransportCredentialTypePassword = "PeerTransportCredentialTypePassword";
        public const string PeerTransportCredentialTypeCertificate = "PeerTransportCredentialTypeCertificate";
        public const string PeerTransportSecurityModeNone = "PeerTransportSecurityModeNone";
        public const string PeerTransportSecurityModeTransport = "PeerTransportSecurityModeTransport";
        public const string PeerTransportSecurityModeMessage = "PeerTransportSecurityModeMessage";
        public const string PeerTransportSecurityModeTransportWithMessageCredential = "PeerTransportSecurityModeTransportWithMessageCredential";
        public const string PeerTransportPrefix = "pc";
    }
 
    [ObsoleteAttribute ("PeerChannel feature is obsolete and will be removed in the future.", false)]
    public sealed class PeerTransportBindingElement
        : TransportBindingElement, IWsdlExportExtension, ITransportPolicyImport, IPolicyExportExtension
    {
        IPAddress listenIPAddress;
        int port;
        PeerResolver resolver;
        bool resolverSet;
        PeerSecuritySettings peerSecurity;
 
        public PeerTransportBindingElement()
            : base()
        {
            this.listenIPAddress = PeerTransportDefaults.ListenIPAddress;
            this.port = PeerTransportDefaults.Port;
            if (PeerTransportDefaults.ResolverAvailable)
            {
                this.resolver = PeerTransportDefaults.CreateResolver();
            }
            peerSecurity = new PeerSecuritySettings();
        }
 
        PeerTransportBindingElement(PeerTransportBindingElement elementToBeCloned)
            : base(elementToBeCloned)
        {
            this.listenIPAddress = elementToBeCloned.listenIPAddress;
            this.port = elementToBeCloned.port;
            this.resolverSet = elementToBeCloned.resolverSet;
            this.resolver = elementToBeCloned.resolver;
            peerSecurity = new PeerSecuritySettings(elementToBeCloned.Security);
        }
 
        public IPAddress ListenIPAddress
        {
            get
            {
                return this.listenIPAddress;
            }
 
            set
            {
                PeerValidateHelper.ValidateListenIPAddress(value);
                this.listenIPAddress = value;
            }
        }
 
        public override long MaxReceivedMessageSize
        {
            get
            {
                return base.MaxReceivedMessageSize;
            }
 
            set
            {
                PeerValidateHelper.ValidateMaxMessageSize(value);
                base.MaxReceivedMessageSize = value;
            }
        }
 
        public int Port
        {
            get
            {
                return this.port;
            }
 
            set
            {
                PeerValidateHelper.ValidatePort(value);
                this.port = value;
            }
        }
 
        internal PeerResolver Resolver
        {
            get
            {
                return this.resolver;
            }
 
            set
            {
                if (value == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
                }
 
                if (value.GetType() == PeerTransportDefaults.ResolverType)
                {
                    if (!PeerTransportDefaults.ResolverInstalled)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("value", SR.GetString(SR.PeerPnrpNotInstalled));
                    }
                    else if (!PeerTransportDefaults.ResolverAvailable)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("value", SR.GetString(SR.PeerPnrpNotAvailable));
                    }
                }
 
                this.resolver = value;
                this.resolverSet = true;
            }
        }
 
        public override string Scheme { get { return PeerStrings.Scheme; } }
 
        public PeerSecuritySettings Security
        {
            get { return peerSecurity; }
        }
 
 
        void ITransportPolicyImport.ImportPolicy(MetadataImporter importer, PolicyConversionContext context)
        {
            if (importer == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("importer");
 
            if (context == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
 
            peerSecurity.OnImportPolicy(importer, context);
        }
 
        void IPolicyExportExtension.ExportPolicy(MetadataExporter exporter, PolicyConversionContext context)
        {
            if (exporter == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("exporter");
            }
 
            if (context == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
            }
 
            peerSecurity.OnExportPolicy(exporter, context);
 
            bool createdNew;
            MessageEncodingBindingElement encodingBindingElement = FindMessageEncodingBindingElement(context.BindingElements, out createdNew);
            if (createdNew && encodingBindingElement is IPolicyExportExtension)
            {
                ((IPolicyExportExtension)encodingBindingElement).ExportPolicy(exporter, context);
            }
 
            WsdlExporter.WSAddressingHelper.AddWSAddressingAssertion(exporter, context, encodingBindingElement.MessageVersion.Addressing);
        }
 
        void IWsdlExportExtension.ExportContract(WsdlExporter exporter, WsdlContractConversionContext context) { }
 
        void IWsdlExportExtension.ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext endpointContext)
        {
            bool createdNew;
            MessageEncodingBindingElement encodingBindingElement = FindMessageEncodingBindingElement(endpointContext, out createdNew);
            TransportBindingElement.ExportWsdlEndpoint(
                exporter, endpointContext, TransportPolicyConstants.PeerTransportUri,
                encodingBindingElement.MessageVersion.Addressing);
        }
 
        internal void CreateDefaultResolver(PeerResolverSettings settings)
        {
            if (PeerTransportDefaults.ResolverAvailable)
            {
                this.resolver = new PnrpPeerResolver(settings.ReferralPolicy);
            }
        }
 
        MessageEncodingBindingElement FindMessageEncodingBindingElement(BindingElementCollection bindingElements, out bool createdNew)
        {
            createdNew = false;
            MessageEncodingBindingElement encodingBindingElement = bindingElements.Find<MessageEncodingBindingElement>();
            if (encodingBindingElement == null)
            {
                createdNew = true;
                encodingBindingElement = new BinaryMessageEncodingBindingElement();
            }
            return encodingBindingElement;
        }
 
        MessageEncodingBindingElement FindMessageEncodingBindingElement(WsdlEndpointConversionContext endpointContext, out bool createdNew)
        {
            BindingElementCollection bindingElements = endpointContext.Endpoint.Binding.CreateBindingElements();
            return FindMessageEncodingBindingElement(bindingElements, out createdNew);
        }
 
        public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
        {
            if (context == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("context"));
            }
 
            if (!this.CanBuildChannelFactory<TChannel>(context))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("TChannel", SR.GetString(SR.ChannelTypeNotSupported, typeof(TChannel)));
            }
 
            if (this.ManualAddressing)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ManualAddressingNotSupported)));
            }
 
            PeerResolver peerResolver = GetResolver(context);
            return new PeerChannelFactory<TChannel>(this, context, peerResolver);
        }
 
        public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
        {
            if (context == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
            }
 
            PeerChannelListenerBase peerListener = null;
            PeerResolver peerResolver = GetResolver(context);
            if (typeof(TChannel) == typeof(IInputChannel))
            {
                peerListener = new PeerInputChannelListener(this, context, peerResolver);
            }
            else if (typeof(TChannel) == typeof(IDuplexChannel))
            {
                peerListener = new PeerDuplexChannelListener(this, context, peerResolver);
            }
            else
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("TChannel", SR.GetString(SR.ChannelTypeNotSupported, typeof(TChannel)));
            }
 
            return (IChannelListener<TChannel>)peerListener;
        }
 
        public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
        {
            return (typeof(TChannel) == typeof(IOutputChannel)
                || typeof(TChannel) == typeof(IDuplexChannel));
        }
 
        public override bool CanBuildChannelListener<TChannel>(BindingContext context)
        {
            return (typeof(TChannel) == typeof(IInputChannel)
                || typeof(TChannel) == typeof(IDuplexChannel));
        }
 
        public override BindingElement Clone()
        {
            return new PeerTransportBindingElement(this);
        }
 
        public override T GetProperty<T>(BindingContext context)
        {
            if (context == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
            }
            if (typeof(T) == typeof(IBindingMulticastCapabilities))
            {
                return (T)(object)new BindingMulticastCapabilities();
            }
            else if (typeof(T) == typeof(ISecurityCapabilities))
            {
                return (T)(object)new SecurityCapabilities(Security.SupportsAuthentication, Security.SupportsAuthentication,
                    false, Security.SupportedProtectionLevel, Security.SupportedProtectionLevel);
            }
            else if (typeof(T) == typeof(IBindingDeliveryCapabilities))
            {
                return (T)(object)new BindingDeliveryCapabilitiesHelper();
            }
 
            return base.GetProperty<T>(context);
        }
 
        // Return the resolver member (if set) or create one from the resolver binding element in the context
        PeerResolver GetResolver(BindingContext context)
        {
            if (this.resolverSet)
            {
                return this.resolver;
            }
 
            Collection<PeerCustomResolverBindingElement> customResolverElements
                = context.BindingParameters.FindAll<PeerCustomResolverBindingElement>();
 
            if (customResolverElements.Count > 1)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MultiplePeerCustomResolverBindingElementsInParameters)));
            }
            else if (customResolverElements.Count == 1)
            {
                context.BindingParameters.Remove<PeerCustomResolverBindingElement>();
                return customResolverElements[0].CreatePeerResolver();
            }
 
 
            // If resolver binding element is included in the context, use it to create the resolver. elementToBeClonedwise,
            // if default resolver is available, use it.
            Collection<PeerResolverBindingElement> resolverBindingElements
                = context.BindingParameters.FindAll<PeerResolverBindingElement>();
 
            if (resolverBindingElements.Count > 1)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MultiplePeerResolverBindingElementsinParameters)));
            }
            else if (resolverBindingElements.Count == 0)
            {
                if (this.resolver != null)  // default resolver available?
                {
                    return this.resolver;
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new InvalidOperationException(SR.GetString(SR.PeerResolverBindingElementRequired, context.Binding.Name)));
                }
            }
            else if (resolverBindingElements[0].GetType() == PeerTransportDefaults.ResolverBindingElementType)
            {
                if (!PeerTransportDefaults.ResolverInstalled)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new InvalidOperationException(SR.GetString(SR.PeerPnrpNotInstalled)));
                }
                else if (!PeerTransportDefaults.ResolverAvailable)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new InvalidOperationException(SR.GetString(SR.PeerPnrpNotAvailable)));
                }
            }
 
            context.BindingParameters.Remove<PeerResolverBindingElement>();
            return resolverBindingElements[0].CreatePeerResolver();
        }
 
        class BindingMulticastCapabilities : IBindingMulticastCapabilities
        {
            public bool IsMulticast { get { return true; } }
        }
 
        class BindingDeliveryCapabilitiesHelper : IBindingDeliveryCapabilities
        {
            internal BindingDeliveryCapabilitiesHelper()
            {
            }
            bool IBindingDeliveryCapabilities.AssuresOrderedDelivery
            {
                get { return false; }
            }
 
            bool IBindingDeliveryCapabilities.QueuedDelivery
            {
                get { return false; }
            }
        }
 
 
    }
}