Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / Channels / ReliableChannelBinder.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.ServiceModel.Channels
6 {
7     using System.Collections.Generic;
8     using System.Runtime;
9     using System.ServiceModel;
10     using System.Threading;
11
12     enum TolerateFaultsMode
13     {
14         Never,
15         IfNotSecuritySession,
16         Always
17     }
18
19     [Flags]
20     enum MaskingMode
21     {
22         None = 0x0,
23         Handled = 0x1,
24         Unhandled = 0x2,
25         All = Handled | Unhandled
26     }
27
28     abstract class ReliableChannelBinder<TChannel> : IReliableChannelBinder
29         where TChannel : class, IChannel
30     {
31         bool aborted = false;
32         TimeSpan defaultCloseTimeout;
33         MaskingMode defaultMaskingMode;
34         TimeSpan defaultSendTimeout;
35         AsyncCallback onCloseChannelComplete;
36         CommunicationState state = CommunicationState.Created;
37         ChannelSynchronizer synchronizer;
38         object thisLock = new object();
39
40         protected ReliableChannelBinder(TChannel channel, MaskingMode maskingMode,
41             TolerateFaultsMode faultMode, TimeSpan defaultCloseTimeout,
42             TimeSpan defaultSendTimeout)
43         {
44             if ((maskingMode != MaskingMode.None) && (maskingMode != MaskingMode.All))
45             {
46                 throw Fx.AssertAndThrow("ReliableChannelBinder was implemented with only 2 default masking modes, None and All.");
47             }
48
49             this.defaultMaskingMode = maskingMode;
50             this.defaultCloseTimeout = defaultCloseTimeout;
51             this.defaultSendTimeout = defaultSendTimeout;
52
53             this.synchronizer = new ChannelSynchronizer(this, channel, faultMode);
54         }
55
56         protected abstract bool CanGetChannelForReceive
57         {
58             get;
59         }
60
61         public abstract bool CanSendAsynchronously
62         {
63             get;
64         }
65
66         public virtual ChannelParameterCollection ChannelParameters
67         {
68             get { return null; }
69         }
70
71         public IChannel Channel
72         {
73             get
74             {
75                 return this.synchronizer.CurrentChannel;
76             }
77         }
78
79         public bool Connected
80         {
81             get
82             {
83                 return this.synchronizer.Connected;
84             }
85         }
86
87         public MaskingMode DefaultMaskingMode
88         {
89             get
90             {
91                 return this.defaultMaskingMode;
92             }
93         }
94
95         public TimeSpan DefaultSendTimeout
96         {
97             get
98             {
99                 return this.defaultSendTimeout;
100             }
101         }
102
103         public abstract bool HasSession
104         {
105             get;
106         }
107
108         public abstract EndpointAddress LocalAddress
109         {
110             get;
111         }
112
113         protected abstract bool MustCloseChannel
114         {
115             get;
116         }
117
118         protected abstract bool MustOpenChannel
119         {
120             get;
121         }
122
123         public abstract EndpointAddress RemoteAddress
124         {
125             get;
126         }
127
128         public CommunicationState State
129         {
130             get
131             {
132                 return this.state;
133             }
134         }
135
136         protected ChannelSynchronizer Synchronizer
137         {
138             get
139             {
140                 return this.synchronizer;
141             }
142         }
143
144         protected object ThisLock
145         {
146             get
147             {
148                 return this.thisLock;
149             }
150         }
151
152         bool TolerateFaults
153         {
154             get
155             {
156                 return this.synchronizer.TolerateFaults;
157             }
158         }
159
160         public event EventHandler ConnectionLost;
161         public event BinderExceptionHandler Faulted;
162         public event BinderExceptionHandler OnException;
163
164
165         public void Abort()
166         {
167             TChannel channel;
168             lock (this.ThisLock)
169             {
170                 this.aborted = true;
171
172                 if (this.state == CommunicationState.Closed)
173                 {
174                     return;
175                 }
176
177                 this.state = CommunicationState.Closing;
178                 channel = this.synchronizer.StopSynchronizing(true);
179
180                 if (!this.MustCloseChannel)
181                 {
182                     channel = null;
183                 }
184             }
185
186             this.synchronizer.UnblockWaiters();
187             this.OnShutdown();
188             this.OnAbort();
189
190             if (channel != null)
191             {
192                 channel.Abort();
193             }
194
195             this.TransitionToClosed();
196         }
197
198         protected virtual void AddOutputHeaders(Message message)
199         {
200         }
201
202         public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback,
203             object state)
204         {
205             return this.BeginClose(timeout, this.defaultMaskingMode, callback, state);
206         }
207
208         public IAsyncResult BeginClose(TimeSpan timeout, MaskingMode maskingMode,
209             AsyncCallback callback, object state)
210         {
211             this.ThrowIfTimeoutNegative(timeout);
212             TChannel channel;
213
214             if (this.CloseCore(out channel))
215             {
216                 return new CompletedAsyncResult(callback, state);
217             }
218             else
219             {
220                 return new CloseAsyncResult(this, channel, timeout, maskingMode, callback, state);
221             }
222         }
223
224         protected virtual IAsyncResult BeginCloseChannel(TChannel channel, TimeSpan timeout,
225             AsyncCallback callback, object state)
226         {
227             return channel.BeginClose(timeout, callback, state);
228         }
229
230         public IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
231         {
232             this.ThrowIfTimeoutNegative(timeout);
233
234             if (this.OnOpening(this.defaultMaskingMode))
235             {
236                 try
237                 {
238                     return this.OnBeginOpen(timeout, callback, state);
239                 }
240                 catch (Exception e)
241                 {
242                     if (Fx.IsFatal(e))
243                     {
244                         throw;
245                     }
246
247                     this.Fault(null);
248
249                     if (this.defaultMaskingMode == MaskingMode.None)
250                     {
251                         throw;
252                     }
253                     else
254                     {
255                         this.RaiseOnException(e);
256                     }
257                 }
258             }
259
260             return new BinderCompletedAsyncResult(callback, state);
261         }
262
263         public IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback,
264             object state)
265         {
266             return this.BeginSend(message, timeout, this.defaultMaskingMode, callback, state);
267         }
268
269         public IAsyncResult BeginSend(Message message, TimeSpan timeout, MaskingMode maskingMode,
270             AsyncCallback callback, object state)
271         {
272             SendAsyncResult result = new SendAsyncResult(this, callback, state);
273             result.Start(message, timeout, maskingMode);
274             return result;
275         }
276
277         // ChannelSynchronizer helper, cannot take a lock.
278         protected abstract IAsyncResult BeginTryGetChannel(TimeSpan timeout,
279             AsyncCallback callback, object state);
280
281         public virtual IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback,
282             object state)
283         {
284             return this.BeginTryReceive(timeout, this.defaultMaskingMode, callback, state);
285         }
286
287         public virtual IAsyncResult BeginTryReceive(TimeSpan timeout, MaskingMode maskingMode,
288             AsyncCallback callback, object state)
289         {
290             if (this.ValidateInputOperation(timeout))
291                 return new TryReceiveAsyncResult(this, timeout, maskingMode, callback, state);
292             else
293                 return new CompletedAsyncResult(callback, state);
294         }
295
296         internal IAsyncResult BeginWaitForPendingOperations(TimeSpan timeout,
297             AsyncCallback callback, object state)
298         {
299             return this.synchronizer.BeginWaitForPendingOperations(timeout, callback, state);
300         }
301
302         bool CloseCore(out TChannel channel)
303         {
304             channel = null;
305             bool abort = true;
306             bool abortChannel = false;
307
308             lock (this.ThisLock)
309             {
310                 if ((this.state == CommunicationState.Closing)
311                     || (this.state == CommunicationState.Closed))
312                 {
313                     return true;
314                 }
315
316                 if (this.state == CommunicationState.Opened)
317                 {
318                     this.state = CommunicationState.Closing;
319                     channel = this.synchronizer.StopSynchronizing(true);
320                     abort = false;
321
322                     if (!this.MustCloseChannel)
323                     {
324                         channel = null;
325                     }
326
327                     if (channel != null)
328                     {
329                         CommunicationState channelState = channel.State;
330
331                         if ((channelState == CommunicationState.Created)
332                             || (channelState == CommunicationState.Opening)
333                             || (channelState == CommunicationState.Faulted))
334                         {
335                             abortChannel = true;
336                         }
337                         else if ((channelState == CommunicationState.Closing)
338                             || (channelState == CommunicationState.Closed))
339                         {
340                             channel = null;
341                         }
342                     }
343                 }
344             }
345
346             this.synchronizer.UnblockWaiters();
347
348             if (abort)
349             {
350                 this.Abort();
351                 return true;
352             }
353             else
354             {
355                 if (abortChannel)
356                 {
357                     channel.Abort();
358                     channel = null;
359                 }
360
361                 return false;
362             }
363         }
364
365         public void Close(TimeSpan timeout)
366         {
367             this.Close(timeout, this.defaultMaskingMode);
368         }
369
370         public void Close(TimeSpan timeout, MaskingMode maskingMode)
371         {
372             this.ThrowIfTimeoutNegative(timeout);
373             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
374             TChannel channel;
375
376             if (this.CloseCore(out channel))
377             {
378                 return;
379             }
380
381             try
382             {
383                 this.OnShutdown();
384                 this.OnClose(timeoutHelper.RemainingTime());
385
386                 if (channel != null)
387                 {
388                     this.CloseChannel(channel, timeoutHelper.RemainingTime());
389                 }
390
391                 this.TransitionToClosed();
392             }
393             catch (Exception e)
394             {
395                 if (Fx.IsFatal(e))
396                 {
397                     throw;
398                 }
399
400                 this.Abort();
401
402                 if (!this.HandleException(e, maskingMode))
403                 {
404                     throw;
405                 }
406             }
407         }
408
409         // The ChannelSynchronizer calls this from an operation thread so this method must not
410         // block.
411         void CloseChannel(TChannel channel)
412         {
413             if (!this.MustCloseChannel)
414             {
415                 throw Fx.AssertAndThrow("MustCloseChannel is false when there is no receive loop and this method is called when there is a receive loop.");
416             }
417
418             if (this.onCloseChannelComplete == null)
419             {
420                 this.onCloseChannelComplete = Fx.ThunkCallback(new AsyncCallback(this.OnCloseChannelComplete));
421             }
422
423             try
424             {
425                 IAsyncResult result = channel.BeginClose(onCloseChannelComplete, channel);
426
427                 if (result.CompletedSynchronously)
428                 {
429                     channel.EndClose(result);
430                 }
431             }
432 #pragma warning suppress 56500 // covered by FxCOP
433             catch (Exception e)
434             {
435                 if (Fx.IsFatal(e))
436                 {
437                     throw;
438                 }
439
440                 this.HandleException(e, MaskingMode.All);
441             }
442         }
443
444         protected virtual void CloseChannel(TChannel channel, TimeSpan timeout)
445         {
446             channel.Close(timeout);
447         }
448
449         public void EndClose(IAsyncResult result)
450         {
451             CloseAsyncResult closeResult = result as CloseAsyncResult;
452
453             if (closeResult != null)
454             {
455                 closeResult.End();
456             }
457             else
458             {
459                 CompletedAsyncResult.End(result);
460             }
461         }
462
463         protected virtual void EndCloseChannel(TChannel channel, IAsyncResult result)
464         {
465             channel.EndClose(result);
466         }
467
468         public void EndOpen(IAsyncResult result)
469         {
470             BinderCompletedAsyncResult completedResult = result as BinderCompletedAsyncResult;
471
472             if (completedResult != null)
473             {
474                 completedResult.End();
475             }
476             else
477             {
478                 try
479                 {
480                     this.OnEndOpen(result);
481                 }
482                 catch (Exception e)
483                 {
484                     if (Fx.IsFatal(e))
485                     {
486                         throw;
487                     }
488
489                     this.Fault(null);
490
491                     if (this.defaultMaskingMode == MaskingMode.None)
492                     {
493                         throw;
494                     }
495                     else
496                     {
497                         this.RaiseOnException(e);
498                         return;
499                     }
500                 }
501
502                 this.synchronizer.StartSynchronizing();
503                 this.OnOpened();
504             }
505         }
506
507         public void EndSend(IAsyncResult result)
508         {
509             SendAsyncResult.End(result);
510         }
511
512         // ChannelSynchronizer helper, cannot take a lock.
513         protected abstract bool EndTryGetChannel(IAsyncResult result);
514
515         public virtual bool EndTryReceive(IAsyncResult result, out RequestContext requestContext)
516         {
517             TryReceiveAsyncResult tryReceiveResult = result as TryReceiveAsyncResult;
518
519             if (tryReceiveResult != null)
520             {
521                 return tryReceiveResult.End(out requestContext);
522             }
523             else
524             {
525                 CompletedAsyncResult.End(result);
526                 requestContext = null;
527                 return true;
528             }
529         }
530
531         public void EndWaitForPendingOperations(IAsyncResult result)
532         {
533             this.synchronizer.EndWaitForPendingOperations(result);
534         }
535
536         protected void Fault(Exception e)
537         {
538             lock (this.ThisLock)
539             {
540                 if (this.state == CommunicationState.Created)
541                 {
542                     throw Fx.AssertAndThrow("The binder should not detect the inner channel's faults until after the binder is opened.");
543                 }
544
545                 if ((this.state == CommunicationState.Faulted)
546                     || (this.state == CommunicationState.Closed))
547                 {
548                     return;
549                 }
550
551                 this.state = CommunicationState.Faulted;
552                 this.synchronizer.StopSynchronizing(false);
553             }
554
555             this.synchronizer.UnblockWaiters();
556
557             BinderExceptionHandler handler = this.Faulted;
558
559             if (handler != null)
560             {
561                 handler(this, e);
562             }
563         }
564
565         // ChannelSynchronizer helper, cannot take a lock.
566         Exception GetClosedException(MaskingMode maskingMode)
567         {
568             if (ReliableChannelBinderHelper.MaskHandled(maskingMode))
569             {
570                 return null;
571             }
572             else if (this.aborted)
573             {
574                 return new CommunicationObjectAbortedException(SR.GetString(
575                     SR.CommunicationObjectAborted1, this.GetType().ToString()));
576             }
577             else
578             {
579                 return new ObjectDisposedException(this.GetType().ToString());
580             }
581         }
582
583         // Must be called within lock (this.ThisLock)
584         Exception GetClosedOrFaultedException(MaskingMode maskingMode)
585         {
586             if (this.state == CommunicationState.Faulted)
587             {
588                 return this.GetFaultedException(maskingMode);
589             }
590             else if ((this.state == CommunicationState.Closing)
591                || (this.state == CommunicationState.Closed))
592             {
593                 return this.GetClosedException(maskingMode);
594             }
595             else
596             {
597                 throw Fx.AssertAndThrow("Caller is attempting to get a terminal exception in a non-terminal state.");
598             }
599         }
600
601         // ChannelSynchronizer helper, cannot take a lock.
602         Exception GetFaultedException(MaskingMode maskingMode)
603         {
604             if (ReliableChannelBinderHelper.MaskHandled(maskingMode))
605             {
606                 return null;
607             }
608             else
609             {
610                 return new CommunicationObjectFaultedException(SR.GetString(
611                     SR.CommunicationObjectFaulted1, this.GetType().ToString()));
612             }
613         }
614
615         public abstract ISession GetInnerSession();
616
617         public void HandleException(Exception e)
618         {
619             this.HandleException(e, MaskingMode.All);
620         }
621
622         protected bool HandleException(Exception e, MaskingMode maskingMode)
623         {
624             if (this.TolerateFaults && (e is CommunicationObjectFaultedException))
625             {
626                 return true;
627             }
628
629             if (this.IsHandleable(e))
630             {
631                 return ReliableChannelBinderHelper.MaskHandled(maskingMode);
632             }
633
634             bool maskUnhandled = ReliableChannelBinderHelper.MaskUnhandled(maskingMode);
635
636             if (maskUnhandled)
637             {
638                 this.RaiseOnException(e);
639             }
640
641             return maskUnhandled;
642         }
643
644         protected bool HandleException(Exception e, MaskingMode maskingMode, bool autoAborted)
645         {
646             if (this.TolerateFaults && autoAborted && e is CommunicationObjectAbortedException)
647             {
648                 return true;
649             }
650
651             return this.HandleException(e, maskingMode);
652         }
653
654         // ChannelSynchronizer helper, cannot take a lock.
655         protected abstract bool HasSecuritySession(TChannel channel);
656
657         public bool IsHandleable(Exception e)
658         {
659             if (e is ProtocolException)
660             {
661                 return false;
662             }
663
664             return (e is CommunicationException)
665                 || (e is TimeoutException);
666         }
667
668         protected abstract void OnAbort();
669         protected abstract IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback,
670             object state);
671         protected abstract IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback,
672             object state);
673
674         protected virtual IAsyncResult OnBeginSend(TChannel channel, Message message,
675             TimeSpan timeout, AsyncCallback callback, object state)
676         {
677             throw Fx.AssertAndThrow("The derived class does not support the BeginSend operation.");
678         }
679
680         protected virtual IAsyncResult OnBeginTryReceive(TChannel channel, TimeSpan timeout,
681             AsyncCallback callback, object state)
682         {
683             throw Fx.AssertAndThrow("The derived class does not support the BeginTryReceive operation.");
684         }
685
686         protected abstract void OnClose(TimeSpan timeout);
687
688         void OnCloseChannelComplete(IAsyncResult result)
689         {
690             if (result.CompletedSynchronously)
691             {
692                 return;
693             }
694
695             TChannel channel = (TChannel)result.AsyncState;
696
697             try
698             {
699                 channel.EndClose(result);
700             }
701 #pragma warning suppress 56500 // covered by FxCOP
702             catch (Exception e)
703             {
704                 if (Fx.IsFatal(e))
705                 {
706                     throw;
707                 }
708
709                 this.HandleException(e, MaskingMode.All);
710             }
711         }
712
713         protected abstract void OnEndClose(IAsyncResult result);
714         protected abstract void OnEndOpen(IAsyncResult result);
715
716         protected virtual void OnEndSend(TChannel channel, IAsyncResult result)
717         {
718             throw Fx.AssertAndThrow("The derived class does not support the EndSend operation.");
719         }
720
721         protected virtual bool OnEndTryReceive(TChannel channel, IAsyncResult result,
722             out RequestContext requestContext)
723         {
724             throw Fx.AssertAndThrow("The derived class does not support the EndTryReceive operation.");
725         }
726
727         void OnInnerChannelFaulted()
728         {
729             if (!this.TolerateFaults)
730                 return;
731
732             EventHandler handler = this.ConnectionLost;
733
734             if (handler != null)
735                 handler(this, EventArgs.Empty);
736         }
737
738         protected abstract void OnOpen(TimeSpan timeout);
739
740         void OnOpened()
741         {
742             lock (this.ThisLock)
743             {
744                 if (this.state == CommunicationState.Opening)
745                 {
746                     this.state = CommunicationState.Opened;
747                 }
748             }
749         }
750
751         bool OnOpening(MaskingMode maskingMode)
752         {
753             lock (this.ThisLock)
754             {
755                 if (this.state != CommunicationState.Created)
756                 {
757                     Exception e = null;
758
759                     if ((this.state == CommunicationState.Opening)
760                         || (this.state == CommunicationState.Opened))
761                     {
762                         if (!ReliableChannelBinderHelper.MaskUnhandled(maskingMode))
763                         {
764                             e = new InvalidOperationException(SR.GetString(
765                                 SR.CommunicationObjectCannotBeModifiedInState,
766                                 this.GetType().ToString(), this.state.ToString()));
767                         }
768                     }
769                     else
770                     {
771                         e = this.GetClosedOrFaultedException(maskingMode);
772                     }
773
774                     if (e != null)
775                     {
776                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e);
777                     }
778
779                     return false;
780                 }
781                 else
782                 {
783                     this.state = CommunicationState.Opening;
784                     return true;
785                 }
786             }
787         }
788
789         protected virtual void OnShutdown()
790         {
791         }
792
793         protected virtual void OnSend(TChannel channel, Message message, TimeSpan timeout)
794         {
795             throw Fx.AssertAndThrow("The derived class does not support the Send operation.");
796         }
797
798         protected virtual bool OnTryReceive(TChannel channel, TimeSpan timeout,
799             out RequestContext requestContext)
800         {
801             throw Fx.AssertAndThrow("The derived class does not support the TryReceive operation.");
802         }
803
804         public void Open(TimeSpan timeout)
805         {
806             this.ThrowIfTimeoutNegative(timeout);
807
808             if (!this.OnOpening(this.defaultMaskingMode))
809             {
810                 return;
811             }
812
813             try
814             {
815                 this.OnOpen(timeout);
816             }
817             catch (Exception e)
818             {
819                 if (Fx.IsFatal(e))
820                 {
821                     throw;
822                 }
823
824                 this.Fault(null);
825
826                 if (this.defaultMaskingMode == MaskingMode.None)
827                 {
828                     throw;
829                 }
830                 else
831                 {
832                     this.RaiseOnException(e);
833                     return;
834                 }
835             }
836
837             this.synchronizer.StartSynchronizing();
838             this.OnOpened();
839         }
840
841         void RaiseOnException(Exception e)
842         {
843             BinderExceptionHandler handler = this.OnException;
844
845             if (handler != null)
846             {
847                 handler(this, e);
848             }
849         }
850
851         public void Send(Message message, TimeSpan timeout)
852         {
853             this.Send(message, timeout, this.defaultMaskingMode);
854         }
855
856         public void Send(Message message, TimeSpan timeout, MaskingMode maskingMode)
857         {
858             if (!this.ValidateOutputOperation(message, timeout, maskingMode))
859             {
860                 return;
861             }
862
863             bool autoAborted = false;
864
865             try
866             {
867                 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
868                 TChannel channel;
869
870                 if (!this.synchronizer.TryGetChannelForOutput(timeoutHelper.RemainingTime(), maskingMode,
871                     out channel))
872                 {
873                     if (!ReliableChannelBinderHelper.MaskHandled(maskingMode))
874                     {
875                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
876                             new TimeoutException(SR.GetString(SR.TimeoutOnSend, timeout)));
877                     }
878
879                     return;
880                 }
881
882                 if (channel == null)
883                 {
884                     return;
885                 }
886
887                 this.AddOutputHeaders(message);
888
889                 try
890                 {
891                     this.OnSend(channel, message, timeoutHelper.RemainingTime());
892                 }
893                 finally
894                 {
895                     autoAborted = this.Synchronizer.Aborting;
896                     this.synchronizer.ReturnChannel();
897                 }
898             }
899             catch (Exception e)
900             {
901                 if (Fx.IsFatal(e))
902                 {
903                     throw;
904                 }
905
906                 if (!this.HandleException(e, maskingMode, autoAborted))
907                 {
908                     throw;
909                 }
910             }
911         }
912
913         public void SetMaskingMode(RequestContext context, MaskingMode maskingMode)
914         {
915             BinderRequestContext binderContext = (BinderRequestContext)context;
916             binderContext.SetMaskingMode(maskingMode);
917         }
918
919         // throwDisposed indicates whether to throw in the Faulted, Closing, and Closed states.
920         // returns true if in Opened state
921         bool ThrowIfNotOpenedAndNotMasking(MaskingMode maskingMode, bool throwDisposed)
922         {
923             lock (this.ThisLock)
924             {
925                 if (this.State == CommunicationState.Created)
926                 {
927                     throw Fx.AssertAndThrow("Messaging operations cannot be called when the binder is in the Created state.");
928                 }
929
930                 if (this.State == CommunicationState.Opening)
931                 {
932                     throw Fx.AssertAndThrow("Messaging operations cannot be called when the binder is in the Opening state.");
933                 }
934
935                 if (this.State == CommunicationState.Opened)
936                 {
937                     return true;
938                 }
939
940                 // state is Faulted, Closing, or Closed
941                 if (throwDisposed)
942                 {
943                     Exception e = this.GetClosedOrFaultedException(maskingMode);
944
945                     if (e != null)
946                     {
947                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e);
948                     }
949                 }
950
951                 return false;
952             }
953         }
954
955         void ThrowIfTimeoutNegative(TimeSpan timeout)
956         {
957             if (timeout < TimeSpan.Zero)
958             {
959                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
960                     new ArgumentOutOfRangeException("timeout", timeout, SR.SFxTimeoutOutOfRange0));
961             }
962         }
963
964         void TransitionToClosed()
965         {
966             lock (this.ThisLock)
967             {
968                 if ((this.state != CommunicationState.Closing)
969                     && (this.state != CommunicationState.Closed)
970                     && (this.state != CommunicationState.Faulted))
971                 {
972                     throw Fx.AssertAndThrow("Caller cannot transition to the Closed state from a non-terminal state.");
973                 }
974
975                 this.state = CommunicationState.Closed;
976             }
977         }
978
979         // ChannelSynchronizer helper, cannot take a lock.
980         protected abstract bool TryGetChannel(TimeSpan timeout);
981
982         public virtual bool TryReceive(TimeSpan timeout, out RequestContext requestContext)
983         {
984             return this.TryReceive(timeout, out requestContext, this.defaultMaskingMode);
985         }
986
987         public virtual bool TryReceive(TimeSpan timeout, out RequestContext requestContext, MaskingMode maskingMode)
988         {
989             if (maskingMode != MaskingMode.None)
990             {
991                 throw Fx.AssertAndThrow("This method was implemented only for the case where we do not mask exceptions.");
992             }
993
994             if (!this.ValidateInputOperation(timeout))
995             {
996                 requestContext = null;
997                 return true;
998             }
999
1000             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1001
1002             while (true)
1003             {
1004                 bool autoAborted = false;
1005
1006                 try
1007                 {
1008                     TChannel channel;
1009                     bool success = !this.synchronizer.TryGetChannelForInput(
1010                         this.CanGetChannelForReceive, timeoutHelper.RemainingTime(), out channel);
1011
1012                     if (channel == null)
1013                     {
1014                         requestContext = null;
1015                         return success;
1016                     }
1017
1018                     try
1019                     {
1020                         success = this.OnTryReceive(channel, timeoutHelper.RemainingTime(),
1021                             out requestContext);
1022
1023                         // timed out || got message, return immediately
1024                         if (!success || (requestContext != null))
1025                         {
1026                             return success;
1027                         }
1028
1029                         // the underlying channel closed or faulted, retry
1030                         this.synchronizer.OnReadEof();
1031                     }
1032                     finally
1033                     {
1034                         autoAborted = this.Synchronizer.Aborting;
1035                         this.synchronizer.ReturnChannel();
1036                     }
1037                 }
1038                 catch (Exception e)
1039                 {
1040                     if (Fx.IsFatal(e))
1041                     {
1042                         throw;
1043                     }
1044
1045                     if (!this.HandleException(e, maskingMode, autoAborted))
1046                     {
1047                         throw;
1048                     }
1049                 }
1050             }
1051         }
1052
1053         protected bool ValidateInputOperation(TimeSpan timeout)
1054         {
1055             if (timeout < TimeSpan.Zero)
1056             {
1057                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("timeout", timeout,
1058                     SR.SFxTimeoutOutOfRange0));
1059             }
1060
1061             return this.ThrowIfNotOpenedAndNotMasking(MaskingMode.All, false);
1062         }
1063
1064         protected bool ValidateOutputOperation(Message message, TimeSpan timeout, MaskingMode maskingMode)
1065         {
1066             if (message == null)
1067             {
1068                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
1069             }
1070
1071             if (timeout < TimeSpan.Zero)
1072             {
1073                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("timeout", timeout,
1074                     SR.SFxTimeoutOutOfRange0));
1075             }
1076
1077             return this.ThrowIfNotOpenedAndNotMasking(maskingMode, true);
1078         }
1079
1080         internal void WaitForPendingOperations(TimeSpan timeout)
1081         {
1082             this.synchronizer.WaitForPendingOperations(timeout);
1083         }
1084
1085         protected RequestContext WrapMessage(Message message)
1086         {
1087             if (message == null)
1088             {
1089                 return null;
1090             }
1091
1092             return new MessageRequestContext(this, message);
1093         }
1094
1095         public RequestContext WrapRequestContext(RequestContext context)
1096         {
1097             if (context == null)
1098             {
1099                 return null;
1100             }
1101
1102             if (!this.TolerateFaults && this.defaultMaskingMode == MaskingMode.None)
1103             {
1104                 return context;
1105             }
1106
1107             return new RequestRequestContext(this, context, context.RequestMessage);
1108         }
1109
1110         sealed class BinderCompletedAsyncResult : CompletedAsyncResult
1111         {
1112             public BinderCompletedAsyncResult(AsyncCallback callback, object state)
1113                 : base(callback, state)
1114             {
1115             }
1116
1117             public void End()
1118             {
1119                 CompletedAsyncResult.End(this);
1120             }
1121         }
1122
1123         abstract class BinderRequestContext : RequestContextBase
1124         {
1125             ReliableChannelBinder<TChannel> binder;
1126             MaskingMode maskingMode;
1127
1128             public BinderRequestContext(ReliableChannelBinder<TChannel> binder, Message message)
1129                 : base(message, binder.defaultCloseTimeout, binder.defaultSendTimeout)
1130             {
1131                 if (binder == null)
1132                 {
1133                     Fx.Assert("Argument binder cannot be null.");
1134                 }
1135
1136                 this.binder = binder;
1137                 this.maskingMode = binder.defaultMaskingMode;
1138             }
1139
1140             protected ReliableChannelBinder<TChannel> Binder
1141             {
1142                 get
1143                 {
1144                     return this.binder;
1145                 }
1146             }
1147
1148             protected MaskingMode MaskingMode
1149             {
1150                 get
1151                 {
1152                     return this.maskingMode;
1153                 }
1154             }
1155
1156             public void SetMaskingMode(MaskingMode maskingMode)
1157             {
1158                 if (this.binder.defaultMaskingMode != MaskingMode.All)
1159                 {
1160                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
1161                 }
1162
1163                 this.maskingMode = maskingMode;
1164             }
1165         }
1166
1167         protected class ChannelSynchronizer
1168         {
1169             bool aborting; // Indicates the current channel is being aborted, not the synchronizer.
1170             ReliableChannelBinder<TChannel> binder;
1171             int count = 0;
1172             TChannel currentChannel;
1173             InterruptibleWaitObject drainEvent;
1174             static Action<object> asyncGetChannelCallback = new Action<object>(AsyncGetChannelCallback);
1175             TolerateFaultsMode faultMode;
1176             Queue<IWaiter> getChannelQueue;
1177             bool innerChannelFaulted;
1178             EventHandler onChannelFaulted;
1179             State state = State.Created;
1180             bool tolerateFaults = true;
1181             object thisLock = new object();
1182             Queue<IWaiter> waitQueue;
1183
1184             public ChannelSynchronizer(ReliableChannelBinder<TChannel> binder, TChannel channel,
1185                 TolerateFaultsMode faultMode)
1186             {
1187                 this.binder = binder;
1188                 this.currentChannel = channel;
1189                 this.faultMode = faultMode;
1190             }
1191
1192             public bool Aborting
1193             {
1194                 get
1195                 {
1196                     return this.aborting;
1197                 }
1198             }
1199
1200             public bool Connected
1201             {
1202                 get
1203                 {
1204                     return (this.state == State.ChannelOpened ||
1205                         this.state == State.ChannelOpening);
1206                 }
1207             }
1208
1209             public TChannel CurrentChannel
1210             {
1211                 get
1212                 {
1213                     return this.currentChannel;
1214                 }
1215             }
1216
1217             object ThisLock
1218             {
1219                 get
1220                 {
1221                     return this.thisLock;
1222                 }
1223             }
1224
1225             public bool TolerateFaults
1226             {
1227                 get
1228                 {
1229                     return this.tolerateFaults;
1230                 }
1231             }
1232
1233             // Server only API.
1234             public TChannel AbortCurentChannel()
1235             {
1236                 lock (this.ThisLock)
1237                 {
1238                     if (!this.tolerateFaults)
1239                     {
1240                         throw Fx.AssertAndThrow("It is only valid to abort the current channel when masking faults");
1241                     }
1242
1243                     if (this.state == State.ChannelOpening)
1244                     {
1245                         this.aborting = true;
1246                     }
1247                     else if (this.state == State.ChannelOpened)
1248                     {
1249                         if (this.count == 0)
1250                         {
1251                             this.state = State.NoChannel;
1252                         }
1253                         else
1254                         {
1255                             this.aborting = true;
1256                             this.state = State.ChannelClosing;
1257                         }
1258                     }
1259                     else
1260                     {
1261                         return null;
1262                     }
1263
1264                     return this.currentChannel;
1265                 }
1266             }
1267
1268             static void AsyncGetChannelCallback(object state)
1269             {
1270                 AsyncWaiter waiter = (AsyncWaiter)state;
1271                 waiter.GetChannel(false);
1272             }
1273
1274             public IAsyncResult BeginTryGetChannelForInput(bool canGetChannel, TimeSpan timeout,
1275                 AsyncCallback callback, object state)
1276             {
1277                 return this.BeginTryGetChannel(canGetChannel, false, timeout, MaskingMode.All,
1278                     callback, state);
1279             }
1280
1281             public IAsyncResult BeginTryGetChannelForOutput(TimeSpan timeout,
1282                 MaskingMode maskingMode, AsyncCallback callback, object state)
1283             {
1284                 return this.BeginTryGetChannel(true, true, timeout, maskingMode,
1285                     callback, state);
1286             }
1287
1288             IAsyncResult BeginTryGetChannel(bool canGetChannel, bool canCauseFault,
1289                 TimeSpan timeout, MaskingMode maskingMode, AsyncCallback callback, object state)
1290             {
1291                 TChannel channel = null;
1292                 AsyncWaiter waiter = null;
1293                 bool getChannel = false;
1294                 bool faulted = false;
1295
1296                 lock (this.ThisLock)
1297                 {
1298                     if (!this.ThrowIfNecessary(maskingMode))
1299                     {
1300                         channel = null;
1301                     }
1302                     else if (this.state == State.ChannelOpened)
1303                     {
1304                         if (this.currentChannel == null)
1305                         {
1306                             throw Fx.AssertAndThrow("Field currentChannel cannot be null in the ChannelOpened state.");
1307                         }
1308
1309                         this.count++;
1310                         channel = this.currentChannel;
1311                     }
1312                     else if (!this.tolerateFaults
1313                         && ((this.state == State.NoChannel)
1314                         || (this.state == State.ChannelClosing)))
1315                     {
1316                         if (canCauseFault)
1317                         {
1318                             faulted = true;
1319                         }
1320
1321                         channel = null;
1322                     }
1323                     else if (!canGetChannel
1324                         || (this.state == State.ChannelOpening)
1325                         || (this.state == State.ChannelClosing))
1326                     {
1327                         waiter = new AsyncWaiter(this, canGetChannel, null, timeout, maskingMode,
1328                             this.binder.ChannelParameters,
1329                             callback, state);
1330                         this.GetQueue(canGetChannel).Enqueue(waiter);
1331                     }
1332                     else
1333                     {
1334                         if (this.state != State.NoChannel)
1335                         {
1336                             throw Fx.AssertAndThrow("The state must be NoChannel.");
1337                         }
1338
1339                         waiter = new AsyncWaiter(this, canGetChannel,
1340                             this.GetCurrentChannelIfCreated(), timeout, maskingMode,
1341                             this.binder.ChannelParameters,
1342                             callback, state);
1343
1344                         this.state = State.ChannelOpening;
1345                         getChannel = true;
1346                     }
1347                 }
1348
1349                 if (faulted)
1350                 {
1351                     this.binder.Fault(null);
1352                 }
1353
1354                 if (waiter == null)
1355                 {
1356                     return new CompletedAsyncResult<TChannel>(channel, callback, state);
1357                 }
1358
1359                 if (getChannel)
1360                 {
1361                     waiter.GetChannel(true);
1362                 }
1363                 else
1364                 {
1365                     waiter.Wait();
1366                 }
1367
1368                 return waiter;
1369             }
1370
1371             public IAsyncResult BeginWaitForPendingOperations(TimeSpan timeout,
1372                 AsyncCallback callback, object state)
1373             {
1374                 lock (this.ThisLock)
1375                 {
1376                     if (this.drainEvent != null)
1377                     {
1378                         throw Fx.AssertAndThrow("The WaitForPendingOperations operation may only be invoked once.");
1379                     }
1380
1381                     if (this.count > 0)
1382                     {
1383                         this.drainEvent = new InterruptibleWaitObject(false, false);
1384                     }
1385                 }
1386
1387                 if (this.drainEvent != null)
1388                 {
1389                     return this.drainEvent.BeginWait(timeout, callback, state);
1390                 }
1391                 else
1392                 {
1393                     return new SynchronizerCompletedAsyncResult(callback, state);
1394                 }
1395             }
1396
1397             bool CompleteSetChannel(IWaiter waiter, out TChannel channel)
1398             {
1399                 if (waiter == null)
1400                 {
1401                     throw Fx.AssertAndThrow("Argument waiter cannot be null.");
1402                 }
1403
1404                 bool close = false;
1405
1406                 lock (this.ThisLock)
1407                 {
1408                     if (this.ValidateOpened())
1409                     {
1410                         channel = this.currentChannel;
1411                         return true;
1412                     }
1413                     else
1414                     {
1415                         channel = null;
1416                         close = this.state == State.Closed;
1417                     }
1418                 }
1419
1420                 if (close)
1421                 {
1422                     waiter.Close();
1423                 }
1424                 else
1425                 {
1426                     waiter.Fault();
1427                 }
1428
1429                 return false;
1430             }
1431
1432             public bool EndTryGetChannel(IAsyncResult result, out TChannel channel)
1433             {
1434                 AsyncWaiter waiter = result as AsyncWaiter;
1435
1436                 if (waiter != null)
1437                 {
1438                     return waiter.End(out channel);
1439                 }
1440                 else
1441                 {
1442                     channel = CompletedAsyncResult<TChannel>.End(result);
1443                     return true;
1444                 }
1445             }
1446
1447             public void EndWaitForPendingOperations(IAsyncResult result)
1448             {
1449                 SynchronizerCompletedAsyncResult completedResult =
1450                     result as SynchronizerCompletedAsyncResult;
1451
1452                 if (completedResult != null)
1453                 {
1454                     completedResult.End();
1455                 }
1456                 else
1457                 {
1458                     this.drainEvent.EndWait(result);
1459                 }
1460             }
1461
1462             // Client API only.
1463             public bool EnsureChannel()
1464             {
1465                 bool fault = false;
1466
1467                 lock (this.ThisLock)
1468                 {
1469                     if (this.ValidateOpened())
1470                     {
1471                         // This is called only during the RM CS phase. In this phase, there are 2
1472                         // valid states between Request calls, ChannelOpened and NoChannel.
1473                         if (this.state == State.ChannelOpened)
1474                         {
1475                             return true;
1476                         }
1477
1478                         if (this.state != State.NoChannel)
1479                         {
1480                             throw Fx.AssertAndThrow("The caller may only invoke this EnsureChannel during the CreateSequence negotiation. ChannelOpening and ChannelClosing are invalid states during this phase of the negotiation.");
1481                         }
1482
1483                         if (!this.tolerateFaults)
1484                         {
1485                             fault = true;
1486                         }
1487                         else
1488                         {
1489                             if (this.GetCurrentChannelIfCreated() != null)
1490                             {
1491                                 return true;
1492                             }
1493
1494                             if (this.binder.TryGetChannel(TimeSpan.Zero))
1495                             {
1496                                 if (this.currentChannel == null)
1497                                 {
1498                                     return false;
1499                                 }
1500
1501                                 return true;
1502                             }
1503                         }
1504                     }
1505                 }
1506
1507                 if (fault)
1508                 {
1509                     this.binder.Fault(null);
1510                 }
1511
1512                 return false;
1513             }
1514
1515             IWaiter GetChannelWaiter()
1516             {
1517                 if ((this.getChannelQueue == null) || (this.getChannelQueue.Count == 0))
1518                 {
1519                     return null;
1520                 }
1521
1522                 return this.getChannelQueue.Dequeue();
1523             }
1524
1525             // Must be called within lock (this.ThisLock)
1526             TChannel GetCurrentChannelIfCreated()
1527             {
1528                 if (this.state != State.NoChannel)
1529                 {
1530                     throw Fx.AssertAndThrow("This method may only be called in the NoChannel state.");
1531                 }
1532
1533                 if ((this.currentChannel != null)
1534                     && (this.currentChannel.State == CommunicationState.Created))
1535                 {
1536                     return this.currentChannel;
1537                 }
1538                 else
1539                 {
1540                     return null;
1541                 }
1542             }
1543
1544             Queue<IWaiter> GetQueue(bool canGetChannel)
1545             {
1546                 if (canGetChannel)
1547                 {
1548                     if (this.getChannelQueue == null)
1549                     {
1550                         this.getChannelQueue = new Queue<IWaiter>();
1551                     }
1552
1553                     return this.getChannelQueue;
1554                 }
1555                 else
1556                 {
1557                     if (this.waitQueue == null)
1558                     {
1559                         this.waitQueue = new Queue<IWaiter>();
1560                     }
1561
1562                     return this.waitQueue;
1563                 }
1564             }
1565
1566             void OnChannelFaulted(object sender, EventArgs e)
1567             {
1568                 TChannel faultedChannel = (TChannel)sender;
1569                 bool faultBinder = false;
1570                 bool raiseInnerChannelFaulted = false;
1571
1572                 lock (this.ThisLock)
1573                 {
1574                     if (this.currentChannel != faultedChannel)
1575                     {
1576                         return;
1577                     }
1578
1579                     // The synchronizer is already closed or aborted.
1580                     if (!this.ValidateOpened())
1581                     {
1582                         return;
1583                     }
1584
1585                     if (this.state == State.ChannelOpened)
1586                     {
1587                         if (this.count == 0)
1588                         {
1589                             faultedChannel.Faulted -= this.onChannelFaulted;
1590                         }
1591
1592                         faultBinder = !this.tolerateFaults;
1593                         this.state = State.ChannelClosing;
1594                         this.innerChannelFaulted = true;
1595
1596                         if (!faultBinder && this.count == 0)
1597                         {
1598                             this.state = State.NoChannel;
1599                             this.aborting = false;
1600                             raiseInnerChannelFaulted = true;
1601                             this.innerChannelFaulted = false;
1602                         }
1603                     }
1604                 }
1605
1606                 if (faultBinder)
1607                 {
1608                     this.binder.Fault(null);
1609                 }
1610
1611                 faultedChannel.Abort();
1612
1613                 if (raiseInnerChannelFaulted)
1614                 {
1615                     this.binder.OnInnerChannelFaulted();
1616                 }
1617             }
1618
1619             bool OnChannelOpened(IWaiter waiter)
1620             {
1621                 if (waiter == null)
1622                 {
1623                     throw Fx.AssertAndThrow("Argument waiter cannot be null.");
1624                 }
1625
1626                 bool close = false;
1627                 bool fault = false;
1628
1629                 Queue<IWaiter> temp1 = null;
1630                 Queue<IWaiter> temp2 = null;
1631                 TChannel channel = null;
1632
1633                 lock (this.ThisLock)
1634                 {
1635                     if (this.currentChannel == null)
1636                     {
1637                         throw Fx.AssertAndThrow("Caller must ensure that field currentChannel is set before opening the channel.");
1638                     }
1639
1640                     if (this.ValidateOpened())
1641                     {
1642                         if (this.state != State.ChannelOpening)
1643                         {
1644                             throw Fx.AssertAndThrow("This method may only be called in the ChannelOpening state.");
1645                         }
1646
1647                         this.state = State.ChannelOpened;
1648                         this.SetTolerateFaults();
1649
1650                         this.count += 1;
1651                         this.count += (this.getChannelQueue == null) ? 0 : this.getChannelQueue.Count;
1652                         this.count += (this.waitQueue == null) ? 0 : this.waitQueue.Count;
1653
1654                         temp1 = this.getChannelQueue;
1655                         temp2 = this.waitQueue;
1656                         channel = this.currentChannel;
1657
1658                         this.getChannelQueue = null;
1659                         this.waitQueue = null;
1660                     }
1661                     else
1662                     {
1663                         close = this.state == State.Closed;
1664                         fault = this.state == State.Faulted;
1665                     }
1666                 }
1667
1668                 if (close)
1669                 {
1670                     waiter.Close();
1671                     return false;
1672                 }
1673                 else if (fault)
1674                 {
1675                     waiter.Fault();
1676                     return false;
1677                 }
1678
1679                 this.SetWaiters(temp1, channel);
1680                 this.SetWaiters(temp2, channel);
1681                 return true;
1682             }
1683
1684             void OnGetChannelFailed()
1685             {
1686                 IWaiter waiter = null;
1687
1688                 lock (this.ThisLock)
1689                 {
1690                     if (!this.ValidateOpened())
1691                     {
1692                         return;
1693                     }
1694
1695                     if (this.state != State.ChannelOpening)
1696                     {
1697                         throw Fx.AssertAndThrow("The state must be set to ChannelOpening before the caller attempts to open the channel.");
1698                     }
1699
1700                     waiter = this.GetChannelWaiter();
1701
1702                     if (waiter == null)
1703                     {
1704                         this.state = State.NoChannel;
1705                         return;
1706                     }
1707                 }
1708
1709                 if (waiter is SyncWaiter)
1710                 {
1711                     waiter.GetChannel(false);
1712                 }
1713                 else
1714                 {
1715                     ActionItem.Schedule(asyncGetChannelCallback, waiter);
1716                 }
1717             }
1718
1719             public void OnReadEof()
1720             {
1721                 lock (this.ThisLock)
1722                 {
1723                     if (this.count <= 0)
1724                     {
1725                         throw Fx.AssertAndThrow("Caller must ensure that OnReadEof is called before ReturnChannel.");
1726                     }
1727
1728                     if (this.ValidateOpened())
1729                     {
1730                         if ((this.state != State.ChannelOpened) && (this.state != State.ChannelClosing))
1731                         {
1732                             throw Fx.AssertAndThrow("Since count is positive, the only valid states are ChannelOpened and ChannelClosing.");
1733                         }
1734
1735                         if (this.currentChannel.State != CommunicationState.Faulted)
1736                         {
1737                             this.state = State.ChannelClosing;
1738                         }
1739                     }
1740                 }
1741             }
1742
1743             bool RemoveWaiter(IWaiter waiter)
1744             {
1745                 Queue<IWaiter> waiters = waiter.CanGetChannel ? this.getChannelQueue : this.waitQueue;
1746
1747                 if (waiters == null)
1748                 {
1749                     return false;
1750                 }
1751
1752                 bool removed = false;
1753
1754                 lock (this.ThisLock)
1755                 {
1756                     if (!this.ValidateOpened())
1757                     {
1758                         return false;
1759                     }
1760
1761                     for (int i = waiters.Count; i > 0; i--)
1762                     {
1763                         IWaiter temp = waiters.Dequeue();
1764
1765                         if (object.ReferenceEquals(waiter, temp))
1766                         {
1767                             removed = true;
1768                         }
1769                         else
1770                         {
1771                             waiters.Enqueue(temp);
1772                         }
1773                     }
1774                 }
1775
1776                 return removed;
1777             }
1778
1779             public void ReturnChannel()
1780             {
1781                 TChannel channel = null;
1782                 IWaiter waiter = null;
1783                 bool faultBinder = false;
1784                 bool drained;
1785                 bool raiseInnerChannelFaulted = false;
1786
1787                 lock (this.ThisLock)
1788                 {
1789                     if (this.count <= 0)
1790                     {
1791                         throw Fx.AssertAndThrow("Method ReturnChannel() can only be called after TryGetChannel or EndTryGetChannel returns a channel.");
1792                     }
1793
1794                     this.count--;
1795                     drained = (this.count == 0) && (this.drainEvent != null);
1796
1797                     if (this.ValidateOpened())
1798                     {
1799                         if ((this.state != State.ChannelOpened) && (this.state != State.ChannelClosing))
1800                         {
1801                             throw Fx.AssertAndThrow("ChannelOpened and ChannelClosing are the only 2 valid states when count is positive.");
1802                         }
1803
1804                         if (this.currentChannel.State == CommunicationState.Faulted)
1805                         {
1806                             faultBinder = !this.tolerateFaults;
1807                             this.innerChannelFaulted = true;
1808                             this.state = State.ChannelClosing;
1809                         }
1810
1811                         if (!faultBinder && (this.state == State.ChannelClosing) && (this.count == 0))
1812                         {
1813                             channel = this.currentChannel;
1814                             raiseInnerChannelFaulted = this.innerChannelFaulted;
1815                             this.innerChannelFaulted = false;
1816
1817                             this.state = State.NoChannel;
1818                             this.aborting = false;
1819
1820                             waiter = this.GetChannelWaiter();
1821
1822                             if (waiter != null)
1823                             {
1824                                 this.state = State.ChannelOpening;
1825                             }
1826                         }
1827                     }
1828                 }
1829
1830                 if (faultBinder)
1831                 {
1832                     this.binder.Fault(null);
1833                 }
1834
1835                 if (drained)
1836                 {
1837                     this.drainEvent.Set();
1838                 }
1839
1840                 if (channel != null)
1841                 {
1842                     channel.Faulted -= this.onChannelFaulted;
1843
1844                     if (channel.State == CommunicationState.Opened)
1845                     {
1846                         this.binder.CloseChannel(channel);
1847                     }
1848                     else
1849                     {
1850                         channel.Abort();
1851                     }
1852
1853                     if (waiter != null)
1854                     {
1855                         waiter.GetChannel(false);
1856                     }
1857                 }
1858
1859                 if (raiseInnerChannelFaulted)
1860                 {
1861                     this.binder.OnInnerChannelFaulted();
1862                 }
1863             }
1864
1865             public bool SetChannel(TChannel channel)
1866             {
1867                 lock (this.ThisLock)
1868                 {
1869                     if (this.state != State.ChannelOpening && this.state != State.NoChannel)
1870                     {
1871                         throw Fx.AssertAndThrow("SetChannel is only valid in the NoChannel and ChannelOpening states");
1872                     }
1873
1874                     if (!this.tolerateFaults)
1875                     {
1876                         throw Fx.AssertAndThrow("SetChannel is only valid when masking faults");
1877                     }
1878
1879                     if (this.ValidateOpened())
1880                     {
1881                         this.currentChannel = channel;
1882                         return true;
1883                     }
1884                     else
1885                     {
1886                         return false;
1887                     }
1888                 }
1889             }
1890
1891             void SetTolerateFaults()
1892             {
1893                 if (this.faultMode == TolerateFaultsMode.Never)
1894                 {
1895                     this.tolerateFaults = false;
1896                 }
1897                 else if (this.faultMode == TolerateFaultsMode.IfNotSecuritySession)
1898                 {
1899                     this.tolerateFaults = !this.binder.HasSecuritySession(this.currentChannel);
1900                 }
1901
1902                 if (this.onChannelFaulted == null)
1903                 {
1904                     this.onChannelFaulted = new EventHandler(this.OnChannelFaulted);
1905                 }
1906
1907                 this.currentChannel.Faulted += this.onChannelFaulted;
1908             }
1909
1910             void SetWaiters(Queue<IWaiter> waiters, TChannel channel)
1911             {
1912                 if ((waiters != null) && (waiters.Count > 0))
1913                 {
1914                     foreach (IWaiter waiter in waiters)
1915                     {
1916                         waiter.Set(channel);
1917                     }
1918                 }
1919             }
1920
1921             public void StartSynchronizing()
1922             {
1923                 lock (this.ThisLock)
1924                 {
1925                     if (this.state == State.Created)
1926                     {
1927                         this.state = State.NoChannel;
1928                     }
1929                     else
1930                     {
1931                         if (this.state != State.Closed)
1932                         {
1933                             throw Fx.AssertAndThrow("Abort is the only operation that can ---- with Open.");
1934                         }
1935
1936                         return;
1937                     }
1938
1939                     if (this.currentChannel == null)
1940                     {
1941                         if (!this.binder.TryGetChannel(TimeSpan.Zero))
1942                         {
1943                             return;
1944                         }
1945                     }
1946
1947                     if (this.currentChannel == null)
1948                     {
1949                         return;
1950                     }
1951
1952                     if (!this.binder.MustOpenChannel)
1953                     {
1954                         // Channel is already opened.
1955                         this.state = State.ChannelOpened;
1956                         this.SetTolerateFaults();
1957                     }
1958                 }
1959             }
1960
1961             public TChannel StopSynchronizing(bool close)
1962             {
1963                 lock (this.ThisLock)
1964                 {
1965                     if ((this.state != State.Faulted) && (this.state != State.Closed))
1966                     {
1967                         this.state = close ? State.Closed : State.Faulted;
1968
1969                         if ((this.currentChannel != null) && (this.onChannelFaulted != null))
1970                         {
1971                             this.currentChannel.Faulted -= this.onChannelFaulted;
1972                         }
1973                     }
1974
1975                     return this.currentChannel;
1976                 }
1977             }
1978
1979             // Must be called under a lock.
1980             bool ThrowIfNecessary(MaskingMode maskingMode)
1981             {
1982                 if (this.ValidateOpened())
1983                 {
1984                     return true;
1985                 }
1986
1987                 // state is Closed or Faulted.
1988                 Exception e;
1989
1990                 if (this.state == State.Closed)
1991                 {
1992                     e = this.binder.GetClosedException(maskingMode);
1993                 }
1994                 else
1995                 {
1996                     e = this.binder.GetFaultedException(maskingMode);
1997                 }
1998
1999                 if (e != null)
2000                 {
2001                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e);
2002                 }
2003
2004                 return false;
2005             }
2006
2007             public bool TryGetChannelForInput(bool canGetChannel, TimeSpan timeout,
2008                 out TChannel channel)
2009             {
2010                 return this.TryGetChannel(canGetChannel, false, timeout, MaskingMode.All,
2011                     out channel);
2012             }
2013
2014             public bool TryGetChannelForOutput(TimeSpan timeout, MaskingMode maskingMode,
2015                 out TChannel channel)
2016             {
2017                 return this.TryGetChannel(true, true, timeout, maskingMode, out channel);
2018             }
2019
2020             bool TryGetChannel(bool canGetChannel, bool canCauseFault, TimeSpan timeout,
2021                 MaskingMode maskingMode, out TChannel channel)
2022             {
2023                 SyncWaiter waiter = null;
2024                 bool faulted = false;
2025                 bool getChannel = false;
2026
2027                 lock (this.ThisLock)
2028                 {
2029                     if (!this.ThrowIfNecessary(maskingMode))
2030                     {
2031                         channel = null;
2032                         return true;
2033                     }
2034
2035                     if (this.state == State.ChannelOpened)
2036                     {
2037                         if (this.currentChannel == null)
2038                         {
2039                             throw Fx.AssertAndThrow("Field currentChannel cannot be null in the ChannelOpened state.");
2040                         }
2041
2042                         this.count++;
2043                         channel = this.currentChannel;
2044                         return true;
2045                     }
2046
2047                     if (!this.tolerateFaults
2048                         && ((this.state == State.ChannelClosing)
2049                         || (this.state == State.NoChannel)))
2050                     {
2051                         if (!canCauseFault)
2052                         {
2053                             channel = null;
2054                             return true;
2055                         }
2056
2057                         faulted = true;
2058                     }
2059                     else if (!canGetChannel
2060                         || (this.state == State.ChannelOpening)
2061                         || (this.state == State.ChannelClosing))
2062                     {
2063                         waiter = new SyncWaiter(this, canGetChannel, null, timeout, maskingMode, this.binder.ChannelParameters);
2064                         this.GetQueue(canGetChannel).Enqueue(waiter);
2065                     }
2066                     else
2067                     {
2068                         if (this.state != State.NoChannel)
2069                         {
2070                             throw Fx.AssertAndThrow("The state must be NoChannel.");
2071                         }
2072
2073                         waiter = new SyncWaiter(this, canGetChannel,
2074                             this.GetCurrentChannelIfCreated(), timeout, maskingMode,
2075                             this.binder.ChannelParameters);
2076
2077                         this.state = State.ChannelOpening;
2078                         getChannel = true;
2079                     }
2080                 }
2081
2082                 if (faulted)
2083                 {
2084                     this.binder.Fault(null);
2085                     channel = null;
2086                     return true;
2087                 }
2088
2089                 if (getChannel)
2090                 {
2091                     waiter.GetChannel(true);
2092                 }
2093
2094                 return waiter.TryWait(out channel);
2095             }
2096
2097             public void UnblockWaiters()
2098             {
2099                 Queue<IWaiter> temp1;
2100                 Queue<IWaiter> temp2;
2101
2102                 lock (this.ThisLock)
2103                 {
2104                     temp1 = this.getChannelQueue;
2105                     temp2 = this.waitQueue;
2106
2107                     this.getChannelQueue = null;
2108                     this.waitQueue = null;
2109                 }
2110
2111                 bool close = this.state == State.Closed;
2112                 this.UnblockWaiters(temp1, close);
2113                 this.UnblockWaiters(temp2, close);
2114             }
2115
2116             void UnblockWaiters(Queue<IWaiter> waiters, bool close)
2117             {
2118                 if ((waiters != null) && (waiters.Count > 0))
2119                 {
2120                     foreach (IWaiter waiter in waiters)
2121                     {
2122                         if (close)
2123                         {
2124                             waiter.Close();
2125                         }
2126                         else
2127                         {
2128                             waiter.Fault();
2129                         }
2130                     }
2131                 }
2132             }
2133
2134             bool ValidateOpened()
2135             {
2136                 if (this.state == State.Created)
2137                 {
2138                     throw Fx.AssertAndThrow("This operation expects that the synchronizer has been opened.");
2139                 }
2140
2141                 return (this.state != State.Closed) && (this.state != State.Faulted);
2142             }
2143
2144             public void WaitForPendingOperations(TimeSpan timeout)
2145             {
2146                 lock (this.ThisLock)
2147                 {
2148                     if (this.drainEvent != null)
2149                     {
2150                         throw Fx.AssertAndThrow("The WaitForPendingOperations operation may only be invoked once.");
2151                     }
2152
2153                     if (this.count > 0)
2154                     {
2155                         this.drainEvent = new InterruptibleWaitObject(false, false);
2156                     }
2157                 }
2158
2159                 if (this.drainEvent != null)
2160                 {
2161                     this.drainEvent.Wait(timeout);
2162                 }
2163             }
2164
2165             enum State
2166             {
2167                 Created,
2168                 NoChannel,
2169                 ChannelOpening,
2170                 ChannelOpened,
2171                 ChannelClosing,
2172                 Faulted,
2173                 Closed
2174             }
2175
2176             public interface IWaiter
2177             {
2178                 bool CanGetChannel { get; }
2179
2180                 void Close();
2181                 void Fault();
2182                 void GetChannel(bool onUserThread);
2183                 void Set(TChannel channel);
2184             }
2185
2186             public sealed class AsyncWaiter : AsyncResult, IWaiter
2187             {
2188                 bool canGetChannel;
2189                 TChannel channel;
2190                 ChannelParameterCollection channelParameters;
2191                 bool isSynchronous = true;
2192                 MaskingMode maskingMode;
2193                 static AsyncCallback onOpenComplete = Fx.ThunkCallback(new AsyncCallback(OnOpenComplete));
2194                 static Action<object> onTimeoutElapsed = new Action<object>(OnTimeoutElapsed);
2195                 static AsyncCallback onTryGetChannelComplete = Fx.ThunkCallback(new AsyncCallback(OnTryGetChannelComplete));
2196                 bool timedOut = false;
2197                 ChannelSynchronizer synchronizer;
2198                 TimeoutHelper timeoutHelper;
2199                 IOThreadTimer timer;
2200                 bool timerCancelled = false;
2201
2202                 public AsyncWaiter(ChannelSynchronizer synchronizer, bool canGetChannel,
2203                     TChannel channel, TimeSpan timeout, MaskingMode maskingMode,
2204                     ChannelParameterCollection channelParameters,
2205                     AsyncCallback callback, object state)
2206                     : base(callback, state)
2207                 {
2208                     if (!canGetChannel)
2209                     {
2210                         if (channel != null)
2211                         {
2212                             throw Fx.AssertAndThrow("This waiter must wait for a channel thus argument channel must be null.");
2213                         }
2214                     }
2215
2216                     this.synchronizer = synchronizer;
2217                     this.canGetChannel = canGetChannel;
2218                     this.channel = channel;
2219                     this.timeoutHelper = new TimeoutHelper(timeout);
2220                     this.maskingMode = maskingMode;
2221                     this.channelParameters = channelParameters;
2222                 }
2223
2224                 public bool CanGetChannel
2225                 {
2226                     get
2227                     {
2228                         return this.canGetChannel;
2229                     }
2230                 }
2231
2232                 object ThisLock
2233                 {
2234                     get
2235                     {
2236                         return this;
2237                     }
2238                 }
2239
2240                 void CancelTimer()
2241                 {
2242                     lock (this.ThisLock)
2243                     {
2244                         if (!this.timerCancelled)
2245                         {
2246                             if (this.timer != null)
2247                             {
2248                                 this.timer.Cancel();
2249                             }
2250
2251                             this.timerCancelled = true;
2252                         }
2253                     }
2254                 }
2255
2256                 public void Close()
2257                 {
2258                     this.CancelTimer();
2259                     this.channel = null;
2260                     this.Complete(false,
2261                         this.synchronizer.binder.GetClosedException(this.maskingMode));
2262                 }
2263
2264                 bool CompleteOpen(IAsyncResult result)
2265                 {
2266                     this.channel.EndOpen(result);
2267                     return this.OnChannelOpened();
2268                 }
2269
2270                 bool CompleteTryGetChannel(IAsyncResult result)
2271                 {
2272                     if (!this.synchronizer.binder.EndTryGetChannel(result))
2273                     {
2274                         this.timedOut = true;
2275                         this.OnGetChannelFailed();
2276                         return true;
2277                     }
2278
2279                     if (!this.synchronizer.CompleteSetChannel(this, out this.channel))
2280                     {
2281                         if (!this.IsCompleted)
2282                         {
2283                             throw Fx.AssertAndThrow("CompleteSetChannel must complete the IWaiter if it returns false.");
2284                         }
2285
2286                         return false;
2287                     }
2288
2289                     return this.OpenChannel();
2290                 }
2291
2292                 public bool End(out TChannel channel)
2293                 {
2294                     AsyncResult.End<AsyncWaiter>(this);
2295                     channel = this.channel;
2296                     return !this.timedOut;
2297                 }
2298
2299                 public void Fault()
2300                 {
2301                     this.CancelTimer();
2302                     this.channel = null;
2303                     this.Complete(false,
2304                         this.synchronizer.binder.GetFaultedException(this.maskingMode));
2305                 }
2306
2307                 bool GetChannel()
2308                 {
2309                     if (this.channel != null)
2310                     {
2311                         return this.OpenChannel();
2312                     }
2313                     else
2314                     {
2315                         IAsyncResult result = this.synchronizer.binder.BeginTryGetChannel(
2316                             this.timeoutHelper.RemainingTime(), onTryGetChannelComplete, this);
2317
2318                         if (result.CompletedSynchronously)
2319                         {
2320                             return this.CompleteTryGetChannel(result);
2321                         }
2322                     }
2323
2324                     return false;
2325                 }
2326
2327                 public void GetChannel(bool onUserThread)
2328                 {
2329                     if (!this.CanGetChannel)
2330                     {
2331                         throw Fx.AssertAndThrow("This waiter must wait for a channel thus the caller cannot attempt to get a channel.");
2332                     }
2333
2334                     this.isSynchronous = onUserThread;
2335
2336                     if (onUserThread)
2337                     {
2338                         bool throwing = true;
2339
2340                         try
2341                         {
2342                             if (this.GetChannel())
2343                             {
2344                                 this.Complete(true);
2345                             }
2346
2347                             throwing = false;
2348                         }
2349                         finally
2350                         {
2351                             if (throwing)
2352                             {
2353                                 this.OnGetChannelFailed();
2354                             }
2355                         }
2356                     }
2357                     else
2358                     {
2359                         bool complete = false;
2360                         Exception completeException = null;
2361
2362                         try
2363                         {
2364                             this.CancelTimer();
2365                             complete = this.GetChannel();
2366                         }
2367 #pragma warning suppress 56500 // covered by FxCOP
2368                         catch (Exception e)
2369                         {
2370                             if (Fx.IsFatal(e))
2371                             {
2372                                 throw;
2373                             }
2374
2375                             this.OnGetChannelFailed();
2376                             completeException = e;
2377                         }
2378
2379                         if (complete || completeException != null)
2380                         {
2381                             this.Complete(false, completeException);
2382                         }
2383                     }
2384                 }
2385
2386                 bool OnChannelOpened()
2387                 {
2388                     if (this.synchronizer.OnChannelOpened(this))
2389                     {
2390                         return true;
2391                     }
2392                     else
2393                     {
2394                         if (!this.IsCompleted)
2395                         {
2396                             throw Fx.AssertAndThrow("OnChannelOpened must complete the IWaiter if it returns false.");
2397                         }
2398
2399                         return false;
2400                     }
2401                 }
2402
2403                 void OnGetChannelFailed()
2404                 {
2405                     if (this.channel != null)
2406                     {
2407                         this.channel.Abort();
2408                     }
2409
2410                     this.synchronizer.OnGetChannelFailed();
2411                 }
2412
2413                 static void OnOpenComplete(IAsyncResult result)
2414                 {
2415                     if (!result.CompletedSynchronously)
2416                     {
2417                         AsyncWaiter waiter = (AsyncWaiter)result.AsyncState;
2418                         bool complete = false;
2419                         Exception completeException = null;
2420
2421                         waiter.isSynchronous = false;
2422
2423                         try
2424                         {
2425                             complete = waiter.CompleteOpen(result);
2426                         }
2427 #pragma warning suppress 56500 // covered by FxCOP
2428                         catch (Exception e)
2429                         {
2430                             if (Fx.IsFatal(e))
2431                             {
2432                                 throw;
2433                             }
2434
2435                             completeException = e;
2436                         }
2437
2438                         if (complete)
2439                         {
2440                             waiter.Complete(false);
2441                         }
2442                         else if (completeException != null)
2443                         {
2444                             waiter.OnGetChannelFailed();
2445                             waiter.Complete(false, completeException);
2446                         }
2447                     }
2448                 }
2449
2450                 void OnTimeoutElapsed()
2451                 {
2452                     if (this.synchronizer.RemoveWaiter(this))
2453                     {
2454                         this.timedOut = true;
2455                         this.Complete(this.isSynchronous, null);
2456                     }
2457                 }
2458
2459                 static void OnTimeoutElapsed(object state)
2460                 {
2461                     AsyncWaiter waiter = (AsyncWaiter)state;
2462                     waiter.isSynchronous = false;
2463                     waiter.OnTimeoutElapsed();
2464                 }
2465
2466                 static void OnTryGetChannelComplete(IAsyncResult result)
2467                 {
2468                     if (!result.CompletedSynchronously)
2469                     {
2470                         AsyncWaiter waiter = (AsyncWaiter)result.AsyncState;
2471                         waiter.isSynchronous = false;
2472                         bool complete = false;
2473                         Exception completeException = null;
2474
2475                         try
2476                         {
2477                             complete = waiter.CompleteTryGetChannel(result);
2478                         }
2479 #pragma warning suppress 56500 // covered by FxCOP
2480                         catch (Exception e)
2481                         {
2482                             if (Fx.IsFatal(e))
2483                             {
2484                                 throw;
2485                             }
2486
2487                             completeException = e;
2488                         }
2489
2490                         if (complete || completeException != null)
2491                         {
2492                             if (completeException != null)
2493                                 waiter.OnGetChannelFailed();
2494                             waiter.Complete(waiter.isSynchronous, completeException);
2495                         }
2496                     }
2497                 }
2498
2499                 bool OpenChannel()
2500                 {
2501                     if (this.synchronizer.binder.MustOpenChannel)
2502                     {
2503                         if (this.channelParameters != null)
2504                         {
2505                             this.channelParameters.PropagateChannelParameters(this.channel);
2506                         }
2507
2508                         IAsyncResult result = this.channel.BeginOpen(
2509                             this.timeoutHelper.RemainingTime(), onOpenComplete, this);
2510
2511                         if (result.CompletedSynchronously)
2512                         {
2513                             return this.CompleteOpen(result);
2514                         }
2515
2516                         return false;
2517                     }
2518                     else
2519                     {
2520                         return this.OnChannelOpened();
2521                     }
2522                 }
2523
2524                 public void Set(TChannel channel)
2525                 {
2526                     this.CancelTimer();
2527                     this.channel = channel;
2528                     this.Complete(false);
2529                 }
2530
2531                 // Always called from the user's thread.
2532                 public void Wait()
2533                 {
2534                     lock (this.ThisLock)
2535                     {
2536                         if (this.timerCancelled)
2537                         {
2538                             return;
2539                         }
2540
2541                         TimeSpan timeout = this.timeoutHelper.RemainingTime();
2542
2543                         if (timeout > TimeSpan.Zero)
2544                         {
2545                             this.timer = new IOThreadTimer(onTimeoutElapsed, this, true);
2546                             this.timer.Set(this.timeoutHelper.RemainingTime());
2547                             return;
2548                         }
2549                     }
2550
2551                     this.OnTimeoutElapsed();
2552                 }
2553             }
2554
2555             sealed class SynchronizerCompletedAsyncResult : CompletedAsyncResult
2556             {
2557                 public SynchronizerCompletedAsyncResult(AsyncCallback callback, object state)
2558                     : base(callback, state)
2559                 {
2560                 }
2561
2562                 public void End()
2563                 {
2564                     CompletedAsyncResult.End(this);
2565                 }
2566             }
2567
2568             sealed class SyncWaiter : IWaiter
2569             {
2570                 bool canGetChannel;
2571                 TChannel channel;
2572                 ChannelParameterCollection channelParameters;
2573                 AutoResetEvent completeEvent = new AutoResetEvent(false);
2574                 Exception exception;
2575                 bool getChannel = false;
2576                 MaskingMode maskingMode;
2577                 ChannelSynchronizer synchronizer;
2578                 TimeoutHelper timeoutHelper;
2579
2580                 public SyncWaiter(ChannelSynchronizer synchronizer, bool canGetChannel,
2581                     TChannel channel, TimeSpan timeout, MaskingMode maskingMode,
2582                     ChannelParameterCollection channelParameters)
2583                 {
2584                     if (!canGetChannel)
2585                     {
2586                         if (channel != null)
2587                         {
2588                             throw Fx.AssertAndThrow("This waiter must wait for a channel thus argument channel must be null.");
2589                         }
2590                     }
2591
2592                     this.synchronizer = synchronizer;
2593                     this.canGetChannel = canGetChannel;
2594                     this.channel = channel;
2595                     this.timeoutHelper = new TimeoutHelper(timeout);
2596                     this.maskingMode = maskingMode;
2597                     this.channelParameters = channelParameters;
2598                 }
2599
2600                 public bool CanGetChannel
2601                 {
2602                     get
2603                     {
2604                         return this.canGetChannel;
2605                     }
2606                 }
2607
2608                 public void Close()
2609                 {
2610                     this.exception = this.synchronizer.binder.GetClosedException(this.maskingMode);
2611                     this.completeEvent.Set();
2612                 }
2613
2614                 public void Fault()
2615                 {
2616                     this.exception = this.synchronizer.binder.GetFaultedException(this.maskingMode);
2617                     this.completeEvent.Set();
2618                 }
2619
2620                 public void GetChannel(bool onUserThread)
2621                 {
2622                     if (!this.CanGetChannel)
2623                     {
2624                         throw Fx.AssertAndThrow("This waiter must wait for a channel thus the caller cannot attempt to get a channel.");
2625                     }
2626
2627                     this.getChannel = true;
2628                     this.completeEvent.Set();
2629                 }
2630
2631                 public void Set(TChannel channel)
2632                 {
2633                     if (channel == null)
2634                     {
2635                         throw Fx.AssertAndThrow("Argument channel cannot be null. Caller must call Fault or Close instead.");
2636                     }
2637
2638                     this.channel = channel;
2639                     this.completeEvent.Set();
2640                 }
2641
2642                 bool TryGetChannel()
2643                 {
2644                     TChannel channel;
2645
2646                     if (this.channel != null)
2647                     {
2648                         channel = this.channel;
2649                     }
2650                     else if (this.synchronizer.binder.TryGetChannel(
2651                         this.timeoutHelper.RemainingTime()))
2652                     {
2653                         if (!this.synchronizer.CompleteSetChannel(this, out channel))
2654                         {
2655                             return true;
2656                         }
2657                     }
2658                     else
2659                     {
2660                         this.synchronizer.OnGetChannelFailed();
2661                         return false;
2662                     }
2663
2664                     if (this.synchronizer.binder.MustOpenChannel)
2665                     {
2666                         bool throwing = true;
2667
2668                         if (this.channelParameters != null)
2669                         {
2670                             this.channelParameters.PropagateChannelParameters(channel);
2671                         }
2672
2673                         try
2674                         {
2675                             channel.Open(this.timeoutHelper.RemainingTime());
2676                             throwing = false;
2677                         }
2678                         finally
2679                         {
2680                             if (throwing)
2681                             {
2682                                 channel.Abort();
2683                                 this.synchronizer.OnGetChannelFailed();
2684                             }
2685                         }
2686                     }
2687
2688                     if (this.synchronizer.OnChannelOpened(this))
2689                     {
2690                         this.Set(channel);
2691                     }
2692
2693                     return true;
2694                 }
2695
2696                 public bool TryWait(out TChannel channel)
2697                 {
2698                     if (!this.Wait())
2699                     {
2700                         channel = null;
2701                         return false;
2702                     }
2703                     else if (this.getChannel && !this.TryGetChannel())
2704                     {
2705                         channel = null;
2706                         return false;
2707                     }
2708
2709                     this.completeEvent.Close();
2710
2711                     if (this.exception != null)
2712                     {
2713                         if (this.channel != null)
2714                         {
2715                             throw Fx.AssertAndThrow("User of IWaiter called both Set and Fault or Close.");
2716                         }
2717
2718                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(this.exception);
2719                     }
2720
2721                     channel = this.channel;
2722                     return true;
2723                 }
2724
2725                 bool Wait()
2726                 {
2727                     if (!TimeoutHelper.WaitOne(this.completeEvent, this.timeoutHelper.RemainingTime()))
2728                     {
2729                         if (this.synchronizer.RemoveWaiter(this))
2730                         {
2731                             return false;
2732                         }
2733                         else
2734                         {
2735                             TimeoutHelper.WaitOne(this.completeEvent, TimeSpan.MaxValue);
2736                         }
2737                     }
2738
2739                     return true;
2740                 }
2741             }
2742         }
2743
2744         sealed class CloseAsyncResult : AsyncResult
2745         {
2746             ReliableChannelBinder<TChannel> binder;
2747             TChannel channel;
2748             MaskingMode maskingMode;
2749             static AsyncCallback onBinderCloseComplete = Fx.ThunkCallback(new AsyncCallback(OnBinderCloseComplete));
2750             static AsyncCallback onChannelCloseComplete = Fx.ThunkCallback(new AsyncCallback(OnChannelCloseComplete));
2751             TimeoutHelper timeoutHelper;
2752
2753             public CloseAsyncResult(ReliableChannelBinder<TChannel> binder, TChannel channel,
2754                 TimeSpan timeout, MaskingMode maskingMode, AsyncCallback callback, object state)
2755                 : base(callback, state)
2756             {
2757                 this.binder = binder;
2758                 this.channel = channel;
2759                 this.timeoutHelper = new TimeoutHelper(timeout);
2760                 this.maskingMode = maskingMode;
2761                 bool complete = false;
2762
2763                 try
2764                 {
2765                     this.binder.OnShutdown();
2766                     IAsyncResult result = this.binder.OnBeginClose(timeout, onBinderCloseComplete, this);
2767
2768                     if (result.CompletedSynchronously)
2769                     {
2770                         complete = this.CompleteBinderClose(true, result);
2771                     }
2772                 }
2773                 catch (Exception e)
2774                 {
2775                     if (Fx.IsFatal(e))
2776                     {
2777                         throw;
2778                     }
2779
2780                     this.binder.Abort();
2781
2782                     if (!this.binder.HandleException(e, this.maskingMode))
2783                     {
2784                         throw;
2785                     }
2786                     else
2787                     {
2788                         complete = true;
2789                     }
2790                 }
2791
2792                 if (complete)
2793                 {
2794                     this.Complete(true);
2795                 }
2796             }
2797
2798             bool CompleteBinderClose(bool synchronous, IAsyncResult result)
2799             {
2800                 this.binder.OnEndClose(result);
2801
2802                 if (this.channel != null)
2803                 {
2804                     result = this.binder.BeginCloseChannel(this.channel,
2805                         this.timeoutHelper.RemainingTime(), onChannelCloseComplete, this);
2806
2807                     if (result.CompletedSynchronously)
2808                     {
2809                         return this.CompleteChannelClose(synchronous, result);
2810                     }
2811                     else
2812                     {
2813                         return false;
2814                     }
2815                 }
2816                 else
2817                 {
2818                     this.binder.TransitionToClosed();
2819                     return true;
2820                 }
2821             }
2822
2823             bool CompleteChannelClose(bool synchronous, IAsyncResult result)
2824             {
2825                 this.binder.EndCloseChannel(this.channel, result);
2826                 this.binder.TransitionToClosed();
2827                 return true;
2828             }
2829
2830             public void End()
2831             {
2832                 AsyncResult.End<CloseAsyncResult>(this);
2833             }
2834
2835             Exception HandleAsyncException(Exception e)
2836             {
2837                 this.binder.Abort();
2838
2839                 if (this.binder.HandleException(e, this.maskingMode))
2840                 {
2841                     return null;
2842                 }
2843                 else
2844                 {
2845                     return e;
2846                 }
2847             }
2848
2849             static void OnBinderCloseComplete(IAsyncResult result)
2850             {
2851                 if (!result.CompletedSynchronously)
2852                 {
2853                     CloseAsyncResult closeResult = (CloseAsyncResult)result.AsyncState;
2854                     bool complete;
2855                     Exception completeException;
2856
2857                     try
2858                     {
2859                         complete = closeResult.CompleteBinderClose(false, result);
2860                         completeException = null;
2861                     }
2862 #pragma warning suppress 56500 // covered by FxCOP
2863                     catch (Exception e)
2864                     {
2865                         if (Fx.IsFatal(e))
2866                         {
2867                             throw;
2868                         }
2869
2870                         complete = true;
2871                         completeException = e;
2872                     }
2873
2874                     if (complete)
2875                     {
2876                         if (completeException != null)
2877                         {
2878                             completeException = closeResult.HandleAsyncException(completeException);
2879                         }
2880
2881                         closeResult.Complete(false, completeException);
2882                     }
2883                 }
2884             }
2885
2886             static void OnChannelCloseComplete(IAsyncResult result)
2887             {
2888                 if (!result.CompletedSynchronously)
2889                 {
2890                     CloseAsyncResult closeResult = (CloseAsyncResult)result.AsyncState;
2891                     bool complete;
2892                     Exception completeException;
2893
2894                     try
2895                     {
2896                         complete = closeResult.CompleteChannelClose(false, result);
2897                         completeException = null;
2898                     }
2899 #pragma warning suppress 56500 // covered by FxCOP
2900                     catch (Exception e)
2901                     {
2902                         if (Fx.IsFatal(e))
2903                         {
2904                             throw;
2905                         }
2906
2907                         complete = true;
2908                         completeException = e;
2909                     }
2910
2911                     if (complete)
2912                     {
2913                         if (completeException != null)
2914                         {
2915                             completeException = closeResult.HandleAsyncException(completeException);
2916                         }
2917
2918                         closeResult.Complete(false, completeException);
2919                     }
2920                 }
2921             }
2922         }
2923
2924         protected abstract class InputAsyncResult<TBinder> : AsyncResult
2925             where TBinder : ReliableChannelBinder<TChannel>
2926         {
2927             bool autoAborted;
2928             TBinder binder;
2929             bool canGetChannel;
2930             TChannel channel;
2931             bool isSynchronous = true;
2932             MaskingMode maskingMode;
2933             static AsyncCallback onInputComplete = Fx.ThunkCallback(new AsyncCallback(OnInputCompleteStatic));
2934             static AsyncCallback onTryGetChannelComplete = Fx.ThunkCallback(new AsyncCallback(OnTryGetChannelCompleteStatic));
2935             bool success;
2936             TimeoutHelper timeoutHelper;
2937
2938             public InputAsyncResult(TBinder binder, bool canGetChannel, TimeSpan timeout,
2939                 MaskingMode maskingMode, AsyncCallback callback, object state)
2940                 : base(callback, state)
2941             {
2942                 this.binder = binder;
2943                 this.canGetChannel = canGetChannel;
2944                 this.timeoutHelper = new TimeoutHelper(timeout);
2945                 this.maskingMode = maskingMode;
2946             }
2947
2948             protected abstract IAsyncResult BeginInput(TBinder binder, TChannel channel,
2949                 TimeSpan timeout, AsyncCallback callback, object state);
2950
2951             // returns true if the caller should retry
2952             bool CompleteInput(IAsyncResult result)
2953             {
2954                 bool complete;
2955
2956                 try
2957                 {
2958                     this.success = this.EndInput(this.binder, this.channel, result, out complete);
2959                 }
2960                 finally
2961                 {
2962                     this.autoAborted = this.binder.Synchronizer.Aborting;
2963                     this.binder.synchronizer.ReturnChannel();
2964                 }
2965
2966                 return !complete;
2967             }
2968
2969             // returns true if the caller should retry
2970             bool CompleteTryGetChannel(IAsyncResult result, out bool complete)
2971             {
2972                 complete = false;
2973                 this.success = this.binder.synchronizer.EndTryGetChannel(result, out this.channel);
2974
2975                 // the synchronizer is faulted and not reestablishing or closed, or the call timed
2976                 // out, complete and don't retry.
2977                 if (this.channel == null)
2978                 {
2979                     complete = true;
2980                     return false;
2981                 }
2982
2983                 bool throwing = true;
2984                 IAsyncResult inputResult = null;
2985
2986                 try
2987                 {
2988                     inputResult = this.BeginInput(this.binder, this.channel,
2989                         this.timeoutHelper.RemainingTime(), onInputComplete, this);
2990                     throwing = false;
2991                 }
2992                 finally
2993                 {
2994                     if (throwing)
2995                     {
2996                         this.autoAborted = this.binder.Synchronizer.Aborting;
2997                         this.binder.synchronizer.ReturnChannel();
2998                     }
2999                 }
3000
3001                 if (inputResult.CompletedSynchronously)
3002                 {
3003                     if (this.CompleteInput(inputResult))
3004                     {
3005                         complete = false;
3006                         return true;
3007                     }
3008                     else
3009                     {
3010                         complete = true;
3011                         return false;
3012                     }
3013                 }
3014                 else
3015                 {
3016                     complete = false;
3017                     return false;
3018                 }
3019             }
3020
3021             public bool End()
3022             {
3023                 AsyncResult.End<InputAsyncResult<TBinder>>(this);
3024                 return this.success;
3025             }
3026
3027             protected abstract bool EndInput(TBinder binder, TChannel channel,
3028                 IAsyncResult result, out bool complete);
3029
3030             void OnInputComplete(IAsyncResult result)
3031             {
3032                 this.isSynchronous = false;
3033                 bool retry;
3034                 Exception completeException = null;
3035
3036                 try
3037                 {
3038                     retry = this.CompleteInput(result);
3039                 }
3040 #pragma warning suppress 56500 // covered by FxCOP
3041                 catch (Exception e)
3042                 {
3043                     if (Fx.IsFatal(e))
3044                     {
3045                         throw;
3046                     }
3047
3048                     if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted))
3049                     {
3050                         completeException = e;
3051                         retry = false;
3052                     }
3053                     else
3054                     {
3055                         retry = true;
3056                     }
3057                 }
3058
3059                 if (retry)
3060                 {
3061                     this.StartOnNonUserThread();
3062                 }
3063                 else
3064                 {
3065                     this.Complete(this.isSynchronous, completeException);
3066                 }
3067             }
3068
3069             static void OnInputCompleteStatic(IAsyncResult result)
3070             {
3071                 if (!result.CompletedSynchronously)
3072                 {
3073                     InputAsyncResult<TBinder> inputResult =
3074                         (InputAsyncResult<TBinder>)result.AsyncState;
3075                     inputResult.OnInputComplete(result);
3076                 }
3077             }
3078
3079             void OnTryGetChannelComplete(IAsyncResult result)
3080             {
3081                 this.isSynchronous = false;
3082                 bool retry = false;
3083                 bool complete = false;
3084                 Exception completeException = null;
3085
3086                 try
3087                 {
3088                     retry = this.CompleteTryGetChannel(result, out complete);
3089                 }
3090 #pragma warning suppress 56500 // covered by FxCOP
3091                 catch (Exception e)
3092                 {
3093                     if (Fx.IsFatal(e))
3094                     {
3095                         throw;
3096                     }
3097
3098                     if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted))
3099                     {
3100                         completeException = e;
3101                         retry = false;
3102                     }
3103                     else
3104                     {
3105                         retry = true;
3106                     }
3107                 }
3108
3109                 // Can't complete AND retry.
3110                 if (complete && retry)
3111                 {
3112                     throw Fx.AssertAndThrow("The derived class' implementation of CompleteTryGetChannel() cannot indicate that the asynchronous operation should complete and retry.");
3113                 }
3114
3115                 if (retry)
3116                 {
3117                     this.StartOnNonUserThread();
3118                 }
3119                 else if (complete || completeException != null)
3120                 {
3121                     this.Complete(this.isSynchronous, completeException);
3122                 }
3123             }
3124
3125             static void OnTryGetChannelCompleteStatic(IAsyncResult result)
3126             {
3127                 if (!result.CompletedSynchronously)
3128                 {
3129                     InputAsyncResult<TBinder> inputResult =
3130                         (InputAsyncResult<TBinder>)result.AsyncState;
3131                     inputResult.OnTryGetChannelComplete(result);
3132                 }
3133             }
3134
3135             protected bool Start()
3136             {
3137                 while (true)
3138                 {
3139                     bool retry = false;
3140                     bool complete = false;
3141
3142                     this.autoAborted = false;
3143
3144                     try
3145                     {
3146                         IAsyncResult result = this.binder.synchronizer.BeginTryGetChannelForInput(
3147                             canGetChannel, this.timeoutHelper.RemainingTime(),
3148                             onTryGetChannelComplete, this);
3149
3150                         if (result.CompletedSynchronously)
3151                         {
3152                             retry = this.CompleteTryGetChannel(result, out complete);
3153                         }
3154                     }
3155                     catch (Exception e)
3156                     {
3157                         if (Fx.IsFatal(e))
3158                         {
3159                             throw;
3160                         }
3161
3162                         if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted))
3163                         {
3164                             throw;
3165                         }
3166                         else
3167                         {
3168                             retry = true;
3169                         }
3170                     }
3171
3172                     // Can't complete AND retry.
3173                     if (complete && retry)
3174                     {
3175                         throw Fx.AssertAndThrow("The derived class' implementation of CompleteTryGetChannel() cannot indicate that the asynchronous operation should complete and retry.");
3176                     }
3177
3178                     if (!retry)
3179                     {
3180                         return complete;
3181                     }
3182                 }
3183             }
3184
3185             void StartOnNonUserThread()
3186             {
3187                 bool complete = false;
3188                 Exception completeException = null;
3189
3190                 try
3191                 {
3192                     complete = this.Start();
3193                 }
3194 #pragma warning suppress 56500 // covered by FxCOP
3195                 catch (Exception e)
3196                 {
3197                     if (Fx.IsFatal(e))
3198                         throw;
3199
3200                     completeException = e;
3201                 }
3202
3203                 if (complete || completeException != null)
3204                     this.Complete(false, completeException);
3205             }
3206         }
3207
3208         sealed class MessageRequestContext : BinderRequestContext
3209         {
3210             public MessageRequestContext(ReliableChannelBinder<TChannel> binder, Message message)
3211                 : base(binder, message)
3212             {
3213             }
3214
3215             protected override void OnAbort()
3216             {
3217             }
3218
3219             protected override void OnClose(TimeSpan timeout)
3220             {
3221             }
3222
3223             protected override IAsyncResult OnBeginReply(Message message, TimeSpan timeout, AsyncCallback callback, object state)
3224             {
3225                 return new ReplyAsyncResult(this, message, timeout, callback, state);
3226             }
3227
3228             protected override void OnEndReply(IAsyncResult result)
3229             {
3230                 ReplyAsyncResult.End(result);
3231             }
3232
3233             protected override void OnReply(Message message, TimeSpan timeout)
3234             {
3235                 if (message != null)
3236                 {
3237                     this.Binder.Send(message, timeout, this.MaskingMode);
3238                 }
3239             }
3240
3241             class ReplyAsyncResult : AsyncResult
3242             {
3243                 static AsyncCallback onSend;
3244                 MessageRequestContext context;
3245
3246                 public ReplyAsyncResult(MessageRequestContext context, Message message, TimeSpan timeout, AsyncCallback callback, object state)
3247                     : base(callback, state)
3248                 {
3249                     if (message != null)
3250                     {
3251                         if (onSend == null)
3252                         {
3253                             onSend = Fx.ThunkCallback(new AsyncCallback(OnSend));
3254                         }
3255                         this.context = context;
3256                         IAsyncResult result = context.Binder.BeginSend(message, timeout, context.MaskingMode, onSend, this);
3257                         if (!result.CompletedSynchronously)
3258                         {
3259                             return;
3260                         }
3261                         context.Binder.EndSend(result);
3262                     }
3263
3264                     base.Complete(true);
3265                 }
3266
3267                 public static void End(IAsyncResult result)
3268                 {
3269                     AsyncResult.End<ReplyAsyncResult>(result);
3270                 }
3271
3272                 static void OnSend(IAsyncResult result)
3273                 {
3274                     if (result.CompletedSynchronously)
3275                     {
3276                         return;
3277                     }
3278
3279                     Exception completionException = null;
3280                     ReplyAsyncResult thisPtr = (ReplyAsyncResult)result.AsyncState;
3281                     try
3282                     {
3283                         thisPtr.context.Binder.EndSend(result);
3284                     }
3285 #pragma warning suppress 56500 // covered by FxCOP
3286                     catch (Exception exception)
3287                     {
3288                         if (Fx.IsFatal(exception))
3289                         {
3290                             throw;
3291                         }
3292                         completionException = exception;
3293                     }
3294
3295                     thisPtr.Complete(false, completionException);
3296                 }
3297             }
3298         }
3299
3300         protected abstract class OutputAsyncResult<TBinder> : AsyncResult
3301             where TBinder : ReliableChannelBinder<TChannel>
3302         {
3303             bool autoAborted;
3304             TBinder binder;
3305             TChannel channel;
3306             bool hasChannel = false;
3307             MaskingMode maskingMode;
3308             Message message;
3309             static AsyncCallback onTryGetChannelComplete = Fx.ThunkCallback(new AsyncCallback(OnTryGetChannelCompleteStatic));
3310             static AsyncCallback onOutputComplete = Fx.ThunkCallback(new AsyncCallback(OnOutputCompleteStatic));
3311             TimeSpan timeout;
3312             TimeoutHelper timeoutHelper;
3313
3314             public OutputAsyncResult(TBinder binder, AsyncCallback callback, object state)
3315                 : base(callback, state)
3316             {
3317                 this.binder = binder;
3318             }
3319
3320             public MaskingMode MaskingMode
3321             {
3322                 get
3323                 {
3324                     return this.maskingMode;
3325                 }
3326             }
3327
3328             protected abstract IAsyncResult BeginOutput(TBinder binder, TChannel channel,
3329                 Message message, TimeSpan timeout, MaskingMode maskingMode, AsyncCallback callback,
3330                 object state);
3331
3332             void Cleanup()
3333             {
3334                 if (this.hasChannel)
3335                 {
3336                     this.autoAborted = this.binder.Synchronizer.Aborting;
3337                     this.binder.synchronizer.ReturnChannel();
3338                 }
3339             }
3340
3341             bool CompleteOutput(IAsyncResult result)
3342             {
3343                 this.EndOutput(this.binder, this.channel, this.maskingMode, result);
3344                 this.Cleanup();
3345                 return true;
3346             }
3347
3348             bool CompleteTryGetChannel(IAsyncResult result)
3349             {
3350                 bool timedOut = !this.binder.synchronizer.EndTryGetChannel(result,
3351                     out this.channel);
3352
3353                 if (timedOut || (this.channel == null))
3354                 {
3355                     this.Cleanup();
3356
3357                     if (timedOut && !ReliableChannelBinderHelper.MaskHandled(maskingMode))
3358                     {
3359                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(this.GetTimeoutString(this.timeout)));
3360                     }
3361
3362                     return true;
3363                 }
3364
3365                 this.hasChannel = true;
3366
3367                 result = this.BeginOutput(this.binder, this.channel, this.message,
3368                     this.timeoutHelper.RemainingTime(), this.maskingMode, onOutputComplete,
3369                     this);
3370
3371                 if (result.CompletedSynchronously)
3372                 {
3373                     return this.CompleteOutput(result);
3374                 }
3375                 else
3376                 {
3377                     return false;
3378                 }
3379             }
3380
3381             protected abstract void EndOutput(TBinder binder, TChannel channel,
3382                 MaskingMode maskingMode, IAsyncResult result);
3383
3384             protected abstract string GetTimeoutString(TimeSpan timeout);
3385
3386             void OnOutputComplete(IAsyncResult result)
3387             {
3388                 if (!result.CompletedSynchronously)
3389                 {
3390                     bool complete = false;
3391                     Exception completeException = null;
3392
3393                     try
3394                     {
3395                         complete = this.CompleteOutput(result);
3396                     }
3397 #pragma warning suppress 56500 // covered by FxCOP
3398                     catch (Exception e)
3399                     {
3400                         if (Fx.IsFatal(e))
3401                         {
3402                             throw;
3403                         }
3404
3405                         this.Cleanup();
3406                         complete = true;
3407                         if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted))
3408                         {
3409                             completeException = e;
3410                         }
3411                     }
3412
3413                     if (complete)
3414                     {
3415                         this.Complete(false, completeException);
3416                     }
3417                 }
3418             }
3419
3420             static void OnOutputCompleteStatic(IAsyncResult result)
3421             {
3422                 OutputAsyncResult<TBinder> outputResult =
3423                     (OutputAsyncResult<TBinder>)result.AsyncState;
3424
3425                 outputResult.OnOutputComplete(result);
3426             }
3427
3428             void OnTryGetChannelComplete(IAsyncResult result)
3429             {
3430                 if (!result.CompletedSynchronously)
3431                 {
3432                     bool complete = false;
3433                     Exception completeException = null;
3434
3435                     try
3436                     {
3437                         complete = this.CompleteTryGetChannel(result);
3438                     }
3439 #pragma warning suppress 56500 // covered by FxCOP
3440                     catch (Exception e)
3441                     {
3442                         if (Fx.IsFatal(e))
3443                         {
3444                             throw;
3445                         }
3446
3447                         this.Cleanup();
3448                         complete = true;
3449                         if (!this.binder.HandleException(e, this.maskingMode, this.autoAborted))
3450                         {
3451                             completeException = e;
3452                         }
3453                     }
3454
3455                     if (complete)
3456                     {
3457                         this.Complete(false, completeException);
3458                     }
3459                 }
3460             }
3461
3462             static void OnTryGetChannelCompleteStatic(IAsyncResult result)
3463             {
3464                 OutputAsyncResult<TBinder> outputResult =
3465                     (OutputAsyncResult<TBinder>)result.AsyncState;
3466
3467                 outputResult.OnTryGetChannelComplete(result);
3468             }
3469
3470             public void Start(Message message, TimeSpan timeout, MaskingMode maskingMode)
3471             {
3472                 if (!this.binder.ValidateOutputOperation(message, timeout, maskingMode))
3473                 {
3474                     this.Complete(true);
3475                     return;
3476                 }
3477
3478                 this.message = message;
3479                 this.timeout = timeout;
3480                 this.timeoutHelper = new TimeoutHelper(timeout);
3481                 this.maskingMode = maskingMode;
3482
3483                 bool complete = false;
3484
3485                 try
3486                 {
3487                     IAsyncResult result = this.binder.synchronizer.BeginTryGetChannelForOutput(
3488                         timeoutHelper.RemainingTime(), this.maskingMode, onTryGetChannelComplete, this);
3489
3490                     if (result.CompletedSynchronously)
3491                     {
3492                         complete = this.CompleteTryGetChannel(result);
3493                     }
3494                 }
3495                 catch (Exception e)
3496                 {
3497                     if (Fx.IsFatal(e))
3498                     {
3499                         throw;
3500                     }
3501
3502                     this.Cleanup();
3503                     if (this.binder.HandleException(e, this.maskingMode, this.autoAborted))
3504                     {
3505                         complete = true;
3506                     }
3507                     else
3508                     {
3509                         throw;
3510                     }
3511                 }
3512
3513                 if (complete)
3514                 {
3515                     this.Complete(true);
3516                 }
3517             }
3518         }
3519
3520         sealed class RequestRequestContext : BinderRequestContext
3521         {
3522             RequestContext innerContext;
3523
3524             public RequestRequestContext(ReliableChannelBinder<TChannel> binder,
3525                 RequestContext innerContext, Message message)
3526                 : base(binder, message)
3527             {
3528                 if ((binder.defaultMaskingMode != MaskingMode.All) && !binder.TolerateFaults)
3529                 {
3530                     throw Fx.AssertAndThrow("This request context is designed to catch exceptions. Thus it cannot be used if the caller expects no exception handling.");
3531                 }
3532
3533                 if (innerContext == null)
3534                 {
3535                     throw Fx.AssertAndThrow("Argument innerContext cannot be null.");
3536                 }
3537
3538                 this.innerContext = innerContext;
3539             }
3540
3541             protected override void OnAbort()
3542             {
3543                 this.innerContext.Abort();
3544             }
3545
3546             protected override IAsyncResult OnBeginReply(Message message, TimeSpan timeout,
3547                 AsyncCallback callback, object state)
3548             {
3549                 try
3550                 {
3551                     if (message != null)
3552                         this.Binder.AddOutputHeaders(message);
3553                     return this.innerContext.BeginReply(message, timeout, callback, state);
3554                 }
3555                 catch (ObjectDisposedException) { }
3556                 catch (Exception e)
3557                 {
3558                     if (Fx.IsFatal(e))
3559                     {
3560                         throw;
3561                     }
3562
3563                     if (!this.Binder.HandleException(e, this.MaskingMode))
3564                     {
3565                         throw;
3566                     }
3567
3568                     this.innerContext.Abort();
3569                 }
3570
3571                 return new BinderCompletedAsyncResult(callback, state);
3572             }
3573
3574             protected override void OnClose(TimeSpan timeout)
3575             {
3576                 try
3577                 {
3578                     this.innerContext.Close(timeout);
3579                 }
3580                 catch (ObjectDisposedException) { }
3581                 catch (Exception e)
3582                 {
3583                     if (Fx.IsFatal(e))
3584                     {
3585                         throw;
3586                     }
3587
3588                     if (!this.Binder.HandleException(e, this.MaskingMode))
3589                     {
3590                         throw;
3591                     }
3592
3593                     this.innerContext.Abort();
3594                 }
3595             }
3596
3597             protected override void OnEndReply(IAsyncResult result)
3598             {
3599                 BinderCompletedAsyncResult completedResult = result as BinderCompletedAsyncResult;
3600                 if (completedResult != null)
3601                 {
3602                     completedResult.End();
3603                     return;
3604                 }
3605
3606                 try
3607                 {
3608                     this.innerContext.EndReply(result);
3609                 }
3610                 catch (ObjectDisposedException) { }
3611                 catch (Exception e)
3612                 {
3613                     if (Fx.IsFatal(e))
3614                     {
3615                         throw;
3616                     }
3617
3618                     if (!this.Binder.HandleException(e, this.MaskingMode))
3619                     {
3620                         throw;
3621                     }
3622
3623                     this.innerContext.Abort();
3624                 }
3625             }
3626
3627             protected override void OnReply(Message message, TimeSpan timeout)
3628             {
3629                 try
3630                 {
3631                     if (message != null)
3632                         this.Binder.AddOutputHeaders(message);
3633                     this.innerContext.Reply(message, timeout);
3634                 }
3635                 catch (ObjectDisposedException) { }
3636                 catch (Exception e)
3637                 {
3638                     if (Fx.IsFatal(e))
3639                     {
3640                         throw;
3641                     }
3642
3643                     if (!this.Binder.HandleException(e, this.MaskingMode))
3644                     {
3645                         throw;
3646                     }
3647
3648                     this.innerContext.Abort();
3649                 }
3650             }
3651         }
3652
3653         sealed class SendAsyncResult : OutputAsyncResult<ReliableChannelBinder<TChannel>>
3654         {
3655             public SendAsyncResult(ReliableChannelBinder<TChannel> binder, AsyncCallback callback,
3656                 object state)
3657                 : base(binder, callback, state)
3658             {
3659             }
3660
3661             protected override IAsyncResult BeginOutput(ReliableChannelBinder<TChannel> binder,
3662                 TChannel channel, Message message, TimeSpan timeout, MaskingMode maskingMode,
3663                 AsyncCallback callback, object state)
3664             {
3665                 binder.AddOutputHeaders(message);
3666                 return binder.OnBeginSend(channel, message, timeout, callback, state);
3667             }
3668
3669             public static void End(IAsyncResult result)
3670             {
3671                 AsyncResult.End<SendAsyncResult>(result);
3672             }
3673
3674             protected override void EndOutput(ReliableChannelBinder<TChannel> binder,
3675                 TChannel channel, MaskingMode maskingMode, IAsyncResult result)
3676             {
3677                 binder.OnEndSend(channel, result);
3678             }
3679
3680             protected override string GetTimeoutString(TimeSpan timeout)
3681             {
3682                 return SR.GetString(SR.TimeoutOnSend, timeout);
3683             }
3684         }
3685
3686         sealed class TryReceiveAsyncResult : InputAsyncResult<ReliableChannelBinder<TChannel>>
3687         {
3688             RequestContext requestContext;
3689
3690             public TryReceiveAsyncResult(ReliableChannelBinder<TChannel> binder, TimeSpan timeout,
3691                 MaskingMode maskingMode, AsyncCallback callback, object state)
3692                 : base(binder, binder.CanGetChannelForReceive, timeout, maskingMode, callback, state)
3693             {
3694                 if (this.Start())
3695                     this.Complete(true);
3696             }
3697
3698             protected override IAsyncResult BeginInput(ReliableChannelBinder<TChannel> binder,
3699                 TChannel channel, TimeSpan timeout, AsyncCallback callback, object state)
3700             {
3701                 return binder.OnBeginTryReceive(channel, timeout, callback, state);
3702             }
3703
3704             public bool End(out RequestContext requestContext)
3705             {
3706                 requestContext = this.requestContext;
3707                 return this.End();
3708             }
3709
3710             protected override bool EndInput(ReliableChannelBinder<TChannel> binder,
3711                 TChannel channel, IAsyncResult result, out bool complete)
3712             {
3713                 bool success = binder.OnEndTryReceive(channel, result, out this.requestContext);
3714
3715                 // timed out || got message, complete immediately
3716                 complete = !success || (this.requestContext != null);
3717
3718                 if (!complete)
3719                 {
3720                     // the underlying channel closed or faulted
3721                     binder.synchronizer.OnReadEof();
3722                 }
3723
3724                 return success;
3725             }
3726         }
3727     }
3728
3729     static class ReliableChannelBinderHelper
3730     {
3731         internal static IAsyncResult BeginCloseDuplexSessionChannel(
3732             ReliableChannelBinder<IDuplexSessionChannel> binder, IDuplexSessionChannel channel,
3733             TimeSpan timeout, AsyncCallback callback, object state)
3734         {
3735             return new CloseDuplexSessionChannelAsyncResult(binder, channel, timeout, callback,
3736                 state);
3737         }
3738
3739         internal static IAsyncResult BeginCloseReplySessionChannel(
3740             ReliableChannelBinder<IReplySessionChannel> binder, IReplySessionChannel channel,
3741             TimeSpan timeout, AsyncCallback callback, object state)
3742         {
3743             return new CloseReplySessionChannelAsyncResult(binder, channel, timeout, callback,
3744                 state);
3745         }
3746
3747         internal static void CloseDuplexSessionChannel(
3748             ReliableChannelBinder<IDuplexSessionChannel> binder, IDuplexSessionChannel channel,
3749             TimeSpan timeout)
3750         {
3751             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
3752
3753             channel.Session.CloseOutputSession(timeoutHelper.RemainingTime());
3754             binder.WaitForPendingOperations(timeoutHelper.RemainingTime());
3755
3756             TimeSpan iterationTimeout = timeoutHelper.RemainingTime();
3757             bool lastIteration = (iterationTimeout == TimeSpan.Zero);
3758
3759             while (true)
3760             {
3761                 Message message = null;
3762                 bool receiveThrowing = true;
3763
3764                 try
3765                 {
3766                     bool success = channel.TryReceive(iterationTimeout, out message);
3767
3768                     receiveThrowing = false;
3769                     if (success && message == null)
3770                     {
3771                         channel.Close(timeoutHelper.RemainingTime());
3772                         return;
3773                     }
3774                 }
3775                 catch (Exception e)
3776                 {
3777                     if (Fx.IsFatal(e))
3778                         throw;
3779
3780                     if (receiveThrowing)
3781                     {
3782                         if (!MaskHandled(binder.DefaultMaskingMode) || !binder.IsHandleable(e))
3783                             throw;
3784
3785                         receiveThrowing = false;
3786                     }
3787                     else
3788                     {
3789                         throw;
3790                     }
3791                 }
3792                 finally
3793                 {
3794                     if (message != null)
3795                         message.Close();
3796
3797                     if (receiveThrowing)
3798                         channel.Abort();
3799                 }
3800
3801                 if (lastIteration || channel.State != CommunicationState.Opened)
3802                     break;
3803
3804                 iterationTimeout = timeoutHelper.RemainingTime();
3805                 lastIteration = (iterationTimeout == TimeSpan.Zero);
3806             }
3807
3808             channel.Abort();
3809         }
3810
3811         internal static void CloseReplySessionChannel(
3812             ReliableChannelBinder<IReplySessionChannel> binder, IReplySessionChannel channel,
3813             TimeSpan timeout)
3814         {
3815             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
3816
3817             binder.WaitForPendingOperations(timeoutHelper.RemainingTime());
3818
3819             TimeSpan iterationTimeout = timeoutHelper.RemainingTime();
3820             bool lastIteration = (iterationTimeout == TimeSpan.Zero);
3821
3822             while (true)
3823             {
3824                 RequestContext context = null;
3825                 bool receiveThrowing = true;
3826
3827                 try
3828                 {
3829                     bool success = channel.TryReceiveRequest(iterationTimeout, out context);
3830
3831                     receiveThrowing = false;
3832                     if (success && context == null)
3833                     {
3834                         channel.Close(timeoutHelper.RemainingTime());
3835                         return;
3836                     }
3837                 }
3838                 catch (Exception e)
3839                 {
3840                     if (Fx.IsFatal(e))
3841                         throw;
3842
3843                     if (receiveThrowing)
3844                     {
3845                         if (!MaskHandled(binder.DefaultMaskingMode) || !binder.IsHandleable(e))
3846                             throw;
3847
3848                         receiveThrowing = false;
3849                     }
3850                     else
3851                     {
3852                         throw;
3853                     }
3854                 }
3855                 finally
3856                 {
3857                     if (context != null)
3858                     {
3859                         context.RequestMessage.Close();
3860                         context.Close();
3861                     }
3862
3863                     if (receiveThrowing)
3864                         channel.Abort();
3865                 }
3866
3867                 if (lastIteration || channel.State != CommunicationState.Opened)
3868                     break;
3869
3870                 iterationTimeout = timeoutHelper.RemainingTime();
3871                 lastIteration = (iterationTimeout == TimeSpan.Zero);
3872             }
3873
3874             channel.Abort();
3875         }
3876
3877         internal static void EndCloseDuplexSessionChannel(IDuplexSessionChannel channel,
3878                 IAsyncResult result)
3879         {
3880             CloseDuplexSessionChannelAsyncResult.End(result);
3881         }
3882
3883         internal static void EndCloseReplySessionChannel(IReplySessionChannel channel,
3884                 IAsyncResult result)
3885         {
3886             CloseReplySessionChannelAsyncResult.End(result);
3887         }
3888
3889         internal static bool MaskHandled(MaskingMode maskingMode)
3890         {
3891             return (maskingMode & MaskingMode.Handled) == MaskingMode.Handled;
3892         }
3893
3894         internal static bool MaskUnhandled(MaskingMode maskingMode)
3895         {
3896             return (maskingMode & MaskingMode.Unhandled) == MaskingMode.Unhandled;
3897         }
3898
3899         abstract class CloseInputSessionChannelAsyncResult<TChannel, TItem> : AsyncResult
3900             where TChannel : class, IChannel
3901             where TItem : class
3902         {
3903             static AsyncCallback onChannelCloseCompleteStatic =
3904                 Fx.ThunkCallback(
3905                 new AsyncCallback(OnChannelCloseCompleteStatic));
3906             static AsyncCallback onInputCompleteStatic =
3907                 Fx.ThunkCallback(new AsyncCallback(OnInputCompleteStatic));
3908             static AsyncCallback onWaitForPendingOperationsCompleteStatic =
3909                 Fx.ThunkCallback(
3910                 new AsyncCallback(OnWaitForPendingOperationsCompleteStatic));
3911             ReliableChannelBinder<TChannel> binder;
3912             TChannel channel;
3913             bool lastReceive;
3914             TimeoutHelper timeoutHelper;
3915
3916             protected CloseInputSessionChannelAsyncResult(
3917                 ReliableChannelBinder<TChannel> binder, TChannel channel,
3918                 TimeSpan timeout, AsyncCallback callback, object state)
3919                 : base(callback, state)
3920             {
3921                 this.binder = binder;
3922                 this.channel = channel;
3923                 this.timeoutHelper = new TimeoutHelper(timeout);
3924             }
3925
3926             protected TChannel Channel
3927             {
3928                 get
3929                 {
3930                     return this.channel;
3931                 }
3932             }
3933
3934             protected TimeSpan RemainingTime
3935             {
3936                 get
3937                 {
3938                     return this.timeoutHelper.RemainingTime();
3939                 }
3940             }
3941
3942             protected bool Begin()
3943             {
3944                 bool complete = false;
3945                 IAsyncResult result = this.binder.BeginWaitForPendingOperations(
3946                     this.RemainingTime, onWaitForPendingOperationsCompleteStatic,
3947                     this);
3948
3949                 if (result.CompletedSynchronously)
3950                     complete = this.HandleWaitForPendingOperationsComplete(result);
3951
3952                 return complete;
3953             }
3954
3955             protected abstract IAsyncResult BeginTryInput(TimeSpan timeout, AsyncCallback callback,
3956                 object state);
3957
3958             protected abstract void DisposeItem(TItem item);
3959
3960             protected abstract bool EndTryInput(IAsyncResult result, out TItem item);
3961
3962             void HandleChannelCloseComplete(IAsyncResult result)
3963             {
3964                 this.channel.EndClose(result);
3965             }
3966
3967             bool HandleInputComplete(IAsyncResult result, out bool gotEof)
3968             {
3969                 TItem item = null;
3970                 bool endThrowing = true;
3971
3972                 gotEof = false;
3973
3974                 try
3975                 {
3976                     bool success = false;
3977
3978                     success = this.EndTryInput(result, out item);
3979                     endThrowing = false;
3980
3981                     if (!success || item != null)
3982                     {
3983                         if (this.lastReceive || this.channel.State != CommunicationState.Opened)
3984                         {
3985                             this.channel.Abort();
3986                             return true;
3987                         }
3988                         else
3989                         {
3990                             return false;
3991                         }
3992                     }
3993
3994                     gotEof = true;
3995
3996                     result = this.channel.BeginClose(this.RemainingTime,
3997                         onChannelCloseCompleteStatic, this);
3998                     if (result.CompletedSynchronously)
3999                     {
4000                         this.HandleChannelCloseComplete(result);
4001                         return true;
4002                     }
4003                     else
4004                     {
4005                         return false;
4006                     }
4007                 }
4008                 catch (Exception e)
4009                 {
4010                     if (Fx.IsFatal(e))
4011                         throw;
4012
4013                     if (endThrowing)
4014                     {
4015                         if (!MaskHandled(binder.DefaultMaskingMode) || !binder.IsHandleable(e))
4016                             throw;
4017
4018                         if (this.lastReceive || this.channel.State != CommunicationState.Opened)
4019                         {
4020                             this.channel.Abort();
4021                             return true;
4022                         }
4023                         else
4024                         {
4025                             return false;
4026                         }
4027                     }
4028
4029                     throw;
4030                 }
4031                 finally
4032                 {
4033                     if (item != null)
4034                         this.DisposeItem(item);
4035
4036                     if (endThrowing)
4037                         this.channel.Abort();
4038                 }
4039             }
4040
4041             bool HandleWaitForPendingOperationsComplete(IAsyncResult result)
4042             {
4043                 this.binder.EndWaitForPendingOperations(result);
4044                 return this.WaitForEof();
4045             }
4046
4047             static void OnChannelCloseCompleteStatic(IAsyncResult result)
4048             {
4049                 if (result.CompletedSynchronously)
4050                     return;
4051
4052                 CloseInputSessionChannelAsyncResult<TChannel, TItem> closeResult =
4053                     (CloseInputSessionChannelAsyncResult<TChannel, TItem>)result.AsyncState;
4054
4055                 Exception completeException = null;
4056
4057                 try
4058                 {
4059                     closeResult.HandleChannelCloseComplete(result);
4060                 }
4061                 catch (Exception e)
4062                 {
4063                     if (Fx.IsFatal(e))
4064                         throw;
4065
4066                     completeException = e;
4067                 }
4068
4069                 closeResult.Complete(false, completeException);
4070             }
4071
4072             static void OnInputCompleteStatic(IAsyncResult result)
4073             {
4074                 if (result.CompletedSynchronously)
4075                     return;
4076
4077                 CloseInputSessionChannelAsyncResult<TChannel, TItem> closeResult =
4078                     (CloseInputSessionChannelAsyncResult<TChannel, TItem>)result.AsyncState;
4079
4080                 bool complete = false;
4081                 Exception completeException = null;
4082
4083                 try
4084                 {
4085                     bool gotEof;
4086
4087                     complete = closeResult.HandleInputComplete(result, out gotEof);
4088                     if (!complete && !gotEof)
4089                         complete = closeResult.WaitForEof();
4090                 }
4091                 catch (Exception e)
4092                 {
4093                     if (Fx.IsFatal(e))
4094                         throw;
4095
4096                     completeException = e;
4097                 }
4098
4099                 if (complete || completeException != null)
4100                     closeResult.Complete(false, completeException);
4101             }
4102
4103             static void OnWaitForPendingOperationsCompleteStatic(IAsyncResult result)
4104             {
4105                 if (result.CompletedSynchronously)
4106                     return;
4107
4108                 CloseInputSessionChannelAsyncResult<TChannel, TItem> closeResult =
4109                     (CloseInputSessionChannelAsyncResult<TChannel, TItem>)result.AsyncState;
4110
4111                 bool complete = false;
4112                 Exception completeException = null;
4113
4114                 try
4115                 {
4116                     complete = closeResult.HandleWaitForPendingOperationsComplete(result);
4117                 }
4118                 catch (Exception e)
4119                 {
4120                     if (Fx.IsFatal(e))
4121                         throw;
4122
4123                     completeException = e;
4124                 }
4125
4126                 if (complete || completeException != null)
4127                     closeResult.Complete(false, completeException);
4128             }
4129
4130             bool WaitForEof()
4131             {
4132                 TimeSpan iterationTimeout = this.RemainingTime;
4133                 this.lastReceive = (iterationTimeout == TimeSpan.Zero);
4134
4135                 while (true)
4136                 {
4137                     IAsyncResult result = null;
4138
4139                     try
4140                     {
4141                         result = this.BeginTryInput(iterationTimeout, onInputCompleteStatic, this);
4142                     }
4143                     catch (Exception e)
4144                     {
4145                         if (Fx.IsFatal(e))
4146                             throw;
4147
4148                         if (!MaskHandled(this.binder.DefaultMaskingMode) || !this.binder.IsHandleable(e))
4149                             throw;
4150                     }
4151
4152                     if (result != null)
4153                     {
4154                         if (result.CompletedSynchronously)
4155                         {
4156                             bool gotEof;
4157                             bool complete = this.HandleInputComplete(result, out gotEof);
4158
4159                             if (complete || gotEof)
4160                                 return complete;
4161                         }
4162                         else
4163                             return false;
4164                     }
4165
4166                     if (this.lastReceive || this.channel.State != CommunicationState.Opened)
4167                     {
4168                         this.channel.Abort();
4169                         break;
4170                     }
4171
4172                     iterationTimeout = this.RemainingTime;
4173                     this.lastReceive = (iterationTimeout == TimeSpan.Zero);
4174                 }
4175
4176                 return true;
4177             }
4178         }
4179
4180         sealed class CloseDuplexSessionChannelAsyncResult :
4181             CloseInputSessionChannelAsyncResult<IDuplexSessionChannel, Message>
4182         {
4183             static AsyncCallback onCloseOutputSessionCompleteStatic =
4184                 Fx.ThunkCallback(
4185                 new AsyncCallback(OnCloseOutputSessionCompleteStatic));
4186
4187             public CloseDuplexSessionChannelAsyncResult(
4188                 ReliableChannelBinder<IDuplexSessionChannel> binder, IDuplexSessionChannel channel,
4189                 TimeSpan timeout, AsyncCallback callback, object state)
4190                 : base(binder, channel, timeout, callback, state)
4191             {
4192                 bool complete = false;
4193
4194                 IAsyncResult result = this.Channel.Session.BeginCloseOutputSession(
4195                     this.RemainingTime, onCloseOutputSessionCompleteStatic, this);
4196
4197                 if (result.CompletedSynchronously)
4198                     complete = this.HandleCloseOutputSessionComplete(result);
4199
4200                 if (complete)
4201                     this.Complete(true);
4202             }
4203
4204             protected override IAsyncResult BeginTryInput(TimeSpan timeout, AsyncCallback callback, object state)
4205             {
4206                 return this.Channel.BeginTryReceive(timeout, callback, state);
4207             }
4208
4209             protected override void DisposeItem(Message item)
4210             {
4211                 item.Close();
4212             }
4213
4214             public static void End(IAsyncResult result)
4215             {
4216                 AsyncResult.End<CloseDuplexSessionChannelAsyncResult>(result);
4217             }
4218
4219             protected override bool EndTryInput(IAsyncResult result, out Message item)
4220             {
4221                 return this.Channel.EndTryReceive(result, out item);
4222             }
4223
4224             bool HandleCloseOutputSessionComplete(IAsyncResult result)
4225             {
4226                 this.Channel.Session.EndCloseOutputSession(result);
4227                 return this.Begin();
4228             }
4229
4230             static void OnCloseOutputSessionCompleteStatic(IAsyncResult result)
4231             {
4232                 if (result.CompletedSynchronously)
4233                     return;
4234
4235                 CloseDuplexSessionChannelAsyncResult closeResult =
4236                     (CloseDuplexSessionChannelAsyncResult)result.AsyncState;
4237
4238                 bool complete = false;
4239                 Exception completeException = null;
4240
4241                 try
4242                 {
4243                     complete = closeResult.HandleCloseOutputSessionComplete(result);
4244                 }
4245                 catch (Exception e)
4246                 {
4247                     if (Fx.IsFatal(e))
4248                         throw;
4249
4250                     completeException = e;
4251                 }
4252
4253                 if (complete || completeException != null)
4254                     closeResult.Complete(false, completeException);
4255             }
4256         }
4257
4258         sealed class CloseReplySessionChannelAsyncResult :
4259             CloseInputSessionChannelAsyncResult<IReplySessionChannel, RequestContext>
4260         {
4261             public CloseReplySessionChannelAsyncResult(
4262                 ReliableChannelBinder<IReplySessionChannel> binder, IReplySessionChannel channel,
4263                 TimeSpan timeout, AsyncCallback callback, object state)
4264                 : base(binder, channel, timeout, callback, state)
4265             {
4266                 if (this.Begin())
4267                     this.Complete(true);
4268             }
4269
4270             protected override IAsyncResult BeginTryInput(TimeSpan timeout, AsyncCallback callback, object state)
4271             {
4272                 return this.Channel.BeginTryReceiveRequest(timeout, callback, state);
4273             }
4274
4275             protected override void DisposeItem(RequestContext item)
4276             {
4277                 item.RequestMessage.Close();
4278                 item.Close();
4279             }
4280
4281             public static void End(IAsyncResult result)
4282             {
4283                 AsyncResult.End<CloseReplySessionChannelAsyncResult>(result);
4284             }
4285
4286             protected override bool EndTryInput(IAsyncResult result, out RequestContext item)
4287             {
4288                 return this.Channel.EndTryReceiveRequest(result, out item);
4289             }
4290         }
4291     }
4292 }