| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208 |
- //----------------------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //--------------------------------------------------------------------------
- namespace System.ServiceModel.Channels
- {
- using System;
- using System.Runtime;
- using System.ServiceModel;
- using System.ServiceModel.Diagnostics.Application;
- using System.ServiceModel.Security;
- using System.Threading;
- using System.Xml;
- abstract class ChannelReliableSession : ISession
- {
- IReliableChannelBinder binder;
- bool canSendFault = true;
- ChannelBase channel;
- SessionFaultState faulted = SessionFaultState.NotFaulted;
- FaultHelper faultHelper;
- SequenceRangeCollection finalRanges;
- Guard guard = new Guard(int.MaxValue);
- InterruptibleTimer inactivityTimer;
- TimeSpan initiationTime;
- UniqueId inputID;
- bool isSessionClosed = false;
- UniqueId outputID;
- RequestContext replyFaultContext;
- IReliableFactorySettings settings;
- Message terminatingFault;
- object thisLock = new object();
- UnblockChannelCloseHandler unblockChannelCloseCallback;
- protected ChannelReliableSession(ChannelBase channel, IReliableFactorySettings settings, IReliableChannelBinder binder, FaultHelper faultHelper)
- {
- this.channel = channel;
- this.settings = settings;
- this.binder = binder;
- this.faultHelper = faultHelper;
- this.inactivityTimer = new InterruptibleTimer(this.settings.InactivityTimeout, new WaitCallback(this.OnInactivityElapsed), null);
- this.initiationTime = ReliableMessagingConstants.UnknownInitiationTime;
- }
- protected ChannelBase Channel
- {
- get
- {
- return this.channel;
- }
- }
- protected Guard Guard
- {
- get
- {
- return this.guard;
- }
- }
- public string Id
- {
- get
- {
- UniqueId sequenceId = this.SequenceID;
- if (sequenceId == null)
- return null;
- else
- return sequenceId.ToString();
- }
- }
- public TimeSpan InitiationTime
- {
- get
- {
- return this.initiationTime;
- }
- protected set
- {
- this.initiationTime = value;
- }
- }
- public UniqueId InputID
- {
- get
- {
- return this.inputID;
- }
- protected set
- {
- this.inputID = value;
- }
- }
- protected FaultHelper FaultHelper
- {
- get
- {
- return this.faultHelper;
- }
- }
- public UniqueId OutputID
- {
- get
- {
- return this.outputID;
- }
- protected set
- {
- this.outputID = value;
- }
- }
- public abstract UniqueId SequenceID
- {
- get;
- }
- public IReliableFactorySettings Settings
- {
- get
- {
- return this.settings;
- }
- }
- protected object ThisLock
- {
- get
- {
- return this.thisLock;
- }
- }
- public UnblockChannelCloseHandler UnblockChannelCloseCallback
- {
- set
- {
- this.unblockChannelCloseCallback = value;
- }
- }
- public virtual void Abort()
- {
- this.guard.Abort();
- this.inactivityTimer.Abort();
- // Try to send a fault.
- bool sendFault;
- lock (this.ThisLock)
- {
- // Faulted thread already cleaned up. No need to to anything more.
- if (this.faulted == SessionFaultState.CleanedUp)
- return;
- // Can only send a fault if the other side did not send one already.
- sendFault = this.canSendFault && (this.faulted != SessionFaultState.RemotelyFaulted); // NotFaulted || LocallyFaulted
- this.faulted = SessionFaultState.CleanedUp;
- }
- if (sendFault)
- {
- if ((this.binder.State == CommunicationState.Opened)
- && this.binder.Connected
- && (this.binder.CanSendAsynchronously || (this.replyFaultContext != null)))
- {
- if (this.terminatingFault == null)
- {
- UniqueId sequenceId = this.InputID ?? this.OutputID;
- if (sequenceId != null)
- {
- WsrmFault fault = SequenceTerminatedFault.CreateCommunicationFault(sequenceId, SR.GetString(SR.SequenceTerminatedOnAbort), null);
- this.terminatingFault = fault.CreateMessage(this.settings.MessageVersion,
- this.settings.ReliableMessagingVersion);
- }
- }
- if (this.terminatingFault != null)
- {
- this.AddFinalRanges();
- this.faultHelper.SendFaultAsync(this.binder, this.replyFaultContext, this.terminatingFault);
- return;
- }
- }
- }
- // Got here so the session did not actually send a fault, must clean up resources.
- if (this.terminatingFault != null)
- this.terminatingFault.Close();
- if (this.replyFaultContext != null)
- this.replyFaultContext.Abort();
- this.binder.Abort();
- }
- void AddFinalRanges()
- {
- // This relies on the assumption that acknowledgements can be piggybacked on sequence
- // faults for the converse sequence.
- if (this.finalRanges != null)
- {
- WsrmUtilities.AddAcknowledgementHeader(this.settings.ReliableMessagingVersion,
- this.terminatingFault, this.InputID, this.finalRanges, true);
- }
- }
- public virtual IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state)
- {
- return this.guard.BeginClose(timeout, callback, state);
- }
- public abstract IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state);
- public virtual void Close(TimeSpan timeout)
- {
- this.guard.Close(timeout);
- this.inactivityTimer.Abort();
- }
- // Corresponds to the state where the other side could have gone away already.
- public void CloseSession()
- {
- this.isSessionClosed = true;
- }
- public virtual void EndClose(IAsyncResult result)
- {
- this.guard.EndClose(result);
- this.inactivityTimer.Abort();
- }
- public abstract void EndOpen(IAsyncResult result);
- protected virtual void FaultCore()
- {
- if (TD.ReliableSessionChannelFaultedIsEnabled())
- {
- TD.ReliableSessionChannelFaulted(this.Id);
- }
- this.inactivityTimer.Abort();
- }
- public void OnLocalFault(Exception e, WsrmFault fault, RequestContext context)
- {
- Message faultMessage = (fault == null) ? null : fault.CreateMessage(this.settings.MessageVersion,
- this.settings.ReliableMessagingVersion);
- this.OnLocalFault(e, faultMessage, context);
- }
- public void OnLocalFault(Exception e, Message faultMessage, RequestContext context)
- {
- if (this.channel.Aborted ||
- this.channel.State == CommunicationState.Faulted ||
- this.channel.State == CommunicationState.Closed)
- {
- if (faultMessage != null)
- faultMessage.Close();
- if (context != null)
- context.Abort();
- return;
- }
- lock (this.ThisLock)
- {
- if (this.faulted != SessionFaultState.NotFaulted)
- return;
- this.faulted = SessionFaultState.LocallyFaulted;
- this.terminatingFault = faultMessage;
- this.replyFaultContext = context;
- }
- this.FaultCore();
- this.channel.Fault(e);
- this.UnblockChannelIfNecessary();
- }
- public void OnRemoteFault(WsrmFault fault)
- {
- this.OnRemoteFault(WsrmFault.CreateException(fault));
- }
- public void OnRemoteFault(Exception e)
- {
- if (this.channel.Aborted ||
- this.channel.State == CommunicationState.Faulted ||
- this.channel.State == CommunicationState.Closed)
- {
- return;
- }
- lock (this.ThisLock)
- {
- if (this.faulted != SessionFaultState.NotFaulted)
- return;
- this.faulted = SessionFaultState.RemotelyFaulted;
- }
- this.FaultCore();
- this.channel.Fault(e);
- this.UnblockChannelIfNecessary();
- }
- public virtual void OnFaulted()
- {
- this.FaultCore();
- // Try to send a fault.
- bool sendFault;
- lock (this.ThisLock)
- {
- // Channel was faulted without the session being told first (e.g. open throws).
- // The session does not know what fault to send so let abort send it if it can.
- if (this.faulted == SessionFaultState.NotFaulted)
- return;
- // Abort thread decided to clean up.
- if (this.faulted == SessionFaultState.CleanedUp)
- return;
- // Can only send a fault if the other side did not send one already.
- sendFault = this.canSendFault && (this.faulted != SessionFaultState.RemotelyFaulted); // LocallyFaulted
- this.faulted = SessionFaultState.CleanedUp;
- }
- if (sendFault)
- {
- if ((this.binder.State == CommunicationState.Opened)
- && this.binder.Connected
- && (this.binder.CanSendAsynchronously || (this.replyFaultContext != null))
- && (this.terminatingFault != null))
- {
- this.AddFinalRanges();
- this.faultHelper.SendFaultAsync(this.binder, this.replyFaultContext, this.terminatingFault);
- return;
- }
- }
- // Got here so the session did not actually send a fault, must clean up resources.
- if (this.terminatingFault != null)
- this.terminatingFault.Close();
- if (this.replyFaultContext != null)
- this.replyFaultContext.Abort();
- this.binder.Abort();
- }
- void OnInactivityElapsed(object state)
- {
- WsrmFault fault;
- Exception e;
- string exceptionMessage = SR.GetString(SR.SequenceTerminatedInactivityTimeoutExceeded, this.settings.InactivityTimeout);
- if (TD.InactivityTimeoutIsEnabled())
- {
- TD.InactivityTimeout(exceptionMessage);
- }
- if (this.SequenceID != null)
- {
- string faultReason = SR.GetString(SR.SequenceTerminatedInactivityTimeoutExceeded, this.settings.InactivityTimeout);
- fault = SequenceTerminatedFault.CreateCommunicationFault(this.SequenceID, faultReason, exceptionMessage);
- e = fault.CreateException();
- }
- else
- {
- fault = null;
- e = new CommunicationException(exceptionMessage);
- }
- OnLocalFault(e, fault, null);
- }
- public abstract void OnLocalActivity();
- public void OnUnknownException(Exception e)
- {
- this.canSendFault = false;
- this.OnLocalFault(e, (Message)null, null);
- }
- public abstract void Open(TimeSpan timeout);
- public virtual void OnRemoteActivity(bool fastPolling)
- {
- this.inactivityTimer.Set();
- }
- // returns true if the info does not fault the session.
- public bool ProcessInfo(WsrmMessageInfo info, RequestContext context)
- {
- return this.ProcessInfo(info, context, false);
- }
- public bool ProcessInfo(WsrmMessageInfo info, RequestContext context, bool throwException)
- {
- Exception e;
- if (info.ParsingException != null)
- {
- WsrmFault fault;
- if (this.SequenceID != null)
- {
- string reason = SR.GetString(SR.CouldNotParseWithAction, info.Action);
- fault = SequenceTerminatedFault.CreateProtocolFault(this.SequenceID, reason, null);
- }
- else
- {
- fault = null;
- }
- e = new ProtocolException(SR.GetString(SR.MessageExceptionOccurred), info.ParsingException);
- this.OnLocalFault(throwException ? null : e, fault, context);
- }
- else if (info.FaultReply != null)
- {
- e = info.FaultException;
- this.OnLocalFault(throwException ? null : e, info.FaultReply, context);
- }
- else if ((info.WsrmHeaderFault != null) && (info.WsrmHeaderFault.SequenceID != this.InputID)
- && (info.WsrmHeaderFault.SequenceID != this.OutputID))
- {
- e = new ProtocolException(SR.GetString(SR.WrongIdentifierFault, FaultException.GetSafeReasonText(info.WsrmHeaderFault.Reason)));
- this.OnLocalFault(throwException ? null : e, (Message)null, context);
- }
- else if (info.FaultInfo != null)
- {
- if (this.isSessionClosed)
- {
- UnknownSequenceFault unknownSequenceFault = info.FaultInfo as UnknownSequenceFault;
- if (unknownSequenceFault != null)
- {
- UniqueId sequenceId = unknownSequenceFault.SequenceID;
- if (((this.OutputID != null) && (this.OutputID == sequenceId))
- || ((this.InputID != null) && (this.InputID == sequenceId)))
- {
- if (this.settings.ReliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005)
- {
- info.Message.Close();
- return false;
- }
- else if (this.settings.ReliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11)
- {
- return true;
- }
- else
- {
- throw Fx.AssertAndThrow("Unknown version.");
- }
- }
- }
- }
- e = info.FaultException;
- if (context != null)
- context.Close();
- this.OnRemoteFault(throwException ? null : e);
- }
- else
- {
- return true;
- }
- info.Message.Close();
- if (throwException)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e);
- else
- return false;
- }
- public void SetFinalAck(SequenceRangeCollection finalRanges)
- {
- this.finalRanges = finalRanges;
- }
- public virtual void StartInactivityTimer()
- {
- this.inactivityTimer.Set();
- }
- // RM channels fault out of band. During the Closing and Closed states CommunicationObjects
- // do not fault. In all other states the RM channel can and must unblock various methods
- // from the OnFaulted method. This method will ensure that anything that needs to unblock
- // in the Closing state will unblock if a fault occurs.
- void UnblockChannelIfNecessary()
- {
- lock (this.ThisLock)
- {
- if (this.faulted == SessionFaultState.NotFaulted)
- {
- throw Fx.AssertAndThrow("This method must be called from a fault thread.");
- }
- // Successfully faulted or aborted.
- else if (this.faulted == SessionFaultState.CleanedUp)
- {
- return;
- }
- }
- // Make sure the fault is sent then unblock the channel.
- this.OnFaulted();
- this.unblockChannelCloseCallback();
- }
- public bool VerifyDuplexProtocolElements(WsrmMessageInfo info, RequestContext context)
- {
- return this.VerifyDuplexProtocolElements(info, context, false);
- }
- public bool VerifyDuplexProtocolElements(WsrmMessageInfo info, RequestContext context, bool throwException)
- {
- WsrmFault fault = this.VerifyDuplexProtocolElements(info);
- if (fault == null)
- {
- return true;
- }
- if (throwException)
- {
- Exception e = fault.CreateException();
- this.OnLocalFault(null, fault, context);
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e);
- }
- else
- {
- this.OnLocalFault(fault.CreateException(), fault, context);
- return false;
- }
- }
- protected virtual WsrmFault VerifyDuplexProtocolElements(WsrmMessageInfo info)
- {
- if (info.AcknowledgementInfo != null && info.AcknowledgementInfo.SequenceID != this.OutputID)
- return new UnknownSequenceFault(info.AcknowledgementInfo.SequenceID);
- else if (info.AckRequestedInfo != null && info.AckRequestedInfo.SequenceID != this.InputID)
- return new UnknownSequenceFault(info.AckRequestedInfo.SequenceID);
- else if (info.SequencedMessageInfo != null && info.SequencedMessageInfo.SequenceID != this.InputID)
- return new UnknownSequenceFault(info.SequencedMessageInfo.SequenceID);
- else if (info.TerminateSequenceInfo != null && info.TerminateSequenceInfo.Identifier != this.InputID)
- {
- if (this.Settings.ReliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005)
- return SequenceTerminatedFault.CreateProtocolFault(this.OutputID, SR.GetString(SR.SequenceTerminatedUnexpectedTerminateSequence), SR.GetString(SR.UnexpectedTerminateSequence));
- else if (info.TerminateSequenceInfo.Identifier == this.OutputID)
- return null;
- else
- return new UnknownSequenceFault(info.TerminateSequenceInfo.Identifier);
- }
- else if (info.TerminateSequenceResponseInfo != null)
- {
- WsrmUtilities.AssertWsrm11(this.settings.ReliableMessagingVersion);
- if (info.TerminateSequenceResponseInfo.Identifier == this.OutputID)
- return null;
- else
- return new UnknownSequenceFault(info.TerminateSequenceResponseInfo.Identifier);
- }
- else if (info.CloseSequenceInfo != null)
- {
- WsrmUtilities.AssertWsrm11(this.settings.ReliableMessagingVersion);
- if (info.CloseSequenceInfo.Identifier == this.InputID)
- return null;
- else if (info.CloseSequenceInfo.Identifier == this.OutputID)
- // Spec allows RM-Destination close, but we do not.
- return SequenceTerminatedFault.CreateProtocolFault(this.OutputID, SR.GetString(SR.SequenceTerminatedUnsupportedClose), SR.GetString(SR.UnsupportedCloseExceptionString));
- else
- return new UnknownSequenceFault(info.CloseSequenceInfo.Identifier);
- }
- else if (info.CloseSequenceResponseInfo != null)
- {
- WsrmUtilities.AssertWsrm11(this.settings.ReliableMessagingVersion);
- if (info.CloseSequenceResponseInfo.Identifier == this.OutputID)
- return null;
- else if (info.CloseSequenceResponseInfo.Identifier == this.InputID)
- return SequenceTerminatedFault.CreateProtocolFault(this.InputID, SR.GetString(SR.SequenceTerminatedUnexpectedCloseSequenceResponse), SR.GetString(SR.UnexpectedCloseSequenceResponse));
- else
- return new UnknownSequenceFault(info.CloseSequenceResponseInfo.Identifier);
- }
- else
- return null;
- }
- public bool VerifySimplexProtocolElements(WsrmMessageInfo info, RequestContext context)
- {
- return this.VerifySimplexProtocolElements(info, context, false);
- }
- public bool VerifySimplexProtocolElements(WsrmMessageInfo info, RequestContext context, bool throwException)
- {
- WsrmFault fault = this.VerifySimplexProtocolElements(info);
- if (fault == null)
- {
- return true;
- }
- info.Message.Close();
- if (throwException)
- {
- Exception e = fault.CreateException();
- this.OnLocalFault(null, fault, context);
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e);
- }
- else
- {
- this.OnLocalFault(fault.CreateException(), fault, context);
- return false;
- }
- }
- protected abstract WsrmFault VerifySimplexProtocolElements(WsrmMessageInfo info);
- enum SessionFaultState
- {
- NotFaulted,
- LocallyFaulted,
- RemotelyFaulted,
- CleanedUp
- }
- public delegate void UnblockChannelCloseHandler();
- }
- class ClientReliableSession : ChannelReliableSession, IOutputSession
- {
- IClientReliableChannelBinder binder;
- PollingMode oldPollingMode;
- PollingHandler pollingHandler;
- PollingMode pollingMode;
- InterruptibleTimer pollingTimer;
- ReliableRequestor requestor;
- public delegate void PollingHandler();
- public ClientReliableSession(ChannelBase channel, IReliableFactorySettings factory, IClientReliableChannelBinder binder, FaultHelper faultHelper, UniqueId inputID) :
- base(channel, factory, binder, faultHelper)
- {
- this.binder = binder;
- this.InputID = inputID;
- this.pollingTimer = new InterruptibleTimer(this.GetPollingInterval(), this.OnPollingTimerElapsed, null);
- if (this.binder.Channel is IRequestChannel)
- {
- this.requestor = new RequestReliableRequestor();
- }
- else if (this.binder.Channel is IDuplexChannel)
- {
- SendReceiveReliableRequestor sendReceiveRequestor = new SendReceiveReliableRequestor();
- sendReceiveRequestor.TimeoutIsSafe = !this.ChannelSupportsOneCreateSequenceAttempt();
- this.requestor = sendReceiveRequestor;
- }
- else
- {
- Fx.Assert("This channel type is not supported");
- }
- MessageVersion messageVersion = this.Settings.MessageVersion;
- ReliableMessagingVersion reliableMessagingVersion = this.Settings.ReliableMessagingVersion;
- this.requestor.MessageVersion = messageVersion;
- this.requestor.Binder = this.binder;
- this.requestor.IsCreateSequence = true;
- this.requestor.TimeoutString1Index = SR.TimeoutOnOpen;
- this.requestor.MessageAction = WsrmIndex.GetCreateSequenceActionHeader(messageVersion.Addressing,
- reliableMessagingVersion);
- if ((reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11)
- && (this.binder.GetInnerSession() is ISecureConversationSession))
- {
- this.requestor.MessageHeader = new WsrmUsesSequenceSTRHeader();
- }
- this.requestor.MessageBody = new CreateSequence(this.Settings.MessageVersion.Addressing,
- reliableMessagingVersion, this.Settings.Ordered, this.binder, this.InputID);
- this.requestor.SetRequestResponsePattern();
- }
- public PollingHandler PollingCallback
- {
- set
- {
- this.pollingHandler = value;
- }
- }
- public override UniqueId SequenceID
- {
- get
- {
- return this.OutputID;
- }
- }
- public override void Abort()
- {
- ReliableRequestor temp = this.requestor;
- if (temp != null)
- temp.Abort(this.Channel);
- pollingTimer.Abort();
- base.Abort();
- }
- public override IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
- {
- if (this.pollingHandler == null)
- {
- throw Fx.AssertAndThrow("The client reliable channel must set the polling handler prior to opening the client reliable session.");
- }
- return new OpenAsyncResult(this, timeout, callback, state);
- }
- bool ChannelSupportsOneCreateSequenceAttempt()
- {
- IDuplexSessionChannel channel = this.binder.Channel as IDuplexSessionChannel;
- if (channel == null)
- return false;
- return (channel.Session is ISecuritySession && !(channel.Session is ISecureConversationSession));
- }
- public override void Close(TimeSpan timeout)
- {
- base.Close(timeout);
- pollingTimer.Abort();
- }
- public override void EndClose(IAsyncResult result)
- {
- base.EndClose(result);
- pollingTimer.Abort();
- }
- public override void EndOpen(IAsyncResult result)
- {
- OpenAsyncResult.End(result);
- this.requestor = null;
- }
- protected override void FaultCore()
- {
- this.pollingTimer.Abort();
- base.FaultCore();
- }
- TimeSpan GetPollingInterval()
- {
- switch (this.pollingMode)
- {
- case PollingMode.Idle:
- return Ticks.ToTimeSpan(Ticks.FromTimeSpan(this.Settings.InactivityTimeout) / 2);
- case PollingMode.KeepAlive:
- return WsrmUtilities.CalculateKeepAliveInterval(this.Settings.InactivityTimeout, this.Settings.MaxRetryCount);
- case PollingMode.NotPolling:
- return TimeSpan.MaxValue;
- case PollingMode.FastPolling:
- TimeSpan keepAliveInterval = WsrmUtilities.CalculateKeepAliveInterval(this.Settings.InactivityTimeout, this.Settings.MaxRetryCount);
- TimeSpan fastPollingInterval = Ticks.ToTimeSpan(Ticks.FromTimeSpan(this.binder.DefaultSendTimeout) / 2);
- if (fastPollingInterval < keepAliveInterval)
- return fastPollingInterval;
- else
- return keepAliveInterval;
- default:
- throw Fx.AssertAndThrow("Unknown polling mode.");
- }
- }
- public override void OnFaulted()
- {
- base.OnFaulted();
- ReliableRequestor temp = this.requestor;
- if (temp != null)
- this.requestor.Fault(this.Channel);
- }
- void OnPollingTimerElapsed(object state)
- {
- if (this.Guard.Enter())
- {
- try
- {
- lock (this.ThisLock)
- {
- if (this.pollingMode == PollingMode.NotPolling)
- return;
- if (this.pollingMode == PollingMode.Idle)
- this.pollingMode = PollingMode.KeepAlive;
- }
- this.pollingHandler();
- this.pollingTimer.Set(this.GetPollingInterval());
- }
- finally
- {
- this.Guard.Exit();
- }
- }
- }
- public override void OnLocalActivity()
- {
- lock (this.ThisLock)
- {
- if (this.pollingMode == PollingMode.NotPolling)
- return;
- this.pollingTimer.Set(this.GetPollingInterval());
- }
- }
- public override void Open(TimeSpan timeout)
- {
- if (this.pollingHandler == null)
- {
- throw Fx.AssertAndThrow("The client reliable channel must set the polling handler prior to opening the client reliable session.");
- }
- DateTime start = DateTime.UtcNow;
- Message response = this.requestor.Request(timeout);
- this.ProcessCreateSequenceResponse(response, start);
- this.requestor = null;
- }
- public override void OnRemoteActivity(bool fastPolling)
- {
- base.OnRemoteActivity(fastPolling);
- lock (this.ThisLock)
- {
- if (this.pollingMode == PollingMode.NotPolling)
- return;
- if (fastPolling)
- this.pollingMode = PollingMode.FastPolling;
- else
- this.pollingMode = PollingMode.Idle;
- this.pollingTimer.Set(this.GetPollingInterval());
- }
- }
- void ProcessCreateSequenceResponse(Message response, DateTime start)
- {
- CreateSequenceResponseInfo createResponse = null;
- using (response)
- {
- if (response.IsFault)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(WsrmUtilities.CreateCSFaultException(
- this.Settings.MessageVersion, this.Settings.ReliableMessagingVersion, response,
- this.binder.Channel));
- }
- else
- {
- WsrmMessageInfo info = WsrmMessageInfo.Get(this.Settings.MessageVersion,
- this.Settings.ReliableMessagingVersion, this.binder.Channel, this.binder.GetInnerSession(),
- response, true);
- if (info.ParsingException != null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.GetString(SR.UnparsableCSResponse), info.ParsingException));
- // this throws and sends a fault if something is wrong with the info
- this.ProcessInfo(info, null, true);
- createResponse = info.CreateSequenceResponseInfo;
- string exceptionReason = null;
- string faultReason = null;
- if (createResponse == null)
- {
- exceptionReason = SR.GetString(SR.InvalidWsrmResponseChannelNotOpened,
- WsrmFeb2005Strings.CreateSequence, info.Action,
- WsrmIndex.GetCreateSequenceResponseActionString(this.Settings.ReliableMessagingVersion));
- }
- else if (!object.Equals(createResponse.RelatesTo, this.requestor.MessageId))
- {
- exceptionReason = SR.GetString(SR.WsrmMessageWithWrongRelatesToExceptionString, WsrmFeb2005Strings.CreateSequence);
- faultReason = SR.GetString(SR.WsrmMessageWithWrongRelatesToFaultString, WsrmFeb2005Strings.CreateSequence);
- }
- else if ((createResponse.AcceptAcksTo == null) && (this.InputID != null))
- {
- if (this.Settings.ReliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005)
- {
- exceptionReason = SR.GetString(SR.CSResponseWithoutOffer);
- faultReason = SR.GetString(SR.CSResponseWithoutOfferReason);
- }
- else if (this.Settings.ReliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11)
- {
- exceptionReason = SR.GetString(SR.CSResponseOfferRejected);
- faultReason = SR.GetString(SR.CSResponseOfferRejectedReason);
- }
- else
- {
- throw Fx.AssertAndThrow("Reliable messaging version not supported.");
- }
- }
- else if ((createResponse.AcceptAcksTo != null) && (this.InputID == null))
- {
- exceptionReason = SR.GetString(SR.CSResponseWithOffer);
- faultReason = SR.GetString(SR.CSResponseWithOfferReason);
- }
- else if (createResponse.AcceptAcksTo != null && (createResponse.AcceptAcksTo.Uri != this.binder.RemoteAddress.Uri))
- {
- exceptionReason = SR.GetString(SR.AcksToMustBeSameAsRemoteAddress);
- faultReason = SR.GetString(SR.AcksToMustBeSameAsRemoteAddressReason);
- }
- if ((faultReason != null) && (createResponse != null))
- {
- UniqueId sequenceId = createResponse.Identifier;
- WsrmFault fault = SequenceTerminatedFault.CreateProtocolFault(sequenceId, faultReason, null);
- this.OnLocalFault(null, fault, null);
- }
- if (exceptionReason != null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(exceptionReason));
- }
- }
- this.InitiationTime = DateTime.UtcNow - start;
- this.OutputID = createResponse.Identifier;
- this.pollingTimer.Set(this.GetPollingInterval());
- base.StartInactivityTimer();
- }
- public void ResumePolling(bool fastPolling)
- {
- lock (this.ThisLock)
- {
- if (this.pollingMode != PollingMode.NotPolling)
- {
- throw Fx.AssertAndThrow("Can't resume polling if pollingMode != PollingMode.NotPolling");
- }
- if (fastPolling)
- {
- this.pollingMode = PollingMode.FastPolling;
- }
- else
- {
- if (this.oldPollingMode == PollingMode.FastPolling)
- this.pollingMode = PollingMode.Idle;
- else
- this.pollingMode = this.oldPollingMode;
- }
- this.Guard.Exit();
- this.pollingTimer.Set(this.GetPollingInterval());
- }
- }
- // Returns true if caller should resume polling
- public bool StopPolling()
- {
- lock (this.ThisLock)
- {
- if (this.pollingMode == PollingMode.NotPolling)
- return false;
- this.oldPollingMode = pollingMode;
- this.pollingMode = PollingMode.NotPolling;
- this.pollingTimer.Cancel();
- return this.Guard.Enter();
- }
- }
- protected override WsrmFault VerifyDuplexProtocolElements(WsrmMessageInfo info)
- {
- WsrmFault fault = base.VerifyDuplexProtocolElements(info);
- if (fault != null)
- return fault;
- else if (info.CreateSequenceInfo != null)
- return SequenceTerminatedFault.CreateProtocolFault(this.OutputID, SR.GetString(SR.SequenceTerminatedUnexpectedCS), SR.GetString(SR.UnexpectedCS));
- else if (info.CreateSequenceResponseInfo != null && info.CreateSequenceResponseInfo.Identifier != this.OutputID)
- return SequenceTerminatedFault.CreateProtocolFault(this.OutputID, SR.GetString(SR.SequenceTerminatedUnexpectedCSROfferId), SR.GetString(SR.UnexpectedCSROfferId));
- else
- return null;
- }
- protected override WsrmFault VerifySimplexProtocolElements(WsrmMessageInfo info)
- {
- if (info.AcknowledgementInfo != null && info.AcknowledgementInfo.SequenceID != this.OutputID)
- return new UnknownSequenceFault(info.AcknowledgementInfo.SequenceID);
- else if (info.AckRequestedInfo != null)
- return SequenceTerminatedFault.CreateProtocolFault(this.OutputID, SR.GetString(SR.SequenceTerminatedUnexpectedAckRequested), SR.GetString(SR.UnexpectedAckRequested));
- else if (info.CreateSequenceInfo != null)
- return SequenceTerminatedFault.CreateProtocolFault(this.OutputID, SR.GetString(SR.SequenceTerminatedUnexpectedCS), SR.GetString(SR.UnexpectedCS));
- else if (info.SequencedMessageInfo != null)
- return new UnknownSequenceFault(info.SequencedMessageInfo.SequenceID);
- else if (info.TerminateSequenceInfo != null)
- {
- if (this.Settings.ReliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005)
- return SequenceTerminatedFault.CreateProtocolFault(this.OutputID, SR.GetString(SR.SequenceTerminatedUnexpectedTerminateSequence), SR.GetString(SR.UnexpectedTerminateSequence));
- else if (info.TerminateSequenceInfo.Identifier == this.OutputID)
- return null;
- else
- return new UnknownSequenceFault(info.TerminateSequenceInfo.Identifier);
- }
- else if (info.TerminateSequenceResponseInfo != null)
- {
- WsrmUtilities.AssertWsrm11(this.Settings.ReliableMessagingVersion);
- if (info.TerminateSequenceResponseInfo.Identifier == this.OutputID)
- return null;
- else
- return new UnknownSequenceFault(info.TerminateSequenceResponseInfo.Identifier);
- }
- else if (info.CloseSequenceInfo != null)
- {
- WsrmUtilities.AssertWsrm11(this.Settings.ReliableMessagingVersion);
- if (info.CloseSequenceInfo.Identifier == this.OutputID)
- return SequenceTerminatedFault.CreateProtocolFault(this.OutputID, SR.GetString(SR.SequenceTerminatedUnsupportedClose), SR.GetString(SR.UnsupportedCloseExceptionString));
- else
- return new UnknownSequenceFault(info.CloseSequenceInfo.Identifier);
- }
- else if (info.CloseSequenceResponseInfo != null)
- {
- WsrmUtilities.AssertWsrm11(this.Settings.ReliableMessagingVersion);
- if (info.CloseSequenceResponseInfo.Identifier == this.OutputID)
- return null;
- else
- return new UnknownSequenceFault(info.CloseSequenceResponseInfo.Identifier);
- }
- else
- return null;
- }
- class OpenAsyncResult : AsyncResult
- {
- static AsyncCallback onRequestComplete = Fx.ThunkCallback(new AsyncCallback(OnRequestCompleteStatic));
- ClientReliableSession session;
- DateTime start;
- public OpenAsyncResult(ClientReliableSession session, TimeSpan timeout, AsyncCallback callback, object state)
- : base(callback, state)
- {
- this.session = session;
- this.start = DateTime.UtcNow;
- IAsyncResult result = this.session.requestor.BeginRequest(timeout, onRequestComplete, this);
- if (result.CompletedSynchronously)
- {
- this.CompleteRequest(result);
- this.Complete(true);
- }
- }
- void CompleteRequest(IAsyncResult result)
- {
- Message response = this.session.requestor.EndRequest(result);
- this.session.ProcessCreateSequenceResponse(response, this.start);
- }
- public static void End(IAsyncResult result)
- {
- AsyncResult.End<OpenAsyncResult>(result);
- }
- static void OnRequestCompleteStatic(IAsyncResult result)
- {
- if (result.CompletedSynchronously)
- return;
- OpenAsyncResult openResult = (OpenAsyncResult)result.AsyncState;
- Exception exception = null;
- try
- {
- openResult.CompleteRequest(result);
- }
- catch (Exception e)
- {
- if (Fx.IsFatal(e))
- throw;
- exception = e;
- }
- openResult.Complete(false, exception);
- }
- }
- enum PollingMode
- {
- Idle,
- KeepAlive,
- FastPolling,
- NotPolling
- }
- }
- class ServerReliableSession : ChannelReliableSession, IInputSession
- {
- public ServerReliableSession(
- ChannelBase channel,
- IReliableFactorySettings listener,
- IServerReliableChannelBinder binder,
- FaultHelper faultHelper,
- UniqueId inputID,
- UniqueId outputID)
- : base(channel, listener, binder, faultHelper)
- {
- this.InputID = inputID;
- this.OutputID = outputID;
- }
- public override UniqueId SequenceID
- {
- get
- {
- return this.InputID;
- }
- }
- public override IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
- {
- return new CompletedAsyncResult(callback, state);
- }
- public override void EndOpen(IAsyncResult result)
- {
- CompletedAsyncResult.End(result);
- base.StartInactivityTimer();
- }
- public override void OnLocalActivity()
- {
- }
- public override void Open(TimeSpan timeout)
- {
- this.StartInactivityTimer();
- }
- protected override WsrmFault VerifyDuplexProtocolElements(WsrmMessageInfo info)
- {
- WsrmFault fault = base.VerifyDuplexProtocolElements(info);
- if (fault != null)
- return fault;
- else if (info.CreateSequenceInfo != null && info.CreateSequenceInfo.OfferIdentifier != this.OutputID)
- return SequenceTerminatedFault.CreateProtocolFault(this.OutputID, SR.GetString(SR.SequenceTerminatedUnexpectedCSOfferId), SR.GetString(SR.UnexpectedCSOfferId));
- else if (info.CreateSequenceResponseInfo != null)
- return SequenceTerminatedFault.CreateProtocolFault(this.OutputID, SR.GetString(SR.SequenceTerminatedUnexpectedCSR), SR.GetString(SR.UnexpectedCSR));
- else
- return null;
- }
- protected override WsrmFault VerifySimplexProtocolElements(WsrmMessageInfo info)
- {
- if (info.AcknowledgementInfo != null)
- return SequenceTerminatedFault.CreateProtocolFault(this.InputID, SR.GetString(SR.SequenceTerminatedUnexpectedAcknowledgement), SR.GetString(SR.UnexpectedAcknowledgement));
- else if (info.AckRequestedInfo != null && info.AckRequestedInfo.SequenceID != this.InputID)
- return new UnknownSequenceFault(info.AckRequestedInfo.SequenceID);
- else if (info.CreateSequenceResponseInfo != null)
- return SequenceTerminatedFault.CreateProtocolFault(this.InputID, SR.GetString(SR.SequenceTerminatedUnexpectedCSR), SR.GetString(SR.UnexpectedCSR));
- else if (info.SequencedMessageInfo != null && info.SequencedMessageInfo.SequenceID != this.InputID)
- return new UnknownSequenceFault(info.SequencedMessageInfo.SequenceID);
- else if (info.TerminateSequenceInfo != null && info.TerminateSequenceInfo.Identifier != this.InputID)
- return new UnknownSequenceFault(info.TerminateSequenceInfo.Identifier);
- else if (info.TerminateSequenceResponseInfo != null)
- {
- WsrmUtilities.AssertWsrm11(this.Settings.ReliableMessagingVersion);
- if (info.TerminateSequenceResponseInfo.Identifier == this.InputID)
- return SequenceTerminatedFault.CreateProtocolFault(this.InputID, SR.GetString(SR.SequenceTerminatedUnexpectedTerminateSequenceResponse), SR.GetString(SR.UnexpectedTerminateSequenceResponse));
- else
- return new UnknownSequenceFault(info.TerminateSequenceResponseInfo.Identifier);
- }
- else if (info.CloseSequenceInfo != null)
- {
- WsrmUtilities.AssertWsrm11(this.Settings.ReliableMessagingVersion);
- if (info.CloseSequenceInfo.Identifier == this.InputID)
- return null;
- else
- return new UnknownSequenceFault(info.CloseSequenceInfo.Identifier);
- }
- else if (info.CloseSequenceResponseInfo != null)
- {
- WsrmUtilities.AssertWsrm11(this.Settings.ReliableMessagingVersion);
- if (info.CloseSequenceResponseInfo.Identifier == this.InputID)
- return SequenceTerminatedFault.CreateProtocolFault(this.InputID, SR.GetString(SR.SequenceTerminatedUnexpectedCloseSequenceResponse), SR.GetString(SR.UnexpectedCloseSequenceResponse));
- else
- return new UnknownSequenceFault(info.CloseSequenceResponseInfo.Identifier);
- }
- else
- return null;
- }
- }
- }
|