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();
            }
        }
예제 #3
0
 public bool CanMerge(Int64 sequenceNumber)
 {
     return(ReliableInputConnection.CanMerge(sequenceNumber, this.ranges));
 }