1 //---------------------------------------------------------------------------- 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //---------------------------------------------------------------------------- 4 namespace System.ServiceModel.Channels 5 { 6 using System.Runtime; 7 using System.Threading; 8 using System.Xml; 9 BeginSendHandler(MessageAttemptInfo attemptInfo, TimeSpan timeout, bool maskUnhandledException, AsyncCallback asyncCallback, object state)10 delegate IAsyncResult BeginSendHandler(MessageAttemptInfo attemptInfo, TimeSpan timeout, bool maskUnhandledException, AsyncCallback asyncCallback, object state); EndSendHandler(IAsyncResult result)11 delegate void EndSendHandler(IAsyncResult result); SendHandler(MessageAttemptInfo attemptInfo, TimeSpan timeout, bool maskUnhandledException)12 delegate void SendHandler(MessageAttemptInfo attemptInfo, TimeSpan timeout, bool maskUnhandledException); ComponentFaultedHandler(Exception faultException, WsrmFault fault)13 delegate void ComponentFaultedHandler(Exception faultException, WsrmFault fault); ComponentExceptionHandler(Exception exception)14 delegate void ComponentExceptionHandler(Exception exception); RetryHandler(MessageAttemptInfo attemptInfo)15 delegate void RetryHandler(MessageAttemptInfo attemptInfo); 16 17 sealed class ReliableOutputConnection 18 { 19 BeginSendHandler beginSendHandler; 20 OperationWithTimeoutBeginCallback beginSendAckRequestedHandler; 21 bool closed = false; 22 EndSendHandler endSendHandler; 23 OperationEndCallback endSendAckRequestedHandler; 24 UniqueId id; 25 MessageVersion messageVersion; 26 object mutex = new Object(); 27 static AsyncCallback onSendRetriesComplete = Fx.ThunkCallback(new AsyncCallback(OnSendRetriesComplete)); 28 static AsyncCallback onSendRetryComplete = Fx.ThunkCallback(new AsyncCallback(OnSendRetryComplete)); 29 ReliableMessagingVersion reliableMessagingVersion; 30 Guard sendGuard = new Guard(Int32.MaxValue); 31 SendHandler sendHandler; 32 OperationWithTimeoutCallback sendAckRequestedHandler; 33 static Action<object> sendRetries = new Action<object>(SendRetries); 34 TimeSpan sendTimeout; 35 InterruptibleWaitObject shutdownHandle = new InterruptibleWaitObject(false); 36 TransmissionStrategy strategy; 37 bool terminated = false; 38 ReliableOutputConnection(UniqueId id, int maxTransferWindowSize, MessageVersion messageVersion, ReliableMessagingVersion reliableMessagingVersion, TimeSpan initialRtt, bool requestAcks, TimeSpan sendTimeout)39 public ReliableOutputConnection(UniqueId id, 40 int maxTransferWindowSize, 41 MessageVersion messageVersion, 42 ReliableMessagingVersion reliableMessagingVersion, 43 TimeSpan initialRtt, 44 bool requestAcks, 45 TimeSpan sendTimeout) 46 { 47 this.id = id; 48 this.messageVersion = messageVersion; 49 this.reliableMessagingVersion = reliableMessagingVersion; 50 this.sendTimeout = sendTimeout; 51 this.strategy = new TransmissionStrategy(reliableMessagingVersion, initialRtt, maxTransferWindowSize, 52 requestAcks, id); 53 this.strategy.RetryTimeoutElapsed = OnRetryTimeoutElapsed; 54 this.strategy.OnException = RaiseOnException; 55 } 56 57 public ComponentFaultedHandler Faulted; 58 public ComponentExceptionHandler OnException; 59 60 MessageVersion MessageVersion 61 { 62 get 63 { 64 return this.messageVersion; 65 } 66 } 67 68 public BeginSendHandler BeginSendHandler 69 { 70 set 71 { 72 this.beginSendHandler = value; 73 } 74 } 75 76 public OperationWithTimeoutBeginCallback BeginSendAckRequestedHandler 77 { 78 set 79 { 80 this.beginSendAckRequestedHandler = value; 81 } 82 } 83 84 public bool Closed 85 { 86 get 87 { 88 return this.closed; 89 } 90 } 91 92 public EndSendHandler EndSendHandler 93 { 94 set 95 { 96 this.endSendHandler = value; 97 } 98 } 99 100 public OperationEndCallback EndSendAckRequestedHandler 101 { 102 set 103 { 104 this.endSendAckRequestedHandler = value; 105 } 106 } 107 108 public Int64 Last 109 { 110 get 111 { 112 return this.strategy.Last; 113 } 114 } 115 116 public SendHandler SendHandler 117 { 118 set 119 { 120 this.sendHandler = value; 121 } 122 } 123 124 public OperationWithTimeoutCallback SendAckRequestedHandler 125 { 126 set 127 { 128 this.sendAckRequestedHandler = value; 129 } 130 } 131 132 public TransmissionStrategy Strategy 133 { 134 get 135 { 136 return this.strategy; 137 } 138 } 139 140 object ThisLock 141 { 142 get { return this.mutex; } 143 } 144 Abort(ChannelBase channel)145 public void Abort(ChannelBase channel) 146 { 147 this.sendGuard.Abort(); 148 this.shutdownHandle.Abort(channel); 149 this.strategy.Abort(channel); 150 } 151 CompleteTransfer(TimeSpan timeout)152 void CompleteTransfer(TimeSpan timeout) 153 { 154 if (this.reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) 155 { 156 Message message = Message.CreateMessage(this.MessageVersion, WsrmFeb2005Strings.LastMessageAction); 157 message.Properties.AllowOutputBatching = false; 158 159 // Return value ignored. 160 this.InternalAddMessage(message, timeout, null, true); 161 } 162 else if (this.reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) 163 { 164 if (this.strategy.SetLast()) 165 { 166 this.shutdownHandle.Set(); 167 } 168 else 169 { 170 this.sendAckRequestedHandler(timeout); 171 } 172 } 173 else 174 { 175 throw Fx.AssertAndThrow("Unsupported version."); 176 } 177 } 178 AddMessage(Message message, TimeSpan timeout, object state)179 public bool AddMessage(Message message, TimeSpan timeout, object state) 180 { 181 return this.InternalAddMessage(message, timeout, state, false); 182 } 183 BeginAddMessage(Message message, TimeSpan timeout, object state, AsyncCallback callback, object asyncState)184 public IAsyncResult BeginAddMessage(Message message, TimeSpan timeout, object state, AsyncCallback callback, object asyncState) 185 { 186 return new AddAsyncResult(message, false, timeout, state, this, callback, asyncState); 187 } 188 EndAddMessage(IAsyncResult result)189 public bool EndAddMessage(IAsyncResult result) 190 { 191 return AddAsyncResult.End(result); 192 } 193 BeginCompleteTransfer(TimeSpan timeout, AsyncCallback callback, object state)194 IAsyncResult BeginCompleteTransfer(TimeSpan timeout, AsyncCallback callback, object state) 195 { 196 if (this.reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) 197 { 198 Message message = Message.CreateMessage(this.MessageVersion, WsrmFeb2005Strings.LastMessageAction); 199 message.Properties.AllowOutputBatching = false; 200 return new AddAsyncResult(message, true, timeout, null, this, callback, state); 201 } 202 else if (this.reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) 203 { 204 if (this.strategy.SetLast()) 205 { 206 this.shutdownHandle.Set(); 207 return new AlreadyCompletedTransferAsyncResult(callback, state); 208 } 209 else 210 { 211 return this.beginSendAckRequestedHandler(timeout, callback, state); 212 } 213 } 214 else 215 { 216 throw Fx.AssertAndThrow("Unsupported version."); 217 } 218 } 219 EndCompleteTransfer(IAsyncResult result)220 void EndCompleteTransfer(IAsyncResult result) 221 { 222 if (this.reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) 223 { 224 AddAsyncResult.End(result); 225 } 226 else if (this.reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) 227 { 228 AlreadyCompletedTransferAsyncResult completedResult = result as AlreadyCompletedTransferAsyncResult; 229 if (completedResult != null) 230 { 231 completedResult.End(); 232 } 233 else 234 { 235 this.endSendAckRequestedHandler(result); 236 } 237 } 238 else 239 { 240 throw Fx.AssertAndThrow("Unsupported version."); 241 } 242 } 243 BeginClose(TimeSpan timeout, AsyncCallback callback, object state)244 public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state) 245 { 246 bool completeTransfer = false; 247 248 lock (this.ThisLock) 249 { 250 completeTransfer = !this.closed; 251 this.closed = true; 252 } 253 254 OperationWithTimeoutBeginCallback[] beginCallbacks; 255 OperationEndCallback[] endCallbacks; 256 257 beginCallbacks = new OperationWithTimeoutBeginCallback[] { 258 completeTransfer ? this.BeginCompleteTransfer : default(OperationWithTimeoutBeginCallback), 259 this.shutdownHandle.BeginWait, 260 this.sendGuard.BeginClose, 261 this.beginSendAckRequestedHandler }; 262 263 endCallbacks = new OperationEndCallback[] { 264 completeTransfer ? this.EndCompleteTransfer : default(OperationEndCallback), 265 this.shutdownHandle.EndWait, 266 this.sendGuard.EndClose, 267 this.endSendAckRequestedHandler }; 268 269 return OperationWithTimeoutComposer.BeginComposeAsyncOperations(timeout, beginCallbacks, endCallbacks, callback, state); 270 } 271 CheckForTermination()272 public bool CheckForTermination() 273 { 274 return this.strategy.DoneTransmitting; 275 } 276 Close(TimeSpan timeout)277 public void Close(TimeSpan timeout) 278 { 279 bool completeTransfer = false; 280 281 lock (this.ThisLock) 282 { 283 completeTransfer = !this.closed; 284 this.closed = true; 285 } 286 287 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 288 289 if (completeTransfer) 290 { 291 this.CompleteTransfer(timeoutHelper.RemainingTime()); 292 } 293 294 this.shutdownHandle.Wait(timeoutHelper.RemainingTime()); 295 this.sendGuard.Close(timeoutHelper.RemainingTime()); 296 this.strategy.Close(); 297 } 298 CompleteSendRetries(IAsyncResult result)299 void CompleteSendRetries(IAsyncResult result) 300 { 301 while (true) 302 { 303 this.endSendHandler(result); 304 this.sendGuard.Exit(); 305 this.strategy.DequeuePending(); 306 307 if (this.sendGuard.Enter()) 308 { 309 MessageAttemptInfo attemptInfo = this.strategy.GetMessageInfoForRetry(true); 310 311 if (attemptInfo.Message == null) 312 { 313 break; 314 } 315 else 316 { 317 result = this.beginSendHandler(attemptInfo, this.sendTimeout, true, onSendRetriesComplete, this); 318 if (!result.CompletedSynchronously) 319 { 320 return; 321 } 322 } 323 } 324 else 325 { 326 return; 327 } 328 } 329 330 // We are here if there are no more messages to retry. 331 this.sendGuard.Exit(); 332 this.OnTransferComplete(); 333 } 334 CompleteSendRetry(IAsyncResult result)335 void CompleteSendRetry(IAsyncResult result) 336 { 337 try 338 { 339 this.endSendHandler(result); 340 } 341 finally 342 { 343 this.sendGuard.Exit(); 344 } 345 } 346 EndClose(IAsyncResult result)347 public void EndClose(IAsyncResult result) 348 { 349 OperationWithTimeoutComposer.EndComposeAsyncOperations(result); 350 this.strategy.Close(); 351 } 352 Fault(ChannelBase channel)353 public void Fault(ChannelBase channel) 354 { 355 this.sendGuard.Abort(); 356 this.shutdownHandle.Fault(channel); 357 this.strategy.Fault(channel); 358 } 359 InternalAddMessage(Message message, TimeSpan timeout, object state, bool isLast)360 bool InternalAddMessage(Message message, TimeSpan timeout, object state, bool isLast) 361 { 362 MessageAttemptInfo attemptInfo; 363 TimeoutHelper helper = new TimeoutHelper(timeout); 364 365 try 366 { 367 if (isLast) 368 { 369 if (state != null) 370 { 371 throw Fx.AssertAndThrow("The isLast overload does not take a state."); 372 } 373 374 attemptInfo = this.strategy.AddLast(message, helper.RemainingTime(), null); 375 } 376 else if (!this.strategy.Add(message, helper.RemainingTime(), state, out attemptInfo)) 377 { 378 return false; 379 } 380 } 381 catch (TimeoutException) 382 { 383 if (isLast) 384 this.RaiseFault(null, SequenceTerminatedFault.CreateCommunicationFault(this.id, SR.GetString(SR.SequenceTerminatedAddLastToWindowTimedOut), null)); 385 // else - RM does not fault the channel based on a timeout exception trying to add a sequenced message to the window. 386 387 throw; 388 } 389 catch (Exception e) 390 { 391 if (!Fx.IsFatal(e)) 392 this.RaiseFault(null, SequenceTerminatedFault.CreateCommunicationFault(this.id, SR.GetString(SR.SequenceTerminatedUnknownAddToWindowError), null)); 393 394 throw; 395 } 396 397 if (sendGuard.Enter()) 398 { 399 try 400 { 401 this.sendHandler(attemptInfo, helper.RemainingTime(), false); 402 } 403 catch (QuotaExceededException) 404 { 405 this.RaiseFault(null, SequenceTerminatedFault.CreateQuotaExceededFault(this.id)); 406 throw; 407 } 408 finally 409 { 410 this.sendGuard.Exit(); 411 } 412 } 413 414 return true; 415 } 416 IsFinalAckConsistent(SequenceRangeCollection ranges)417 public bool IsFinalAckConsistent(SequenceRangeCollection ranges) 418 { 419 return this.strategy.IsFinalAckConsistent(ranges); 420 } 421 OnRetryTimeoutElapsed(MessageAttemptInfo attemptInfo)422 void OnRetryTimeoutElapsed(MessageAttemptInfo attemptInfo) 423 { 424 if (this.sendGuard.Enter()) 425 { 426 IAsyncResult result = this.beginSendHandler(attemptInfo, this.sendTimeout, true, onSendRetryComplete, this); 427 428 if (result.CompletedSynchronously) 429 { 430 this.CompleteSendRetry(result); 431 } 432 } 433 } 434 OnSendRetryComplete(IAsyncResult result)435 static void OnSendRetryComplete(IAsyncResult result) 436 { 437 if (!result.CompletedSynchronously) 438 { 439 ReliableOutputConnection outputConnection = (ReliableOutputConnection)result.AsyncState; 440 441 try 442 { 443 outputConnection.CompleteSendRetry(result); 444 } 445 #pragma warning suppress 56500 // covered by FxCOP 446 catch (Exception e) 447 { 448 if (Fx.IsFatal(e)) 449 throw; 450 451 outputConnection.RaiseOnException(e); 452 } 453 } 454 } 455 OnSendRetriesComplete(IAsyncResult result)456 static void OnSendRetriesComplete(IAsyncResult result) 457 { 458 if (!result.CompletedSynchronously) 459 { 460 ReliableOutputConnection outputConnection = (ReliableOutputConnection)result.AsyncState; 461 462 try 463 { 464 outputConnection.CompleteSendRetries(result); 465 } 466 #pragma warning suppress 56500 // covered by FxCOP 467 catch (Exception e) 468 { 469 if (Fx.IsFatal(e)) 470 throw; 471 472 outputConnection.RaiseOnException(e); 473 } 474 } 475 } 476 OnTransferComplete()477 void OnTransferComplete() 478 { 479 this.strategy.DequeuePending(); 480 481 if (this.strategy.DoneTransmitting) 482 Terminate(); 483 } 484 ProcessTransferred(Int64 transferred, SequenceRangeCollection ranges, int quotaRemaining)485 public void ProcessTransferred(Int64 transferred, SequenceRangeCollection ranges, int quotaRemaining) 486 { 487 if (transferred < 0) 488 { 489 throw Fx.AssertAndThrow("Argument transferred must be a valid sequence number or 0 for protocol messages."); 490 } 491 492 bool invalidAck; 493 494 // ignored, TransmissionStrategy is being used to keep track of what must be re-sent. 495 // In the Request-Reply case this state may not align with acks. 496 bool inconsistentAck; 497 498 this.strategy.ProcessAcknowledgement(ranges, out invalidAck, out inconsistentAck); 499 invalidAck = (invalidAck || ((transferred != 0) && !ranges.Contains(transferred))); 500 501 if (!invalidAck) 502 { 503 if ((transferred > 0) && this.strategy.ProcessTransferred(transferred, quotaRemaining)) 504 { 505 ActionItem.Schedule(sendRetries, this); 506 } 507 else 508 { 509 this.OnTransferComplete(); 510 } 511 } 512 else 513 { 514 WsrmFault fault = new InvalidAcknowledgementFault(this.id, ranges); 515 RaiseFault(fault.CreateException(), fault); 516 } 517 } 518 ProcessTransferred(SequenceRangeCollection ranges, int quotaRemaining)519 public void ProcessTransferred(SequenceRangeCollection ranges, int quotaRemaining) 520 { 521 bool invalidAck; 522 bool inconsistentAck; 523 524 this.strategy.ProcessAcknowledgement(ranges, out invalidAck, out inconsistentAck); 525 526 if (!invalidAck && !inconsistentAck) 527 { 528 if (this.strategy.ProcessTransferred(ranges, quotaRemaining)) 529 { 530 ActionItem.Schedule(sendRetries, this); 531 } 532 else 533 { 534 this.OnTransferComplete(); 535 } 536 } 537 else 538 { 539 WsrmFault fault = new InvalidAcknowledgementFault(this.id, ranges); 540 RaiseFault(fault.CreateException(), fault); 541 } 542 } 543 RaiseFault(Exception faultException, WsrmFault fault)544 void RaiseFault(Exception faultException, WsrmFault fault) 545 { 546 ComponentFaultedHandler handler = this.Faulted; 547 548 if (handler != null) 549 handler(faultException, fault); 550 } 551 RaiseOnException(Exception exception)552 void RaiseOnException(Exception exception) 553 { 554 ComponentExceptionHandler handler = this.OnException; 555 556 if (handler != null) 557 handler(exception); 558 } 559 SendRetries()560 void SendRetries() 561 { 562 IAsyncResult result = null; 563 564 if (this.sendGuard.Enter()) 565 { 566 MessageAttemptInfo attemptInfo = this.strategy.GetMessageInfoForRetry(false); 567 568 if (attemptInfo.Message != null) 569 { 570 result = this.beginSendHandler(attemptInfo, this.sendTimeout, true, onSendRetriesComplete, this); 571 } 572 573 if (result != null) 574 { 575 if (result.CompletedSynchronously) 576 { 577 this.CompleteSendRetries(result); 578 } 579 } 580 else 581 { 582 this.sendGuard.Exit(); 583 this.OnTransferComplete(); 584 } 585 } 586 } 587 SendRetries(object state)588 static void SendRetries(object state) 589 { 590 ReliableOutputConnection outputConnection = (ReliableOutputConnection)state; 591 592 try 593 { 594 outputConnection.SendRetries(); 595 } 596 #pragma warning suppress 56500 // covered by FxCOP 597 catch (Exception e) 598 { 599 if (Fx.IsFatal(e)) 600 throw; 601 602 outputConnection.RaiseOnException(e); 603 } 604 } 605 Terminate()606 public void Terminate() 607 { 608 lock (this.ThisLock) 609 { 610 if (this.terminated) 611 return; 612 613 this.terminated = true; 614 } 615 616 this.shutdownHandle.Set(); 617 } 618 619 sealed class AddAsyncResult : AsyncResult 620 { 621 static AsyncCallback addCompleteStatic = Fx.ThunkCallback(new AsyncCallback(AddComplete)); 622 ReliableOutputConnection connection; 623 bool isLast; 624 static AsyncCallback sendCompleteStatic = Fx.ThunkCallback(new AsyncCallback(SendComplete)); 625 TimeoutHelper timeoutHelper; 626 bool validAdd; 627 AddAsyncResult(Message message, bool isLast, TimeSpan timeout, object state, ReliableOutputConnection connection, AsyncCallback callback, object asyncState)628 public AddAsyncResult(Message message, bool isLast, TimeSpan timeout, object state, 629 ReliableOutputConnection connection, AsyncCallback callback, object asyncState) 630 : base(callback, asyncState) 631 { 632 this.connection = connection; 633 this.timeoutHelper = new TimeoutHelper(timeout); 634 this.isLast = isLast; 635 636 bool complete = false; 637 IAsyncResult result; 638 639 try 640 { 641 if (isLast) 642 { 643 if (state != null) 644 { 645 throw Fx.AssertAndThrow("The isLast overload does not take a state."); 646 } 647 648 result = this.connection.strategy.BeginAddLast(message, this.timeoutHelper.RemainingTime(), state, addCompleteStatic, this); 649 } 650 else 651 { 652 result = this.connection.strategy.BeginAdd(message, this.timeoutHelper.RemainingTime(), state, addCompleteStatic, this); 653 } 654 } 655 catch (TimeoutException) 656 { 657 if (isLast) 658 this.connection.RaiseFault(null, SequenceTerminatedFault.CreateCommunicationFault(this.connection.id, SR.GetString(SR.SequenceTerminatedAddLastToWindowTimedOut), null)); 659 // else - RM does not fault the channel based on a timeout exception trying to add a sequenced message to the window. 660 661 throw; 662 } 663 catch (Exception e) 664 { 665 if (!Fx.IsFatal(e)) 666 this.connection.RaiseFault(null, SequenceTerminatedFault.CreateCommunicationFault(this.connection.id, SR.GetString(SR.SequenceTerminatedUnknownAddToWindowError), null)); 667 668 throw; 669 } 670 671 if (result.CompletedSynchronously) 672 complete = this.CompleteAdd(result); 673 674 if (complete) 675 this.Complete(true); 676 } 677 AddComplete(IAsyncResult result)678 static void AddComplete(IAsyncResult result) 679 { 680 if (!result.CompletedSynchronously) 681 { 682 AddAsyncResult addResult = (AddAsyncResult)result.AsyncState; 683 bool complete = false; 684 Exception completeException = null; 685 686 try 687 { 688 complete = addResult.CompleteAdd(result); 689 } 690 #pragma warning suppress 56500 // covered by FxCOP 691 catch (Exception e) 692 { 693 if (Fx.IsFatal(e)) 694 throw; 695 696 completeException = e; 697 } 698 699 if (complete || completeException != null) 700 addResult.Complete(false, completeException); 701 } 702 } 703 CompleteAdd(IAsyncResult result)704 bool CompleteAdd(IAsyncResult result) 705 { 706 MessageAttemptInfo attemptInfo = default(MessageAttemptInfo); 707 this.validAdd = true; 708 709 try 710 { 711 if (this.isLast) 712 { 713 attemptInfo = this.connection.strategy.EndAddLast(result); 714 } 715 else if (!this.connection.strategy.EndAdd(result, out attemptInfo)) 716 { 717 this.validAdd = false; 718 return true; 719 } 720 } 721 catch (TimeoutException) 722 { 723 if (this.isLast) 724 this.connection.RaiseFault(null, SequenceTerminatedFault.CreateCommunicationFault(this.connection.id, SR.GetString(SR.SequenceTerminatedAddLastToWindowTimedOut), null)); 725 // else - RM does not fault the channel based on a timeout exception trying to add a sequenced message to the window. 726 727 throw; 728 } 729 catch (Exception e) 730 { 731 if (!Fx.IsFatal(e)) 732 this.connection.RaiseFault(null, SequenceTerminatedFault.CreateCommunicationFault(this.connection.id, SR.GetString(SR.SequenceTerminatedUnknownAddToWindowError), null)); 733 734 throw; 735 } 736 737 if (this.connection.sendGuard.Enter()) 738 { 739 bool throwing = true; 740 741 try 742 { 743 result = this.connection.beginSendHandler(attemptInfo, this.timeoutHelper.RemainingTime(), false, sendCompleteStatic, this); 744 throwing = false; 745 } 746 catch (QuotaExceededException) 747 { 748 this.connection.RaiseFault(null, SequenceTerminatedFault.CreateQuotaExceededFault(this.connection.id)); 749 throw; 750 } 751 finally 752 { 753 if (throwing) 754 this.connection.sendGuard.Exit(); 755 } 756 } 757 else 758 { 759 return true; 760 } 761 762 if (result.CompletedSynchronously) 763 { 764 this.CompleteSend(result); 765 return true; 766 } 767 else 768 { 769 return false; 770 } 771 } 772 CompleteSend(IAsyncResult result)773 void CompleteSend(IAsyncResult result) 774 { 775 try 776 { 777 this.connection.endSendHandler(result); 778 } 779 catch (QuotaExceededException) 780 { 781 this.connection.RaiseFault(null, SequenceTerminatedFault.CreateQuotaExceededFault(this.connection.id)); 782 throw; 783 } 784 finally 785 { 786 this.connection.sendGuard.Exit(); 787 } 788 } 789 SendComplete(IAsyncResult result)790 static void SendComplete(IAsyncResult result) 791 { 792 if (!result.CompletedSynchronously) 793 { 794 AddAsyncResult addResult = (AddAsyncResult)result.AsyncState; 795 Exception completeException = null; 796 797 try 798 { 799 addResult.CompleteSend(result); 800 } 801 #pragma warning suppress 56500 // covered by FxCOP 802 catch (Exception e) 803 { 804 if (Fx.IsFatal(e)) 805 throw; 806 807 completeException = e; 808 } 809 810 addResult.Complete(false, completeException); 811 } 812 } 813 End(IAsyncResult result)814 public static bool End(IAsyncResult result) 815 { 816 AsyncResult.End<AddAsyncResult>(result); 817 return ((AddAsyncResult)result).validAdd; 818 } 819 } 820 821 class AlreadyCompletedTransferAsyncResult : CompletedAsyncResult 822 { AlreadyCompletedTransferAsyncResult(AsyncCallback callback, object state)823 public AlreadyCompletedTransferAsyncResult(AsyncCallback callback, object state) 824 : base(callback, state) 825 { 826 } 827 End()828 public void End() 829 { 830 AsyncResult.End<AlreadyCompletedTransferAsyncResult>(this); 831 } 832 } 833 } 834 } 835