TcpChannelListener.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / TcpChannelListener.cs / 1 / TcpChannelListener.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------

namespace System.ServiceModel.Channels 
{
    using System.Collections.Generic; 
    using System.ServiceModel; 
    using System.Diagnostics;
    using System.IO; 
    using System.Net;
    using System.Net.Sockets;
    using System.Runtime.Serialization;
    using System.ServiceModel.Diagnostics; 
    using System.Text;
    using System.Threading; 
    using System.ServiceModel.Description; 

    static class TcpUri 
    {
        public const int DefaultPort = 808;
    }
 
    abstract class TcpChannelListener
        : TcpChannelListener, IChannelListener 
        where TChannel : class, IChannel 
        where TChannelAcceptor : ChannelAcceptor
    { 
        protected TcpChannelListener(TcpTransportBindingElement bindingElement, BindingContext context)
            : base(bindingElement, context)
        {
        } 

        protected abstract TChannelAcceptor ChannelAcceptor { get; } 
 
        protected override void OnOpen(TimeSpan timeout)
        { 
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            base.OnOpen(timeoutHelper.RemainingTime());
            ChannelAcceptor.Open(timeoutHelper.RemainingTime());
        } 

        protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) 
        { 
            return new ChainedOpenAsyncResult(timeout, callback, state, base.OnBeginOpen, base.OnEndOpen, ChannelAcceptor);
        } 

        protected override void OnEndOpen(IAsyncResult result)
        {
            ChainedOpenAsyncResult.End(result); 
        }
 
