From a610e32e4b07d860048d478e2f2c851c7c9bb4d6 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 13 Sep 2016 16:53:05 +0200 Subject: throw correct exception failed writes --- src/csharp/Grpc.Core/Internal/AsyncCallBase.cs | 32 ++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'src/csharp/Grpc.Core/Internal/AsyncCallBase.cs') diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs index eb9c3ea62d..b27baba942 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs @@ -68,6 +68,7 @@ namespace Grpc.Core.Internal protected TaskCompletionSource streamingReadTcs; // Completion of a pending streaming read if not null. protected TaskCompletionSource streamingWriteTcs; // Completion of a pending streaming write or send close from client if not null. + protected TaskCompletionSource delayedStreamingWriteTcs; protected TaskCompletionSource sendStatusFromServerTcs; protected bool readingDone; // True if last read (i.e. read with null payload) was already received. @@ -200,6 +201,12 @@ namespace Grpc.Core.Internal get; } + /// + /// Returns an exception to throw for a failed send operation. + /// It is only allowed to call this method for a call that has already finished. + /// + protected abstract Exception GetRpcExceptionClientOnly(); + private void ReleaseResources() { if (call != null) @@ -252,18 +259,39 @@ namespace Grpc.Core.Internal /// protected void HandleSendFinished(bool success) { + bool delayCompletion = false; TaskCompletionSource origTcs = null; lock (myLock) { origTcs = streamingWriteTcs; streamingWriteTcs = null; + if (!success && !finished && IsClient) + { + // We should be setting this only once per call, following writes will be short circuited. + GrpcPreconditions.CheckState (delayedStreamingWriteTcs == null); + delayedStreamingWriteTcs = origTcs; + delayCompletion = true; + } + ReleaseResourcesIfPossible(); } if (!success) { - origTcs.SetException(new InvalidOperationException("Send failed")); + if (!delayCompletion) + { + if (IsClient) + { + GrpcPreconditions.CheckState(finished); // implied by !success && !delayCompletion && IsClient + origTcs.SetException(GetRpcExceptionClientOnly()); + } + else + { + origTcs.SetException (new IOException("Error sending from server.")); + } + } + // if delayCompletion == true, postpone SetException until call finishes. } else { @@ -283,7 +311,7 @@ namespace Grpc.Core.Internal if (!success) { - sendStatusFromServerTcs.SetException(new InvalidOperationException("Error sending status from server.")); + sendStatusFromServerTcs.SetException(new IOException("Error sending status from server.")); } else { -- cgit v1.2.3