// // Copyright (c) Microsoft Corporation. All rights reserved. // 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, 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() { if (typeof(T) == typeof(IReplyChannel)) { return (T)(object)this; } return base.GetProperty(); } 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(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)); } } } } }