e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
1090 lines
38 KiB
C#
1090 lines
38 KiB
C#
//------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------
|
|
|
|
namespace System.ServiceModel.Channels
|
|
{
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Runtime;
|
|
using System.ServiceModel;
|
|
using System.ServiceModel.Dispatcher;
|
|
using System.ServiceModel.Security;
|
|
|
|
abstract class ServerReliableChannelBinder<TChannel> : ReliableChannelBinder<TChannel>,
|
|
IServerReliableChannelBinder
|
|
where TChannel : class, IChannel
|
|
{
|
|
static string addressedPropertyName = "MessageAddressedByBinderProperty";
|
|
IChannelListener<TChannel> listener;
|
|
static AsyncCallback onAcceptChannelComplete = Fx.ThunkCallback(new AsyncCallback(OnAcceptChannelCompleteStatic));
|
|
EndpointAddress cachedLocalAddress;
|
|
TChannel pendingChannel;
|
|
InterruptibleWaitObject pendingChannelEvent = new InterruptibleWaitObject(false, false);
|
|
EndpointAddress remoteAddress;
|
|
|
|
protected ServerReliableChannelBinder(ChannelBuilder builder,
|
|
EndpointAddress remoteAddress, MessageFilter filter, int priority, MaskingMode maskingMode,
|
|
TolerateFaultsMode faultMode, TimeSpan defaultCloseTimeout,
|
|
TimeSpan defaultSendTimeout)
|
|
: base(null, maskingMode, faultMode, defaultCloseTimeout, defaultSendTimeout)
|
|
{
|
|
this.listener = builder.BuildChannelListener<TChannel>(filter, priority);
|
|
this.remoteAddress = remoteAddress;
|
|
}
|
|
|
|
protected ServerReliableChannelBinder(TChannel channel, EndpointAddress cachedLocalAddress,
|
|
EndpointAddress remoteAddress, MaskingMode maskingMode,
|
|
TolerateFaultsMode faultMode, TimeSpan defaultCloseTimeout,
|
|
TimeSpan defaultSendTimeout)
|
|
: base(channel, maskingMode, faultMode, defaultCloseTimeout, defaultSendTimeout)
|
|
{
|
|
this.cachedLocalAddress = cachedLocalAddress;
|
|
this.remoteAddress = remoteAddress;
|
|
}
|
|
|
|
protected override bool CanGetChannelForReceive
|
|
{
|
|
get
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public override EndpointAddress LocalAddress
|
|
{
|
|
get
|
|
{
|
|
if (this.cachedLocalAddress != null)
|
|
{
|
|
return this.cachedLocalAddress;
|
|
}
|
|
else
|
|
{
|
|
return this.GetInnerChannelLocalAddress();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override bool MustCloseChannel
|
|
{
|
|
get
|
|
{
|
|
return this.MustOpenChannel || this.HasSession;
|
|
}
|
|
}
|
|
|
|
protected override bool MustOpenChannel
|
|
{
|
|
get
|
|
{
|
|
return this.listener != null;
|
|
}
|
|
}
|
|
|
|
public override EndpointAddress RemoteAddress
|
|
{
|
|
get
|
|
{
|
|
return this.remoteAddress;
|
|
}
|
|
}
|
|
|
|
void AddAddressedProperty(Message message)
|
|
{
|
|
message.Properties.Add(addressedPropertyName, new object());
|
|
}
|
|
|
|
protected override void AddOutputHeaders(Message message)
|
|
{
|
|
if (this.GetAddressedProperty(message) == null)
|
|
{
|
|
this.RemoteAddress.ApplyTo(message);
|
|
this.AddAddressedProperty(message);
|
|
}
|
|
}
|
|
|
|
public bool AddressResponse(Message request, Message response)
|
|
{
|
|
if (this.GetAddressedProperty(response) != null)
|
|
{
|
|
throw Fx.AssertAndThrow("The binder can't address a response twice");
|
|
}
|
|
|
|
try
|
|
{
|
|
RequestReplyCorrelator.PrepareReply(response, request);
|
|
}
|
|
catch (MessageHeaderException exception)
|
|
{
|
|
// ---- it - we don't need to correlate the reply if the MessageId header is bad
|
|
if (DiagnosticUtility.ShouldTraceInformation)
|
|
DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
|
|
}
|
|
|
|
bool sendResponse = true;
|
|
try
|
|
{
|
|
sendResponse = RequestReplyCorrelator.AddressReply(response, request);
|
|
}
|
|
catch (MessageHeaderException exception)
|
|
{
|
|
// ---- it - we don't need to address the reply if the addressing headers are bad
|
|
if (DiagnosticUtility.ShouldTraceInformation)
|
|
DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
|
|
}
|
|
|
|
if (sendResponse)
|
|
this.AddAddressedProperty(response);
|
|
|
|
return sendResponse;
|
|
}
|
|
|
|
protected override IAsyncResult BeginTryGetChannel(TimeSpan timeout,
|
|
AsyncCallback callback, object state)
|
|
{
|
|
return this.pendingChannelEvent.BeginTryWait(timeout, callback, state);
|
|
}
|
|
|
|
public IAsyncResult BeginWaitForRequest(TimeSpan timeout, AsyncCallback callback,
|
|
object state)
|
|
{
|
|
if (this.DefaultMaskingMode != MaskingMode.None)
|
|
{
|
|
throw Fx.AssertAndThrow("This method was implemented only for the case where we do not mask exceptions.");
|
|
}
|
|
|
|
if (this.ValidateInputOperation(timeout))
|
|
{
|
|
return new WaitForRequestAsyncResult(this, timeout, callback, state);
|
|
}
|
|
else
|
|
{
|
|
return new CompletedAsyncResult(callback, state);
|
|
}
|
|
}
|
|
|
|
bool CompleteAcceptChannel(IAsyncResult result)
|
|
{
|
|
TChannel channel = this.listener.EndAcceptChannel(result);
|
|
|
|
if (channel == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!this.UseNewChannel(channel))
|
|
{
|
|
channel.Abort();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static IServerReliableChannelBinder CreateBinder(ChannelBuilder builder,
|
|
EndpointAddress remoteAddress, MessageFilter filter, int priority,
|
|
TolerateFaultsMode faultMode, TimeSpan defaultCloseTimeout,
|
|
TimeSpan defaultSendTimeout)
|
|
{
|
|
Type type = typeof(TChannel);
|
|
|
|
if (type == typeof(IDuplexChannel))
|
|
{
|
|
return new DuplexServerReliableChannelBinder(builder, remoteAddress, filter,
|
|
priority, MaskingMode.None, defaultCloseTimeout, defaultSendTimeout);
|
|
}
|
|
else if (type == typeof(IDuplexSessionChannel))
|
|
{
|
|
return new DuplexSessionServerReliableChannelBinder(builder, remoteAddress, filter,
|
|
priority, MaskingMode.None, faultMode, defaultCloseTimeout,
|
|
defaultSendTimeout);
|
|
}
|
|
else if (type == typeof(IReplyChannel))
|
|
{
|
|
return new ReplyServerReliableChannelBinder(builder, remoteAddress, filter,
|
|
priority, MaskingMode.None, defaultCloseTimeout, defaultSendTimeout);
|
|
}
|
|
else if (type == typeof(IReplySessionChannel))
|
|
{
|
|
return new ReplySessionServerReliableChannelBinder(builder, remoteAddress, filter,
|
|
priority, MaskingMode.None, faultMode, defaultCloseTimeout,
|
|
defaultSendTimeout);
|
|
}
|
|
else
|
|
{
|
|
throw Fx.AssertAndThrow("ServerReliableChannelBinder supports creation of IDuplexChannel, IDuplexSessionChannel, IReplyChannel, and IReplySessionChannel only.");
|
|
}
|
|
}
|
|
|
|
public static IServerReliableChannelBinder CreateBinder(TChannel channel,
|
|
EndpointAddress cachedLocalAddress, EndpointAddress remoteAddress,
|
|
TolerateFaultsMode faultMode, TimeSpan defaultCloseTimeout,
|
|
TimeSpan defaultSendTimeout)
|
|
{
|
|
Type type = typeof(TChannel);
|
|
|
|
if (type == typeof(IDuplexChannel))
|
|
{
|
|
return new DuplexServerReliableChannelBinder((IDuplexChannel)channel,
|
|
cachedLocalAddress, remoteAddress, MaskingMode.All, defaultCloseTimeout,
|
|
defaultSendTimeout);
|
|
}
|
|
else if (type == typeof(IDuplexSessionChannel))
|
|
{
|
|
return new DuplexSessionServerReliableChannelBinder((IDuplexSessionChannel)channel,
|
|
cachedLocalAddress, remoteAddress, MaskingMode.All, faultMode,
|
|
defaultCloseTimeout, defaultSendTimeout);
|
|
}
|
|
else if (type == typeof(IReplyChannel))
|
|
{
|
|
return new ReplyServerReliableChannelBinder((IReplyChannel)channel,
|
|
cachedLocalAddress, remoteAddress, MaskingMode.All, defaultCloseTimeout,
|
|
defaultSendTimeout);
|
|
}
|
|
else if (type == typeof(IReplySessionChannel))
|
|
{
|
|
return new ReplySessionServerReliableChannelBinder((IReplySessionChannel)channel,
|
|
cachedLocalAddress, remoteAddress, MaskingMode.All, faultMode,
|
|
defaultCloseTimeout, defaultSendTimeout);
|
|
}
|
|
else
|
|
{
|
|
throw Fx.AssertAndThrow("ServerReliableChannelBinder supports creation of IDuplexChannel, IDuplexSessionChannel, IReplyChannel, and IReplySessionChannel only.");
|
|
}
|
|
}
|
|
|
|
protected override bool EndTryGetChannel(IAsyncResult result)
|
|
{
|
|
if (!this.pendingChannelEvent.EndTryWait(result))
|
|
return false;
|
|
|
|
TChannel abortChannel = null;
|
|
|
|
lock (this.ThisLock)
|
|
{
|
|
if (this.State != CommunicationState.Faulted &&
|
|
this.State != CommunicationState.Closing &&
|
|
this.State != CommunicationState.Closed)
|
|
{
|
|
if (!this.Synchronizer.SetChannel(this.pendingChannel))
|
|
{
|
|
abortChannel = this.pendingChannel;
|
|
}
|
|
|
|
this.pendingChannel = null;
|
|
this.pendingChannelEvent.Reset();
|
|
}
|
|
}
|
|
|
|
if (abortChannel != null)
|
|
{
|
|
abortChannel.Abort();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool EndWaitForRequest(IAsyncResult result)
|
|
{
|
|
WaitForRequestAsyncResult waitForRequestResult = result as WaitForRequestAsyncResult;
|
|
|
|
if (waitForRequestResult != null)
|
|
{
|
|
return waitForRequestResult.End();
|
|
}
|
|
else
|
|
{
|
|
CompletedAsyncResult.End(result);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
object GetAddressedProperty(Message message)
|
|
{
|
|
object property;
|
|
|
|
message.Properties.TryGetValue(addressedPropertyName, out property);
|
|
return property;
|
|
}
|
|
|
|
protected abstract EndpointAddress GetInnerChannelLocalAddress();
|
|
|
|
bool IsListenerExceptionNullOrHandleable(Exception e)
|
|
{
|
|
if (e == null)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (this.listener.State == CommunicationState.Faulted)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return this.IsHandleable(e);
|
|
}
|
|
|
|
protected override void OnAbort()
|
|
{
|
|
if (this.listener != null)
|
|
{
|
|
this.listener.Abort();
|
|
}
|
|
}
|
|
|
|
void OnAcceptChannelComplete(IAsyncResult result)
|
|
{
|
|
Exception expectedException = null;
|
|
Exception unexpectedException = null;
|
|
bool gotChannel = false;
|
|
|
|
try
|
|
{
|
|
gotChannel = this.CompleteAcceptChannel(result);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (Fx.IsFatal(e))
|
|
{
|
|
throw;
|
|
}
|
|
|
|
if (this.IsHandleable(e))
|
|
{
|
|
expectedException = e;
|
|
}
|
|
else
|
|
{
|
|
unexpectedException = e;
|
|
}
|
|
}
|
|
|
|
if (gotChannel)
|
|
{
|
|
this.StartAccepting();
|
|
}
|
|
else if (unexpectedException != null)
|
|
{
|
|
this.Fault(unexpectedException);
|
|
}
|
|
else if ((expectedException != null)
|
|
&& (this.listener.State == CommunicationState.Opened))
|
|
{
|
|
this.StartAccepting();
|
|
}
|
|
else if (this.listener.State == CommunicationState.Faulted)
|
|
{
|
|
this.Fault(expectedException);
|
|
}
|
|
}
|
|
|
|
static void OnAcceptChannelCompleteStatic(IAsyncResult result)
|
|
{
|
|
if (!result.CompletedSynchronously)
|
|
{
|
|
ServerReliableChannelBinder<TChannel> binder =
|
|
(ServerReliableChannelBinder<TChannel>)result.AsyncState;
|
|
|
|
binder.OnAcceptChannelComplete(result);
|
|
}
|
|
}
|
|
|
|
protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback,
|
|
object state)
|
|
{
|
|
if (this.listener != null)
|
|
{
|
|
return this.listener.BeginClose(timeout, callback, state);
|
|
}
|
|
else
|
|
{
|
|
return new CompletedAsyncResult(callback, state);
|
|
}
|
|
}
|
|
|
|
protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback,
|
|
object state)
|
|
{
|
|
if (this.listener != null)
|
|
{
|
|
return this.listener.BeginOpen(timeout, callback, state);
|
|
}
|
|
else
|
|
{
|
|
return new CompletedAsyncResult(callback, state);
|
|
}
|
|
}
|
|
|
|
protected abstract IAsyncResult OnBeginWaitForRequest(TChannel channel, TimeSpan timeout,
|
|
AsyncCallback callback, object state);
|
|
|
|
protected override void OnClose(TimeSpan timeout)
|
|
{
|
|
if (this.listener != null)
|
|
{
|
|
this.listener.Close(timeout);
|
|
}
|
|
}
|
|
|
|
protected override void OnShutdown()
|
|
{
|
|
TChannel channel = null;
|
|
|
|
lock (this.ThisLock)
|
|
{
|
|
channel = this.pendingChannel;
|
|
this.pendingChannel = null;
|
|
this.pendingChannelEvent.Set();
|
|
}
|
|
|
|
if (channel != null)
|
|
channel.Abort();
|
|
}
|
|
|
|
protected abstract bool OnWaitForRequest(TChannel channel, TimeSpan timeout);
|
|
|
|
protected override void OnEndClose(IAsyncResult result)
|
|
{
|
|
if (this.listener != null)
|
|
{
|
|
this.listener.EndClose(result);
|
|
}
|
|
else
|
|
{
|
|
CompletedAsyncResult.End(result);
|
|
}
|
|
}
|
|
|
|
protected override void OnEndOpen(IAsyncResult result)
|
|
{
|
|
if (this.listener != null)
|
|
{
|
|
this.listener.EndOpen(result);
|
|
this.StartAccepting();
|
|
}
|
|
else
|
|
{
|
|
CompletedAsyncResult.End(result);
|
|
}
|
|
}
|
|
|
|
protected abstract bool OnEndWaitForRequest(TChannel channel, IAsyncResult result);
|
|
|
|
protected override void OnOpen(TimeSpan timeout)
|
|
{
|
|
if (this.listener != null)
|
|
{
|
|
this.listener.Open(timeout);
|
|
this.StartAccepting();
|
|
}
|
|
}
|
|
|
|
void StartAccepting()
|
|
{
|
|
Exception expectedException = null;
|
|
Exception unexpectedException = null;
|
|
|
|
while (this.listener.State == CommunicationState.Opened)
|
|
{
|
|
expectedException = null;
|
|
unexpectedException = null;
|
|
|
|
try
|
|
{
|
|
IAsyncResult result = this.listener.BeginAcceptChannel(TimeSpan.MaxValue,
|
|
onAcceptChannelComplete, this);
|
|
|
|
if (!result.CompletedSynchronously)
|
|
{
|
|
return;
|
|
}
|
|
else if (!this.CompleteAcceptChannel(result))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (Fx.IsFatal(e))
|
|
{
|
|
throw;
|
|
}
|
|
|
|
if (this.IsHandleable(e))
|
|
{
|
|
expectedException = e;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
unexpectedException = e;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (unexpectedException != null)
|
|
{
|
|
this.Fault(unexpectedException);
|
|
}
|
|
else if (this.listener.State == CommunicationState.Faulted)
|
|
{
|
|
this.Fault(expectedException);
|
|
}
|
|
}
|
|
|
|
protected override bool TryGetChannel(TimeSpan timeout)
|
|
{
|
|
if (!this.pendingChannelEvent.Wait(timeout))
|
|
return false;
|
|
|
|
TChannel abortChannel = null;
|
|
|
|
lock (this.ThisLock)
|
|
{
|
|
if (this.State != CommunicationState.Faulted &&
|
|
this.State != CommunicationState.Closing &&
|
|
this.State != CommunicationState.Closed)
|
|
{
|
|
if (!this.Synchronizer.SetChannel(this.pendingChannel))
|
|
{
|
|
abortChannel = this.pendingChannel;
|
|
}
|
|
|
|
this.pendingChannel = null;
|
|
this.pendingChannelEvent.Reset();
|
|
}
|
|
}
|
|
|
|
if (abortChannel != null)
|
|
{
|
|
abortChannel.Abort();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool UseNewChannel(IChannel channel)
|
|
{
|
|
TChannel oldPendingChannel = null;
|
|
TChannel oldBinderChannel = null;
|
|
|
|
lock (this.ThisLock)
|
|
{
|
|
if (!this.Synchronizer.TolerateFaults ||
|
|
this.State == CommunicationState.Faulted ||
|
|
this.State == CommunicationState.Closing ||
|
|
this.State == CommunicationState.Closed)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
oldPendingChannel = this.pendingChannel;
|
|
this.pendingChannel = (TChannel)channel;
|
|
oldBinderChannel = this.Synchronizer.AbortCurentChannel();
|
|
}
|
|
}
|
|
|
|
if (oldPendingChannel != null)
|
|
{
|
|
oldPendingChannel.Abort();
|
|
}
|
|
|
|
this.pendingChannelEvent.Set();
|
|
|
|
if (oldBinderChannel != null)
|
|
{
|
|
oldBinderChannel.Abort();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool WaitForRequest(TimeSpan timeout)
|
|
{
|
|
if (this.DefaultMaskingMode != MaskingMode.None)
|
|
{
|
|
throw Fx.AssertAndThrow("This method was implemented only for the case where we do not mask exceptions.");
|
|
}
|
|
|
|
if (!this.ValidateInputOperation(timeout))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
|
|
|
|
while (true)
|
|
{
|
|
bool autoAborted = false;
|
|
|
|
try
|
|
{
|
|
TChannel channel;
|
|
bool success = !this.Synchronizer.TryGetChannelForInput(true, timeoutHelper.RemainingTime(),
|
|
out channel);
|
|
|
|
if (channel == null)
|
|
{
|
|
return success;
|
|
}
|
|
|
|
try
|
|
{
|
|
return this.OnWaitForRequest(channel, timeoutHelper.RemainingTime());
|
|
}
|
|
finally
|
|
{
|
|
autoAborted = this.Synchronizer.Aborting;
|
|
this.Synchronizer.ReturnChannel();
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
if (Fx.IsFatal(e))
|
|
throw;
|
|
|
|
if (!this.HandleException(e, this.DefaultMaskingMode, autoAborted))
|
|
{
|
|
throw;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
abstract class DuplexServerReliableChannelBinder<TDuplexChannel>
|
|
: ServerReliableChannelBinder<TDuplexChannel>
|
|
where TDuplexChannel : class, IDuplexChannel
|
|
{
|
|
protected DuplexServerReliableChannelBinder(ChannelBuilder builder,
|
|
EndpointAddress remoteAddress, MessageFilter filter, int priority,
|
|
MaskingMode maskingMode, TolerateFaultsMode faultMode,
|
|
TimeSpan defaultCloseTimeout, TimeSpan defaultSendTimeout)
|
|
: base(builder, remoteAddress, filter, priority, maskingMode, faultMode,
|
|
defaultCloseTimeout, defaultSendTimeout)
|
|
{
|
|
}
|
|
|
|
protected DuplexServerReliableChannelBinder(TDuplexChannel channel,
|
|
EndpointAddress cachedLocalAddress, EndpointAddress remoteAddress,
|
|
MaskingMode maskingMode, TolerateFaultsMode faultMode,
|
|
TimeSpan defaultCloseTimeout, TimeSpan defaultSendTimeout)
|
|
: base(channel, cachedLocalAddress, remoteAddress, maskingMode, faultMode,
|
|
defaultCloseTimeout, defaultSendTimeout)
|
|
{
|
|
}
|
|
|
|
public override bool CanSendAsynchronously
|
|
{
|
|
get
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
protected override EndpointAddress GetInnerChannelLocalAddress()
|
|
{
|
|
IDuplexChannel channel = this.Synchronizer.CurrentChannel;
|
|
EndpointAddress localAddress = (channel == null) ? null : channel.LocalAddress;
|
|
return localAddress;
|
|
}
|
|
|
|
protected override IAsyncResult OnBeginSend(TDuplexChannel channel, Message message,
|
|
TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return channel.BeginSend(message, timeout, callback, state);
|
|
}
|
|
|
|
protected override IAsyncResult OnBeginTryReceive(TDuplexChannel channel,
|
|
TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return channel.BeginTryReceive(timeout, callback, state);
|
|
}
|
|
|
|
protected override IAsyncResult OnBeginWaitForRequest(TDuplexChannel channel,
|
|
TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return channel.BeginWaitForMessage(timeout, callback, state);
|
|
}
|
|
|
|
protected override void OnEndSend(TDuplexChannel channel, IAsyncResult result)
|
|
{
|
|
channel.EndSend(result);
|
|
}
|
|
|
|
protected override bool OnEndTryReceive(TDuplexChannel channel, IAsyncResult result,
|
|
out RequestContext requestContext)
|
|
{
|
|
Message message;
|
|
bool success = channel.EndTryReceive(result, out message);
|
|
if (success)
|
|
{
|
|
this.OnMessageReceived(message);
|
|
}
|
|
requestContext = this.WrapMessage(message);
|
|
return success;
|
|
}
|
|
|
|
protected override bool OnEndWaitForRequest(TDuplexChannel channel,
|
|
IAsyncResult result)
|
|
{
|
|
return channel.EndWaitForMessage(result);
|
|
}
|
|
|
|
protected abstract void OnMessageReceived(Message message);
|
|
|
|
protected override void OnSend(TDuplexChannel channel, Message message,
|
|
TimeSpan timeout)
|
|
{
|
|
channel.Send(message, timeout);
|
|
}
|
|
|
|
protected override bool OnTryReceive(TDuplexChannel channel, TimeSpan timeout,
|
|
out RequestContext requestContext)
|
|
{
|
|
Message message;
|
|
bool success = channel.TryReceive(timeout, out message);
|
|
if (success)
|
|
{
|
|
this.OnMessageReceived(message);
|
|
}
|
|
requestContext = this.WrapMessage(message);
|
|
return success;
|
|
}
|
|
|
|
protected override bool OnWaitForRequest(TDuplexChannel channel, TimeSpan timeout)
|
|
{
|
|
return channel.WaitForMessage(timeout);
|
|
}
|
|
|
|
}
|
|
|
|
sealed class DuplexServerReliableChannelBinder
|
|
: DuplexServerReliableChannelBinder<IDuplexChannel>
|
|
{
|
|
public DuplexServerReliableChannelBinder(ChannelBuilder builder,
|
|
EndpointAddress remoteAddress, MessageFilter filter, int priority,
|
|
MaskingMode maskingMode, TimeSpan defaultCloseTimeout, TimeSpan defaultSendTimeout)
|
|
: base(builder, remoteAddress, filter, priority, maskingMode,
|
|
TolerateFaultsMode.Never, defaultCloseTimeout, defaultSendTimeout)
|
|
{
|
|
}
|
|
|
|
public DuplexServerReliableChannelBinder(IDuplexChannel channel,
|
|
EndpointAddress cachedLocalAddress, EndpointAddress remoteAddress,
|
|
MaskingMode maskingMode, TimeSpan defaultCloseTimeout, TimeSpan defaultSendTimeout)
|
|
: base(channel, cachedLocalAddress, remoteAddress, maskingMode, TolerateFaultsMode.Never,
|
|
defaultCloseTimeout, defaultSendTimeout)
|
|
{
|
|
}
|
|
|
|
public override bool HasSession
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public override ISession GetInnerSession()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
protected override bool HasSecuritySession(IDuplexChannel channel)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
protected override void OnMessageReceived(Message message)
|
|
{
|
|
}
|
|
}
|
|
|
|
sealed class DuplexSessionServerReliableChannelBinder
|
|
: DuplexServerReliableChannelBinder<IDuplexSessionChannel>
|
|
{
|
|
public DuplexSessionServerReliableChannelBinder(ChannelBuilder builder,
|
|
EndpointAddress remoteAddress, MessageFilter filter, int priority,
|
|
MaskingMode maskingMode, TolerateFaultsMode faultMode,
|
|
TimeSpan defaultCloseTimeout, TimeSpan defaultSendTimeout)
|
|
: base(builder, remoteAddress, filter, priority, maskingMode, faultMode,
|
|
defaultCloseTimeout, defaultSendTimeout)
|
|
{
|
|
}
|
|
|
|
public DuplexSessionServerReliableChannelBinder(IDuplexSessionChannel channel,
|
|
EndpointAddress cachedLocalAddress, EndpointAddress remoteAddress,
|
|
MaskingMode maskingMode, TolerateFaultsMode faultMode,
|
|
TimeSpan defaultCloseTimeout, TimeSpan defaultSendTimeout)
|
|
: base(channel, cachedLocalAddress, remoteAddress, maskingMode, faultMode,
|
|
defaultCloseTimeout, defaultSendTimeout)
|
|
{
|
|
}
|
|
|
|
public override bool HasSession
|
|
{
|
|
get
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
protected override IAsyncResult BeginCloseChannel(IDuplexSessionChannel channel,
|
|
TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return ReliableChannelBinderHelper.BeginCloseDuplexSessionChannel(this, channel,
|
|
timeout, callback, state);
|
|
}
|
|
|
|
protected override void CloseChannel(IDuplexSessionChannel channel, TimeSpan timeout)
|
|
{
|
|
ReliableChannelBinderHelper.CloseDuplexSessionChannel(this, channel, timeout);
|
|
}
|
|
|
|
protected override void EndCloseChannel(IDuplexSessionChannel channel,
|
|
IAsyncResult result)
|
|
{
|
|
ReliableChannelBinderHelper.EndCloseDuplexSessionChannel(channel, result);
|
|
}
|
|
|
|
public override ISession GetInnerSession()
|
|
{
|
|
return this.Synchronizer.CurrentChannel.Session;
|
|
}
|
|
|
|
protected override bool HasSecuritySession(IDuplexSessionChannel channel)
|
|
{
|
|
return channel.Session is ISecuritySession;
|
|
}
|
|
|
|
protected override void OnMessageReceived(Message message)
|
|
{
|
|
if (message == null)
|
|
this.Synchronizer.OnReadEof();
|
|
}
|
|
}
|
|
|
|
abstract class ReplyServerReliableChannelBinder<TReplyChannel>
|
|
: ServerReliableChannelBinder<TReplyChannel>
|
|
where TReplyChannel : class, IReplyChannel
|
|
{
|
|
public ReplyServerReliableChannelBinder(ChannelBuilder builder,
|
|
EndpointAddress remoteAddress, MessageFilter filter, int priority,
|
|
MaskingMode maskingMode, TolerateFaultsMode faultMode,
|
|
TimeSpan defaultCloseTimeout, TimeSpan defaultSendTimeout)
|
|
: base(builder, remoteAddress, filter, priority, maskingMode, faultMode,
|
|
defaultCloseTimeout, defaultSendTimeout)
|
|
{
|
|
}
|
|
|
|
public ReplyServerReliableChannelBinder(TReplyChannel channel,
|
|
EndpointAddress cachedLocalAddress, EndpointAddress remoteAddress,
|
|
MaskingMode maskingMode, TolerateFaultsMode faultMode,
|
|
TimeSpan defaultCloseTimeout, TimeSpan defaultSendTimeout)
|
|
: base(channel, cachedLocalAddress, remoteAddress, maskingMode, faultMode,
|
|
defaultCloseTimeout, defaultSendTimeout)
|
|
{
|
|
}
|
|
|
|
public override bool CanSendAsynchronously
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
protected override EndpointAddress GetInnerChannelLocalAddress()
|
|
{
|
|
IReplyChannel channel = this.Synchronizer.CurrentChannel;
|
|
EndpointAddress localAddress = (channel == null) ? null : channel.LocalAddress;
|
|
return localAddress;
|
|
}
|
|
|
|
protected override IAsyncResult OnBeginTryReceive(TReplyChannel channel,
|
|
TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return channel.BeginTryReceiveRequest(timeout, callback, state);
|
|
}
|
|
|
|
protected override IAsyncResult OnBeginWaitForRequest(TReplyChannel channel,
|
|
TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return channel.BeginWaitForRequest(timeout, callback, state);
|
|
}
|
|
|
|
protected override bool OnEndTryReceive(TReplyChannel channel, IAsyncResult result,
|
|
out RequestContext requestContext)
|
|
{
|
|
bool success = channel.EndTryReceiveRequest(result, out requestContext);
|
|
if (success && (requestContext == null))
|
|
{
|
|
this.OnReadNullMessage();
|
|
}
|
|
requestContext = this.WrapRequestContext(requestContext);
|
|
return success;
|
|
}
|
|
|
|
protected override bool OnEndWaitForRequest(TReplyChannel channel, IAsyncResult result)
|
|
{
|
|
return channel.EndWaitForRequest(result);
|
|
}
|
|
|
|
protected virtual void OnReadNullMessage()
|
|
{
|
|
}
|
|
|
|
protected override bool OnTryReceive(TReplyChannel channel, TimeSpan timeout,
|
|
out RequestContext requestContext)
|
|
{
|
|
bool success = channel.TryReceiveRequest(timeout, out requestContext);
|
|
if (success && (requestContext == null))
|
|
{
|
|
this.OnReadNullMessage();
|
|
}
|
|
requestContext = this.WrapRequestContext(requestContext);
|
|
return success;
|
|
}
|
|
|
|
protected override bool OnWaitForRequest(TReplyChannel channel, TimeSpan timeout)
|
|
{
|
|
return channel.WaitForRequest(timeout);
|
|
}
|
|
}
|
|
|
|
sealed class ReplyServerReliableChannelBinder
|
|
: ReplyServerReliableChannelBinder<IReplyChannel>
|
|
{
|
|
public ReplyServerReliableChannelBinder(ChannelBuilder builder,
|
|
EndpointAddress remoteAddress, MessageFilter filter, int priority,
|
|
MaskingMode maskingMode, TimeSpan defaultCloseTimeout, TimeSpan defaultSendTimeout)
|
|
: base(builder, remoteAddress, filter, priority, maskingMode,
|
|
TolerateFaultsMode.Never, defaultCloseTimeout, defaultSendTimeout)
|
|
{
|
|
}
|
|
|
|
public ReplyServerReliableChannelBinder(IReplyChannel channel,
|
|
EndpointAddress cachedLocalAddress, EndpointAddress remoteAddress,
|
|
MaskingMode maskingMode, TimeSpan defaultCloseTimeout, TimeSpan defaultSendTimeout)
|
|
: base(channel, cachedLocalAddress, remoteAddress, maskingMode,
|
|
TolerateFaultsMode.Never, defaultCloseTimeout, defaultSendTimeout)
|
|
{
|
|
}
|
|
|
|
public override bool HasSession
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public override ISession GetInnerSession()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
protected override bool HasSecuritySession(IReplyChannel channel)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
sealed class ReplySessionServerReliableChannelBinder
|
|
: ReplyServerReliableChannelBinder<IReplySessionChannel>
|
|
{
|
|
public ReplySessionServerReliableChannelBinder(ChannelBuilder builder,
|
|
EndpointAddress remoteAddress, MessageFilter filter, int priority,
|
|
MaskingMode maskingMode, TolerateFaultsMode faultMode,
|
|
TimeSpan defaultCloseTimeout, TimeSpan defaultSendTimeout)
|
|
: base(builder, remoteAddress, filter, priority, maskingMode, faultMode,
|
|
defaultCloseTimeout, defaultSendTimeout)
|
|
{
|
|
}
|
|
|
|
public ReplySessionServerReliableChannelBinder(IReplySessionChannel channel,
|
|
EndpointAddress cachedLocalAddress, EndpointAddress remoteAddress,
|
|
MaskingMode maskingMode, TolerateFaultsMode faultMode,
|
|
TimeSpan defaultCloseTimeout, TimeSpan defaultSendTimeout)
|
|
: base(channel, cachedLocalAddress, remoteAddress, maskingMode, faultMode,
|
|
defaultCloseTimeout, defaultSendTimeout)
|
|
{
|
|
}
|
|
|
|
public override bool HasSession
|
|
{
|
|
get
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
protected override IAsyncResult BeginCloseChannel(IReplySessionChannel channel,
|
|
TimeSpan timeout, AsyncCallback callback, object state)
|
|
{
|
|
return ReliableChannelBinderHelper.BeginCloseReplySessionChannel(this, channel,
|
|
timeout, callback, state);
|
|
}
|
|
|
|
protected override void CloseChannel(IReplySessionChannel channel, TimeSpan timeout)
|
|
{
|
|
ReliableChannelBinderHelper.CloseReplySessionChannel(this, channel, timeout);
|
|
}
|
|
|
|
protected override void EndCloseChannel(IReplySessionChannel channel,
|
|
IAsyncResult result)
|
|
{
|
|
ReliableChannelBinderHelper.EndCloseReplySessionChannel(channel, result);
|
|
}
|
|
|
|
public override ISession GetInnerSession()
|
|
{
|
|
return this.Synchronizer.CurrentChannel.Session;
|
|
}
|
|
|
|
protected override bool HasSecuritySession(IReplySessionChannel channel)
|
|
{
|
|
return channel.Session is ISecuritySession;
|
|
}
|
|
|
|
protected override void OnReadNullMessage()
|
|
{
|
|
this.Synchronizer.OnReadEof();
|
|
}
|
|
}
|
|
|
|
sealed class WaitForRequestAsyncResult
|
|
: InputAsyncResult<ServerReliableChannelBinder<TChannel>>
|
|
{
|
|
public WaitForRequestAsyncResult(ServerReliableChannelBinder<TChannel> binder,
|
|
TimeSpan timeout, AsyncCallback callback, object state)
|
|
: base(binder, true, timeout, binder.DefaultMaskingMode, callback, state)
|
|
{
|
|
if (this.Start())
|
|
this.Complete(true);
|
|
}
|
|
|
|
protected override IAsyncResult BeginInput(
|
|
ServerReliableChannelBinder<TChannel> binder, TChannel channel, TimeSpan timeout,
|
|
AsyncCallback callback, object state)
|
|
{
|
|
return binder.OnBeginWaitForRequest(channel, timeout, callback, state);
|
|
}
|
|
|
|
protected override bool EndInput(ServerReliableChannelBinder<TChannel> binder,
|
|
TChannel channel, IAsyncResult result, out bool complete)
|
|
{
|
|
complete = true;
|
|
return binder.OnEndWaitForRequest(channel, result);
|
|
}
|
|
}
|
|
}
|
|
}
|