        protected override void OnClose(TimeSpan timeout) 
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 
            ChannelAcceptor.Close(timeoutHelper.RemainingTime());
            base.OnClose(timeoutHelper.RemainingTime());
        }
 
        protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
        { 
            return new ChainedCloseAsyncResult(timeout, callback, state, base.OnBeginClose, base.OnEndClose, ChannelAcceptor); 
        }
 
        protected override void OnEndClose(IAsyncResult result)
        {
            ChainedCloseAsyncResult.End(result);
        } 

        protected override void OnAbort() 
        { 
            this.ChannelAcceptor.Abort();
            base.OnAbort(); 
        }

        public TChannel AcceptChannel()
        { 
            return this.AcceptChannel(this.DefaultReceiveTimeout);
        } 
 
        public IAsyncResult BeginAcceptChannel(AsyncCallback callback, object state)
        { 
            return this.BeginAcceptChannel(this.DefaultReceiveTimeout, callback, state);
        }

        public TChannel AcceptChannel(TimeSpan timeout) 
        {
            base.ThrowIfNotOpened(); 
            return ChannelAcceptor.AcceptChannel(timeout); 
        }
 
        public IAsyncResult BeginAcceptChannel(TimeSpan timeout, AsyncCallback callback, object state)
        {
            base.ThrowIfNotOpened();
            return ChannelAcceptor.BeginAcceptChannel(timeout, callback, state); 
        }
 
        public TChannel EndAcceptChannel(IAsyncResult result) 
        {
            base.ThrowPending(); 
            return ChannelAcceptor.EndAcceptChannel(result);
        }

        protected override bool OnWaitForChannel(TimeSpan timeout) 
        {
            return ChannelAcceptor.WaitForChannel(timeout); 
        } 

        protected override IAsyncResult OnBeginWaitForChannel(TimeSpan timeout, AsyncCallback callback, object state) 
        {
            return ChannelAcceptor.BeginWaitForChannel(timeout, callback, state);
        }
 
        protected override bool OnEndWaitForChannel(IAsyncResult result)
        { 
            return ChannelAcceptor.EndWaitForChannel(result); 
        }
    } 

    class TcpReplyChannelListener
        : TcpChannelListener
        , ISingletonChannelListener 
    {
        ReplyChannelAcceptor replyAcceptor; 
 
        public TcpReplyChannelListener(TcpTransportBindingElement bindingElement, BindingContext context)
            : base(bindingElement, context) 
        {
            this.replyAcceptor = new ConnectionOrientedTransportReplyChannelAcceptor(this);
        }
 
        protected override ReplyChannelAcceptor ChannelAcceptor
        { 
            get { return this.replyAcceptor; } 
        }
 
        TimeSpan ISingletonChannelListener.ReceiveTimeout
        {
            get { return this.InternalReceiveTimeout; }
        } 

        void ISingletonChannelListener.ReceiveRequest(RequestContext requestContext, ItemDequeuedCallback callback, bool canDispatchOnThisThread) 
        { 
            if (DiagnosticUtility.ShouldTraceVerbose)
            { 
                TraceUtility.TraceEvent(TraceEventType.Verbose, MessageReceivedTraceCode, requestContext.RequestMessage);
            }
            replyAcceptor.Enqueue(requestContext, callback, canDispatchOnThisThread);
        } 
    }
 
    class TcpDuplexChannelListener 
        : TcpChannelListener>
        , ISessionPreambleHandler 
    {
        InputQueueChannelAcceptor duplexAcceptor;

        public TcpDuplexChannelListener(TcpTransportBindingElement bindingElement, BindingContext context) 
            : base(bindingElement, context)
        { 
            this.duplexAcceptor = new InputQueueChannelAcceptor(this); 
        }
 
        protected override InputQueueChannelAcceptor ChannelAcceptor
        {
            get { return this.duplexAcceptor; }
        } 

        void ISessionPreambleHandler.HandleServerSessionPreamble(ServerSessionPreambleConnectionReader preambleReader, 
            ConnectionDemuxer connectionDemuxer) 
        {
            IDuplexSessionChannel channel = preambleReader.CreateDuplexSessionChannel( 
                this, new EndpointAddress(this.Uri), ExposeConnectionProperty, connectionDemuxer);

            duplexAcceptor.EnqueueAndDispatch(channel, preambleReader.ConnectionDequeuedCallback);
        } 
    }
 
    abstract class TcpChannelListener : ConnectionOrientedTransportChannelListener 
    {
        bool teredoEnabled; 
        int listenBacklog;
        bool portSharingEnabled;

        // "port 0" support 
        Socket ipv4ListenSocket;
        Socket ipv6ListenSocket; 
        static Random randomPortGenerator = new Random(AppDomain.CurrentDomain.GetHashCode() | Environment.TickCount); 

        static UriPrefixTable transportManagerTable = 
            new UriPrefixTable(true);

        protected TcpChannelListener(TcpTransportBindingElement bindingElement, BindingContext context)
            : base(bindingElement, context) 
        {
            this.listenBacklog = bindingElement.ListenBacklog; 
            this.portSharingEnabled = bindingElement.PortSharingEnabled; 
            this.teredoEnabled = bindingElement.TeredoEnabled;
            SetIdleTimeout(bindingElement.ConnectionPoolSettings.IdleTimeout); 
            SetMaxPooledConnections(bindingElement.ConnectionPoolSettings.MaxOutboundConnectionsPerEndpoint);

            // for exclusive mode, we have "port 0" functionality
            if (!bindingElement.PortSharingEnabled && context.ListenUriMode == ListenUriMode.Unique) 
            {
                SetupUniquePort(context); 
            } 
        }
 
        public bool PortSharingEnabled
        {
            get
            { 
                return this.portSharingEnabled;
            } 
        } 

        public bool TeredoEnabled 
        {
            get
            {
                return this.teredoEnabled; 
            }
        } 
 
        public int ListenBacklog
        { 
            get
            {
                return this.listenBacklog;
            } 
        }
 
        internal Socket GetListenSocket(UriHostNameType ipHostNameType) 
        {
            if (ipHostNameType == UriHostNameType.IPv4) 
            {
                Socket result = this.ipv4ListenSocket;
                this.ipv4ListenSocket = null;
                return result; 
            }
            else // UriHostNameType.IPv6 
            { 
                Socket result = this.ipv6ListenSocket;
                this.ipv6ListenSocket = null; 
                return result;
            }
        }
 
        public override string Scheme
        { 
            get { return Uri.UriSchemeNetTcp; } 
        }
 
        internal override TraceCode MessageReceivedTraceCode
        {
            get { return TraceCode.TcpChannelMessageReceived; }
        } 

        internal override TraceCode MessageReceiveFailedTraceCode 
        { 
            get { return TraceCode.TcpChannelMessageReceiveFailed; }
        } 

        internal static UriPrefixTable StaticTransportManagerTable
        {
            get 
            {
                return transportManagerTable; 
            } 
        }
 
        internal override UriPrefixTable TransportManagerTable
        {
            get
            { 
                return transportManagerTable;
            } 
        } 

        internal static void FixIpv6Hostname(UriBuilder uriBuilder, Uri originalUri) 
        {
            if (originalUri.HostNameType == UriHostNameType.IPv6)
            {
                string ipv6Host = originalUri.DnsSafeHost; 
                uriBuilder.Host = string.Concat("[", ipv6Host, "]");
            } 
        } 

        internal override ITransportManagerRegistration CreateTransportManagerRegistration() 
        {
            Uri listenUri = this.BaseUri;
            if (!this.PortSharingEnabled)
            { 
                UriBuilder builder = new UriBuilder(listenUri.Scheme, listenUri.Host, listenUri.Port);
                TcpChannelListener.FixIpv6Hostname(builder, listenUri); 
                listenUri = builder.Uri; 
            }
 
            return this.CreateTransportManagerRegistration(listenUri);
        }

        internal override ITransportManagerRegistration CreateTransportManagerRegistration(Uri listenUri) 
        {
            if (this.PortSharingEnabled) 
            { 
                return new SharedTcpTransportManager(listenUri, this);
            } 
            else
            {
                return new ExclusiveTcpTransportManagerRegistration(listenUri, this);
            } 
        }
 
        Socket ListenAndBind(IPEndPoint localEndpoint) 
        {
            Socket result = new Socket(localEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 
            try
            {
                result.Bind(localEndpoint);
            } 
            catch (SocketException socketException)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                    SocketConnectionListener.ConvertListenException(socketException, localEndpoint));
            } 

            return result;
        }
 
        void SetupUniquePort(BindingContext context)
        { 
            IPAddress ipv4Address = IPAddress.Any; 
            IPAddress ipv6Address = IPAddress.IPv6Any;
 
            bool useIPv4 = Socket.SupportsIPv4;
            bool useIPv6 = Socket.OSSupportsIPv6;
            if (this.Uri.HostNameType == UriHostNameType.IPv6)
            { 
                useIPv4 = false;
                ipv6Address = IPAddress.Parse(this.Uri.DnsSafeHost); 
            } 
            else if (this.Uri.HostNameType == UriHostNameType.IPv4)
            { 
                useIPv6 = false;
                ipv4Address = IPAddress.Parse(this.Uri.DnsSafeHost);
            }
 
            if (!useIPv4 && !useIPv6)
            { 
                if (this.Uri.HostNameType == UriHostNameType.IPv6) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument( 
                        "context",
                        SR.GetString(SR.TcpV6AddressInvalid, this.Uri));
                }
                else 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument( 
                        "context", 
                        SR.GetString(SR.TcpV4AddressInvalid, this.Uri));
                } 
            }

            UriBuilder uriBuilder = new UriBuilder(context.ListenUriBaseAddress);
            int port = -1; 
            if (!useIPv6) // we just want IPv4
            { 
                this.ipv4ListenSocket = ListenAndBind(new IPEndPoint(ipv4Address, 0)); 
                port = ((IPEndPoint)this.ipv4ListenSocket.LocalEndPoint).Port;
            } 
            else if (!useIPv4) // or just IPv6
            {
                this.ipv6ListenSocket = ListenAndBind(new IPEndPoint(ipv6Address, 0));
                port = ((IPEndPoint)this.ipv6ListenSocket.LocalEndPoint).Port; 
            }
            else 
            { 
                // We need both IPv4 and IPv6 on the same port. We can't atomically bind for IPv4 and IPv6,
                // so we try 10 times, which even with a 50% failure rate will statistically succeed 99.9% of the time. 
                //
                // We look in the range of 49152-65534 for Vista default behavior parity.
                // http://www.iana.org/assignments/port-numbers
                // 
                // We also grab the 10 random numbers in a row to reduce collisions between multiple people somehow
                // colliding on the same seed. 
                const int retries = 10; 
                const int lowWatermark = 49152;
                const int highWatermark = 65535; 

                int[] portNumbers = new int[retries];
                lock (randomPortGenerator)
                { 
                    for (int i = 0; i < retries; i++)
                    { 
                        portNumbers[i] = randomPortGenerator.Next(lowWatermark, highWatermark); 
                    }
                } 


                for (int i = 0; i < retries; i++)
                { 
                    port = portNumbers[i];
                    try 
                    { 
                        this.ipv4ListenSocket = ListenAndBind(new IPEndPoint(ipv4Address, port));
                        this.ipv6ListenSocket = ListenAndBind(new IPEndPoint(ipv6Address, port)); 
                        break;
                    }
                    catch (AddressAlreadyInUseException e)
                    { 
                        if (DiagnosticUtility.ShouldTraceInformation)
                        { 
                            DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); 
                        }
                        if (this.ipv4ListenSocket != null) 
                        {
                            this.ipv4ListenSocket.Close();
                            this.ipv4ListenSocket = null;
                        } 
                        this.ipv6ListenSocket = null;
                    } 
                } 

                if (ipv4ListenSocket == null) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new AddressAlreadyInUseException(SR.GetString(SR.UniquePortNotAvailable)));
                } 
            }
 
            uriBuilder.Port = port; 
            base.SetUri(uriBuilder.Uri, context.ListenUriRelativeAddress);
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK