File: System\ServiceModel\Channels\UdpReplyChannel.cs
Project: ndp\cdf\src\NetFx40\System.ServiceModel.Channels\System.ServiceModel.Channels.csproj (System.ServiceModel.Channels)
// <copyright>
// Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
 
namespace System.ServiceModel.Channels
{
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Net;
    using System.Runtime;
    using System.ServiceModel;
 
    internal sealed class UdpReplyChannel : UdpChannelBase<RequestContext>, IReplyChannel
    {
        public UdpReplyChannel(UdpReplyChannelListener listener, UdpSocket[] sockets, EndpointAddress localAddress, Uri via, bool isMulticast)
            : base(
            listener, 
            listener.MessageEncoderFactory.Encoder, 
            listener.BufferManager,
            sockets, 
            listener.UdpTransportBindingElement.RetransmissionSettings,
            listener.UdpTransportBindingElement.MaxPendingMessagesTotalSize,
            localAddress,
            via,
            isMulticast,
            (int)listener.UdpTransportBindingElement.MaxReceivedMessageSize)
        {
            UdpOutputChannel udpOutputChannel = new ServerUdpOutputChannel(
                listener,
                listener.MessageEncoderFactory.Encoder,
                listener.BufferManager,
                sockets,
                listener.UdpTransportBindingElement.RetransmissionSettings,
                via,
                isMulticast);
 
            this.SetOutputChannel(udpOutputChannel);
        }
 
        protected override bool IgnoreSerializationException
        {
            get
            {
                return true;
            }
        }
 
        [SuppressMessage("Microsoft.StyleCop.CSharp.ReadabilityRules", "SA1100:DoNotPrefixCallsWithBaseUnlessLocalImplementationExists", Justification = "StyleCop 4.5 does not validate this rule properly.")]
        public override T GetProperty<T>()
        {
            if (typeof(T) == typeof(IReplyChannel))
            {
                return (T)(object)this;
            }
 
            return base.GetProperty<T>();
        }
 
        public RequestContext ReceiveRequest()
        {
            return this.ReceiveRequest(this.DefaultReceiveTimeout);
        }
 
        public RequestContext ReceiveRequest(TimeSpan timeout)
        {
            if (timeout < TimeSpan.Zero)
            {
                throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("timeout", timeout, SR.TimeoutOutOfRange0));
            }
 
            this.ThrowPending();
            return UdpReplyChannel.HelpReceiveRequest(this, timeout);
        }
 
        public IAsyncResult BeginReceiveRequest(AsyncCallback callback, object state)
        {
            return this.BeginReceiveRequest(this.DefaultReceiveTimeout, callback, state);
        }
 
