//---------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- namespace System.ServiceModel.Channels { using System.Runtime; sealed class ReliableInputConnection { bool isLastKnown = false; bool isSequenceClosed = false; Int64 last = 0; SequenceRangeCollection ranges = SequenceRangeCollection.Empty; ReliableMessagingVersion reliableMessagingVersion; InterruptibleWaitObject shutdownWaitObject = new InterruptibleWaitObject(false); bool terminated = false; InterruptibleWaitObject terminateWaitObject = new InterruptibleWaitObject(false, false); public ReliableInputConnection() { } public bool AllAdded { get { return (this.ranges.Count == 1 && this.ranges[0].Lower == 1 && this.ranges[0].Upper == this.last) || this.isLastKnown; } } public bool IsLastKnown { get { return this.last != 0 || this.isLastKnown; } } public bool IsSequenceClosed { get { return this.isSequenceClosed; } } public Int64 Last { get { return this.last; } } public SequenceRangeCollection Ranges { get { return this.ranges; } } public ReliableMessagingVersion ReliableMessagingVersion { set { this.reliableMessagingVersion = value; } } public void Abort(ChannelBase channel) { this.shutdownWaitObject.Abort(channel); this.terminateWaitObject.Abort(channel); } public bool CanMerge(Int64 sequenceNumber) { return ReliableInputConnection.CanMerge(sequenceNumber, this.ranges); } // Returns true if merging the number will not increase the number of ranges past MaxSequenceRanges. public static bool CanMerge(Int64 sequenceNumber, SequenceRangeCollection ranges) { if (ranges.Count < ReliableMessagingConstants.MaxSequenceRanges) { return true; } ranges = ranges.MergeWith(sequenceNumber); return ranges.Count <= ReliableMessagingConstants.MaxSequenceRanges; } public void Fault(ChannelBase channel) { this.shutdownWaitObject.Fault(channel); this.terminateWaitObject.Fault(channel); } public bool IsValid(Int64 sequenceNumber, bool isLast) { if (this.reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) { if (isLast) { if (this.last == 0) { if (this.ranges.Count > 0) { return sequenceNumber > this.ranges[this.ranges.Count - 1].Upper; } else { return true; } } else { return sequenceNumber == this.last; } } else if (this.last > 0) { return sequenceNumber < this.last; } } else { if (this.isLastKnown) { return this.ranges.Contains(sequenceNumber); } } return true; } public void Merge(Int64 sequenceNumber, bool isLast) { this.ranges = this.ranges.MergeWith(sequenceNumber); if (isLast) this.last = sequenceNumber; if (this.AllAdded) this.shutdownWaitObject.Set(); } public bool SetCloseSequenceLast(Int64 last) { WsrmUtilities.AssertWsrm11(this.reliableMessagingVersion); bool validLast; if ((last < 1) || (this.ranges.Count == 0)) { validLast = true; } else { validLast = last >= this.ranges[this.ranges.Count - 1].Upper; } if (validLast) { this.isSequenceClosed = true; this.SetLast(last); } return validLast; } void SetLast(Int64 last) { if (this.isLastKnown) { throw Fx.AssertAndThrow("Last can only be set once."); } this.last = last; this.isLastKnown = true; this.shutdownWaitObject.Set(); } // Two error cases: // (1) The sequence contains holes. // (2) TerminateSequence.LastMsgNumber < last received message number. // In both cases the channel should be faulted. In case (2) the channel should send a fault. public bool SetTerminateSequenceLast(Int64 last, out bool isLastLargeEnough) { WsrmUtilities.AssertWsrm11(this.reliableMessagingVersion); isLastLargeEnough = true; // unspecified last if (last < 1) { return false; } int rangeCount = this.ranges.Count; Int64 lastReceived = (rangeCount > 0) ? this.ranges[rangeCount - 1].Upper : 0; // last is too small to be valid if (last < lastReceived) { isLastLargeEnough = false; return false; } // there is a hole in the sequence if ((rangeCount > 1) || (last > lastReceived)) { return false; } this.SetLast(last); return true; } public bool Terminate() { if ((this.reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) || this.isSequenceClosed) { if (!this.terminated && this.AllAdded) { this.terminateWaitObject.Set(); this.terminated = true; } return this.terminated; } return this.isLastKnown; } public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state) { OperationWithTimeoutBeginCallback[] beginCallbacks = new OperationWithTimeoutBeginCallback[] { shutdownWaitObject.BeginWait, terminateWaitObject.BeginWait }; OperationEndCallback[] endCallbacks = new OperationEndCallback[] { shutdownWaitObject.EndWait, terminateWaitObject.EndWait }; return OperationWithTimeoutComposer.BeginComposeAsyncOperations(timeout, beginCallbacks, endCallbacks, callback, state); } public void Close(TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); this.shutdownWaitObject.Wait(timeoutHelper.RemainingTime()); this.terminateWaitObject.Wait(timeoutHelper.RemainingTime()); } public void EndClose(IAsyncResult result) { OperationWithTimeoutComposer.EndComposeAsyncOperations(result); } } }