private void ProcessReply(Message reply, IReliableRequest request, long requestSequenceNumber) { WsrmMessageInfo info = WsrmMessageInfo.Get(this.settings.MessageVersion, this.settings.ReliableMessagingVersion, this.binder.Channel, this.binder.GetInnerSession(), reply); if (this.session.ProcessInfo(info, null) && this.session.VerifyDuplexProtocolElements(info, null)) { bool flag = this.settings.ReliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11; if (info.WsrmHeaderFault != null) { info.Message.Close(); if (!(info.WsrmHeaderFault is UnknownSequenceFault)) { throw Fx.AssertAndThrow("Fault must be UnknownSequence fault."); } if (this.terminateRequestor == null) { throw Fx.AssertAndThrow("If we start getting UnknownSequence, terminateRequestor cannot be null."); } this.terminateRequestor.SetInfo(info); } else if (info.AcknowledgementInfo == null) { WsrmFault fault = SequenceTerminatedFault.CreateProtocolFault(this.session.InputID, System.ServiceModel.SR.GetString("SequenceTerminatedReplyMissingAcknowledgement"), System.ServiceModel.SR.GetString("ReplyMissingAcknowledgement")); info.Message.Close(); this.session.OnLocalFault(fault.CreateException(), fault, null); } else if (flag && (info.TerminateSequenceInfo != null)) { UniqueId sequenceID = (info.TerminateSequenceInfo.Identifier == this.session.OutputID) ? this.session.InputID : this.session.OutputID; WsrmFault fault2 = SequenceTerminatedFault.CreateProtocolFault(sequenceID, System.ServiceModel.SR.GetString("SequenceTerminatedUnsupportedTerminateSequence"), System.ServiceModel.SR.GetString("UnsupportedTerminateSequenceExceptionString")); info.Message.Close(); this.session.OnLocalFault(fault2.CreateException(), fault2, null); } else if (flag && info.AcknowledgementInfo.Final) { info.Message.Close(); if (this.closeRequestor == null) { string exceptionMessage = System.ServiceModel.SR.GetString("UnsupportedCloseExceptionString"); string faultReason = System.ServiceModel.SR.GetString("SequenceTerminatedUnsupportedClose"); WsrmFault fault3 = SequenceTerminatedFault.CreateProtocolFault(this.session.OutputID, faultReason, exceptionMessage); this.session.OnLocalFault(fault3.CreateException(), fault3, null); } else { WsrmFault fault4 = WsrmUtilities.ValidateFinalAck(this.session, info, this.connection.Last); if (fault4 == null) { this.closeRequestor.SetInfo(info); } else { this.session.OnLocalFault(fault4.CreateException(), fault4, null); } } } else { int quotaRemaining = -1; if (this.settings.FlowControlEnabled) { quotaRemaining = info.AcknowledgementInfo.BufferRemaining; } if ((info.SequencedMessageInfo != null) && !ReliableInputConnection.CanMerge(info.SequencedMessageInfo.SequenceNumber, this.ranges)) { info.Message.Close(); } else { bool flag2 = (this.replyAckConsistencyGuard != null) ? this.replyAckConsistencyGuard.Enter() : false; try { this.connection.ProcessTransferred(requestSequenceNumber, info.AcknowledgementInfo.Ranges, quotaRemaining); this.session.OnRemoteActivity(this.connection.Strategy.QuotaRemaining == 0); if (info.SequencedMessageInfo != null) { lock (base.ThisLock) { this.ranges = this.ranges.MergeWith(info.SequencedMessageInfo.SequenceNumber); } } } finally { if (flag2) { this.replyAckConsistencyGuard.Exit(); } } if (request != null) { if (WsrmUtilities.IsWsrmAction(this.settings.ReliableMessagingVersion, info.Action)) { info.Message.Close(); request.Set(null); } else { request.Set(info.Message); } } if ((this.shutdownHandle != null) && this.connection.CheckForTermination()) { this.shutdownHandle.Set(); } if (request != null) { request.Complete(); } } } } }
void ProcessReply(Message reply, IReliableRequest request, Int64 requestSequenceNumber) { WsrmMessageInfo messageInfo = WsrmMessageInfo.Get(this.settings.MessageVersion, this.settings.ReliableMessagingVersion, this.binder.Channel, this.binder.GetInnerSession(), reply); if (!this.session.ProcessInfo(messageInfo, null)) { return; } if (!this.session.VerifyDuplexProtocolElements(messageInfo, null)) { return; } bool wsrm11 = this.settings.ReliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11; if (messageInfo.WsrmHeaderFault != null) { // Close message now, going to stop processing in all cases. messageInfo.Message.Close(); if (!(messageInfo.WsrmHeaderFault is UnknownSequenceFault)) { throw Fx.AssertAndThrow("Fault must be UnknownSequence fault."); } if (this.terminateRequestor == null) { throw Fx.AssertAndThrow("If we start getting UnknownSequence, terminateRequestor cannot be null."); } this.terminateRequestor.SetInfo(messageInfo); return; } if (messageInfo.AcknowledgementInfo == null) { WsrmFault fault = SequenceTerminatedFault.CreateProtocolFault(this.session.InputID, SR.GetString(SR.SequenceTerminatedReplyMissingAcknowledgement), SR.GetString(SR.ReplyMissingAcknowledgement)); messageInfo.Message.Close(); this.session.OnLocalFault(fault.CreateException(), fault, null); return; } if (wsrm11 && (messageInfo.TerminateSequenceInfo != null)) { UniqueId faultId = (messageInfo.TerminateSequenceInfo.Identifier == this.session.OutputID) ? this.session.InputID : this.session.OutputID; WsrmFault fault = SequenceTerminatedFault.CreateProtocolFault(faultId, SR.GetString(SR.SequenceTerminatedUnsupportedTerminateSequence), SR.GetString(SR.UnsupportedTerminateSequenceExceptionString)); messageInfo.Message.Close(); this.session.OnLocalFault(fault.CreateException(), fault, null); return; } else if (wsrm11 && messageInfo.AcknowledgementInfo.Final) { // Close message now, going to stop processing in all cases. messageInfo.Message.Close(); if (this.closeRequestor == null) { // Remote endpoint signaled Close, this is not allowed so we fault. string exceptionString = SR.GetString(SR.UnsupportedCloseExceptionString); string faultString = SR.GetString(SR.SequenceTerminatedUnsupportedClose); WsrmFault fault = SequenceTerminatedFault.CreateProtocolFault(this.session.OutputID, faultString, exceptionString); this.session.OnLocalFault(fault.CreateException(), fault, null); } else { WsrmFault fault = WsrmUtilities.ValidateFinalAck(this.session, messageInfo, this.connection.Last); if (fault == null) { // Received valid final ack after sending Close, inform the close thread. this.closeRequestor.SetInfo(messageInfo); } else { // Received invalid final ack after sending Close, fault. this.session.OnLocalFault(fault.CreateException(), fault, null); } } return; } int bufferRemaining = -1; if (this.settings.FlowControlEnabled) { bufferRemaining = messageInfo.AcknowledgementInfo.BufferRemaining; } // We accept no more than MaxSequenceRanges ranges to limit the serialized ack size and // the amount of memory taken up by the ack ranges. Since request reply uses the presence of // a reply as an acknowledgement we cannot call ProcessTransferred (which stops retrying the // request) if we intend to drop the message. This means the limit is not strict since we do // not check for the limit and merge the ranges atomically. The limit + the number of // concurrent threads is a sufficient mitigation. if ((messageInfo.SequencedMessageInfo != null) && !ReliableInputConnection.CanMerge(messageInfo.SequencedMessageInfo.SequenceNumber, this.ranges)) { messageInfo.Message.Close(); return; } bool exitGuard = this.replyAckConsistencyGuard != null?this.replyAckConsistencyGuard.Enter() : false; try { this.connection.ProcessTransferred(requestSequenceNumber, messageInfo.AcknowledgementInfo.Ranges, bufferRemaining); this.session.OnRemoteActivity(this.connection.Strategy.QuotaRemaining == 0); if (messageInfo.SequencedMessageInfo != null) { lock (this.ThisLock) { this.ranges = this.ranges.MergeWith(messageInfo.SequencedMessageInfo.SequenceNumber); } } } finally { if (exitGuard) { this.replyAckConsistencyGuard.Exit(); } } if (request != null) { if (WsrmUtilities.IsWsrmAction(this.settings.ReliableMessagingVersion, messageInfo.Action)) { messageInfo.Message.Close(); request.Set(null); } else { request.Set(messageInfo.Message); } } // The termination mechanism in the TerminateSequence fails with RequestReply. // Since the ack ranges are updated after ProcessTransferred is called and // ProcessTransferred potentially signals the Termination process, this channel // winds up sending a message with the ack for last message missing. // Thus we send the termination after we update the ranges. if ((this.shutdownHandle != null) && this.connection.CheckForTermination()) { this.shutdownHandle.Set(); } if (request != null) { request.Complete(); } }
public bool CanMerge(Int64 sequenceNumber) { return(ReliableInputConnection.CanMerge(sequenceNumber, this.ranges)); }