blob: 513902ee36484caff0da6ae019776d7dfc949682 [file] [log] [blame]
Jan Tattermuscha29d0f32015-03-04 17:54:56 -08001#region Copyright notice and license
2
3// Copyright 2015, Google Inc.
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32#endregion
33
34using System;
35using System.Diagnostics;
36using System.Runtime.CompilerServices;
37using System.Runtime.InteropServices;
38using System.Threading;
39using System.Threading.Tasks;
40using Grpc.Core.Internal;
41using Grpc.Core.Utils;
42
43namespace Grpc.Core.Internal
44{
45 /// <summary>
Jan Tattermuscha5272b62015-04-30 11:56:46 -070046 /// Manages server side native call lifecycle.
Jan Tattermuscha29d0f32015-03-04 17:54:56 -080047 /// </summary>
48 internal class AsyncCallServer<TRequest, TResponse> : AsyncCallBase<TResponse, TRequest>
49 {
Jan Tattermuscha29d0f32015-03-04 17:54:56 -080050 readonly TaskCompletionSource<object> finishedServersideTcs = new TaskCompletionSource<object>();
Jan Tattermusch0846b682015-07-23 17:02:12 -070051 readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
Jan Tattermusch04eb89c2015-06-12 13:03:05 -070052 readonly GrpcEnvironment environment;
Jan Tattermuscha29d0f32015-03-04 17:54:56 -080053
Jan Tattermusch04eb89c2015-06-12 13:03:05 -070054 public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer, GrpcEnvironment environment) : base(serializer, deserializer)
Jan Tattermuscha29d0f32015-03-04 17:54:56 -080055 {
Jan Tattermusch04eb89c2015-06-12 13:03:05 -070056 this.environment = Preconditions.CheckNotNull(environment);
Jan Tattermuscha29d0f32015-03-04 17:54:56 -080057 }
58
59 public void Initialize(CallSafeHandle call)
60 {
Jan Tattermusch04eb89c2015-06-12 13:03:05 -070061 call.SetCompletionRegistry(environment.CompletionRegistry);
62 environment.DebugStats.ActiveServerCalls.Increment();
Jan Tattermuscha29d0f32015-03-04 17:54:56 -080063 InitializeInternal(call);
64 }
65
66 /// <summary>
Jan Tattermuscha5272b62015-04-30 11:56:46 -070067 /// Starts a server side call.
Jan Tattermuscha29d0f32015-03-04 17:54:56 -080068 /// </summary>
Jan Tattermuscha5272b62015-04-30 11:56:46 -070069 public Task ServerSideCallAsync()
Jan Tattermuscha29d0f32015-03-04 17:54:56 -080070 {
71 lock (myLock)
72 {
73 Preconditions.CheckNotNull(call);
74
75 started = true;
Jan Tattermuscha29d0f32015-03-04 17:54:56 -080076
Jan Tattermuschd3677482015-06-01 19:27:40 -070077 call.StartServerSide(HandleFinishedServerside);
Jan Tattermuscha29d0f32015-03-04 17:54:56 -080078 return finishedServersideTcs.Task;
79 }
80 }
81
82 /// <summary>
83 /// Sends a streaming response. Only one pending send action is allowed at any given time.
84 /// completionDelegate is called when the operation finishes.
85 /// </summary>
Jan Tattermuscha5272b62015-04-30 11:56:46 -070086 public void StartSendMessage(TResponse msg, AsyncCompletionDelegate<object> completionDelegate)
Jan Tattermuscha29d0f32015-03-04 17:54:56 -080087 {
88 StartSendMessageInternal(msg, completionDelegate);
89 }
90
91 /// <summary>
Jan Tattermuscha5272b62015-04-30 11:56:46 -070092 /// Receives a streaming request. Only one pending read action is allowed at any given time.
93 /// completionDelegate is called when the operation finishes.
94 /// </summary>
95 public void StartReadMessage(AsyncCompletionDelegate<TRequest> completionDelegate)
96 {
97 StartReadMessageInternal(completionDelegate);
98 }
99
100 /// <summary>
Jan Tattermuscha29d0f32015-03-04 17:54:56 -0800101 /// Sends call result status, also indicating server is done with streaming responses.
102 /// Only one pending send action is allowed at any given time.
103 /// completionDelegate is called when the operation finishes.
104 /// </summary>
Jan Tattermuscha0bb0652015-07-20 22:34:19 -0700105 public void StartSendStatusFromServer(Status status, Metadata trailers, AsyncCompletionDelegate<object> completionDelegate)
Jan Tattermuscha29d0f32015-03-04 17:54:56 -0800106 {
107 lock (myLock)
108 {
109 Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null");
110 CheckSendingAllowed();
111
Jan Tattermuscha0bb0652015-07-20 22:34:19 -0700112 using (var metadataArray = MetadataArraySafeHandle.Create(trailers))
113 {
114 call.StartSendStatusFromServer(status, HandleHalfclosed, metadataArray);
115 }
Jan Tattermuscha29d0f32015-03-04 17:54:56 -0800116 halfcloseRequested = true;
Jan Tattermusch4ec975d2015-06-11 17:24:15 -0700117 readingDone = true;
Jan Tattermuscha29d0f32015-03-04 17:54:56 -0800118 sendCompletionDelegate = completionDelegate;
119 }
120 }
121
Jan Tattermusch0846b682015-07-23 17:02:12 -0700122 /// <summary>
123 /// Gets cancellation token that gets cancelled once close completion
124 /// is received and the cancelled flag is set.
125 /// </summary>
126 public CancellationToken CancellationToken
127 {
128 get
129 {
130 return cancellationTokenSource.Token;
131 }
132 }
133
Jan Tattermusch062c3292015-07-23 20:28:42 -0700134 public string Peer
135 {
136 get
137 {
138 return call.GetPeer();
139 }
140 }
141
Jan Tattermusch1b54fcf2015-05-01 14:30:16 -0700142 protected override void OnReleaseResources()
143 {
Jan Tattermusch04eb89c2015-06-12 13:03:05 -0700144 environment.DebugStats.ActiveServerCalls.Decrement();
Jan Tattermusch1b54fcf2015-05-01 14:30:16 -0700145 }
146
Jan Tattermuscha29d0f32015-03-04 17:54:56 -0800147 /// <summary>
148 /// Handles the server side close completion.
149 /// </summary>
Jan Tattermuschd3677482015-06-01 19:27:40 -0700150 private void HandleFinishedServerside(bool success, BatchContextSafeHandle ctx)
Jan Tattermuscha29d0f32015-03-04 17:54:56 -0800151 {
Jan Tattermusch8c2dd9d2015-05-04 09:20:43 -0700152 bool cancelled = ctx.GetReceivedCloseOnServerCancelled();
153
Jan Tattermuscha29d0f32015-03-04 17:54:56 -0800154 lock (myLock)
155 {
156 finished = true;
157
Jan Tattermusch8c2dd9d2015-05-04 09:20:43 -0700158 if (cancelled)
Jan Tattermusche5c44602015-05-01 11:12:34 -0700159 {
Jan Tattermusch8c2dd9d2015-05-04 09:20:43 -0700160 // Once we cancel, we don't have to care that much
161 // about reads and writes.
Jan Tattermusch0846b682015-07-23 17:02:12 -0700162
163 // TODO(jtattermusch): is this still necessary?
Jan Tattermusch8c2dd9d2015-05-04 09:20:43 -0700164 Cancel();
Jan Tattermusche5c44602015-05-01 11:12:34 -0700165 }
166
Jan Tattermuscha29d0f32015-03-04 17:54:56 -0800167 ReleaseResourcesIfPossible();
168 }
Jan Tattermusch9b9a8772015-05-06 14:43:51 -0700169 // TODO(jtattermusch): handle error
Jan Tattermuscha29d0f32015-03-04 17:54:56 -0800170
Jan Tattermusch0846b682015-07-23 17:02:12 -0700171 if (cancelled)
172 {
173 cancellationTokenSource.Cancel();
174 }
175
Jan Tattermuscha29d0f32015-03-04 17:54:56 -0800176 finishedServersideTcs.SetResult(null);
177 }
178 }
179}