        public IAsyncResult BeginReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)
        {
            if (timeout < TimeSpan.Zero)
            {
                throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("timeout", timeout, SR.TimeoutOutOfRange0));
            }
 
            this.ThrowPending();
            return UdpReplyChannel.HelpBeginReceiveRequest(this, timeout, callback, state);
        }
 
        public RequestContext EndReceiveRequest(IAsyncResult result)
        {
            return UdpReplyChannel.HelpEndReceiveRequest(result);
        }
 
        public bool TryReceiveRequest(TimeSpan timeout, out RequestContext context)
        {
            if (timeout < TimeSpan.Zero)
            {
                throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("timeout", timeout, SR.TimeoutOutOfRange0));
            }
 
            this.ThrowPending();
            return this.Dequeue(timeout, out context);
        }
 
        public IAsyncResult BeginTryReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)
        {
            if (timeout < TimeSpan.Zero)
            {
                throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("timeout", timeout, SR.TimeoutOutOfRange0));
            }
 
            this.ThrowPending();
            return this.BeginDequeue(timeout, callback, state);
        }
 
        public bool EndTryReceiveRequest(IAsyncResult result, out RequestContext context)
        {
            return this.EndDequeue(result, out context);
        }
 
        public bool WaitForRequest(TimeSpan timeout)
        {
            if (timeout < TimeSpan.Zero)
            {
                throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("timeout", timeout, SR.TimeoutOutOfRange0));
            }
 
            this.ThrowPending();
            return this.WaitForItem(timeout);
        }
 
        public IAsyncResult BeginWaitForRequest(TimeSpan timeout, AsyncCallback callback, object state)
        {
            if (timeout < TimeSpan.Zero)
            {
                throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("timeout", timeout, SR.TimeoutOutOfRange0));
            }
 
            this.ThrowPending();
            return this.BeginWaitForItem(timeout, callback, state);
        }
 
        public bool EndWaitForRequest(IAsyncResult result)
        {
            return this.EndWaitForItem(result);
        }
 
        internal override void FinishEnqueueMessage(Message message, Action dequeuedCallback, bool canDispatchOnThisThread)
        {
            UdpRequestContext udpRequestContext = new UdpRequestContext(this.UdpOutputChannel, message);
            this.EnqueueAndDispatch(udpRequestContext, dequeuedCallback, canDispatchOnThisThread);
        }
 
        private static RequestContext HelpReceiveRequest(IReplyChannel channel, TimeSpan timeout)
        {
            RequestContext requestContext;
            if (channel.TryReceiveRequest(timeout, out requestContext))
            {
                return requestContext;
            }
            else
            {
                throw FxTrace.Exception.AsError(UdpReplyChannel.CreateReceiveRequestTimedOutException(channel, timeout));
            }
        }
 
        private static IAsyncResult HelpBeginReceiveRequest(IReplyChannel channel, TimeSpan timeout, AsyncCallback callback, object state)
        {
            return new HelpReceiveRequestAsyncResult(channel, timeout, callback, state);
        }
 
        private static RequestContext HelpEndReceiveRequest(IAsyncResult result)
        {
            return HelpReceiveRequestAsyncResult.End(result);
        }
 
        private static Exception CreateReceiveRequestTimedOutException(IReplyChannel channel, TimeSpan timeout)
        {
            if (channel.LocalAddress != null)
            {
                return new TimeoutException(SR.ReceiveRequestTimedOut(channel.LocalAddress.Uri.AbsoluteUri, timeout));
            }
            else
            {
                return new TimeoutException(SR.ReceiveRequestTimedOutNoLocalAddress(timeout));
            }
        }
 
        private class HelpReceiveRequestAsyncResult : AsyncResult
        {
            private static AsyncCallback onReceiveRequest = Fx.ThunkCallback(new AsyncCallback(OnReceiveRequest));
            private IReplyChannel channel;
            private TimeSpan timeout;
            private RequestContext requestContext;
 
            public HelpReceiveRequestAsyncResult(IReplyChannel channel, TimeSpan timeout, AsyncCallback callback, object state)
                : base(callback, state)
            {
                this.channel = channel;
                this.timeout = timeout;
                IAsyncResult result = channel.BeginTryReceiveRequest(timeout, onReceiveRequest, this);
 
                if (!result.CompletedSynchronously)
                {
                    return;
                }
 
                this.HandleReceiveRequestComplete(result);
                this.Complete(true);
            }
 
            public static RequestContext End(IAsyncResult result)
            {
                HelpReceiveRequestAsyncResult thisPtr = AsyncResult.End<HelpReceiveRequestAsyncResult>(result);
                return thisPtr.requestContext;
            }
 
            private static void OnReceiveRequest(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                {
                    return;
                }
 
                HelpReceiveRequestAsyncResult thisPtr = (HelpReceiveRequestAsyncResult)result.AsyncState;
                Exception completionException = null;
                try
                {
                    thisPtr.HandleReceiveRequestComplete(result);
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
 
                    completionException = e;
                }
 
                thisPtr.Complete(false, completionException);
            }
 
            private void HandleReceiveRequestComplete(IAsyncResult result)
            {
                if (!this.channel.EndTryReceiveRequest(result, out this.requestContext))
                {
                    throw FxTrace.Exception.AsError(UdpReplyChannel.CreateReceiveRequestTimedOutException(this.channel, this.timeout));
                }
            }
        }
    }
}