• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 // Copyright 2015 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #endregion
17 using System;
18 using System.Diagnostics;
19 using System.Runtime.InteropServices;
20 using System.Text;
21 using Grpc.Core;
22 using Grpc.Core.Utils;
23 using Grpc.Core.Profiling;
24 
25 namespace Grpc.Core.Internal
26 {
27     /// <summary>
28     /// grpc_call from <c>grpc/grpc.h</c>
29     /// </summary>
30     internal class CallSafeHandle : SafeHandleZeroIsInvalid, INativeCall
31     {
32         public static readonly CallSafeHandle NullInstance = new CallSafeHandle();
33         static readonly NativeMethods Native = NativeMethods.Get();
34 
35         // Completion handlers are pre-allocated to avoid unneccessary delegate allocations.
36         // The "state" field is used to store the actual callback to invoke.
37         static readonly BatchCompletionDelegate CompletionHandler_IUnaryResponseClientCallback =
38             (success, context, state) => ((IUnaryResponseClientCallback)state).OnUnaryResponseClient(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata());
39         static readonly BatchCompletionDelegate CompletionHandler_IReceivedStatusOnClientCallback =
40             (success, context, state) => ((IReceivedStatusOnClientCallback)state).OnReceivedStatusOnClient(success, context.GetReceivedStatusOnClient());
41         static readonly BatchCompletionDelegate CompletionHandler_IReceivedMessageCallback =
42             (success, context, state) => ((IReceivedMessageCallback)state).OnReceivedMessage(success, context.GetReceivedMessage());
43         static readonly BatchCompletionDelegate CompletionHandler_IReceivedResponseHeadersCallback =
44             (success, context, state) => ((IReceivedResponseHeadersCallback)state).OnReceivedResponseHeaders(success, context.GetReceivedInitialMetadata());
45         static readonly BatchCompletionDelegate CompletionHandler_ISendCompletionCallback =
46             (success, context, state) => ((ISendCompletionCallback)state).OnSendCompletion(success);
47         static readonly BatchCompletionDelegate CompletionHandler_ISendStatusFromServerCompletionCallback =
48             (success, context, state) => ((ISendStatusFromServerCompletionCallback)state).OnSendStatusFromServerCompletion(success);
49         static readonly BatchCompletionDelegate CompletionHandler_IReceivedCloseOnServerCallback =
50             (success, context, state) => ((IReceivedCloseOnServerCallback)state).OnReceivedCloseOnServer(success, context.GetReceivedCloseOnServerCancelled());
51 
52         const uint GRPC_WRITE_BUFFER_HINT = 1;
53         CompletionQueueSafeHandle completionQueue;
54 
CallSafeHandle()55         private CallSafeHandle()
56         {
57         }
58 
Initialize(CompletionQueueSafeHandle completionQueue)59         public void Initialize(CompletionQueueSafeHandle completionQueue)
60         {
61             this.completionQueue = completionQueue;
62         }
63 
SetCredentials(CallCredentialsSafeHandle credentials)64         public void SetCredentials(CallCredentialsSafeHandle credentials)
65         {
66             Native.grpcsharp_call_set_credentials(this, credentials).CheckOk();
67         }
68 
StartUnary(IUnaryResponseClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)69         public void StartUnary(IUnaryResponseClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
70         {
71             using (completionQueue.NewScope())
72             {
73                 var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_IUnaryResponseClientCallback, callback);
74                 Native.grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, metadataArray, callFlags)
75                     .CheckOk();
76             }
77         }
78 
StartUnary(BatchContextSafeHandle ctx, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)79         public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
80         {
81             Native.grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, metadataArray, callFlags)
82                 .CheckOk();
83         }
84 
StartClientStreaming(IUnaryResponseClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)85         public void StartClientStreaming(IUnaryResponseClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
86         {
87             using (completionQueue.NewScope())
88             {
89                 var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_IUnaryResponseClientCallback, callback);
90                 Native.grpcsharp_call_start_client_streaming(this, ctx, metadataArray, callFlags).CheckOk();
91             }
92         }
93 
StartServerStreaming(IReceivedStatusOnClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)94         public void StartServerStreaming(IReceivedStatusOnClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
95         {
96             using (completionQueue.NewScope())
97             {
98                 var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_IReceivedStatusOnClientCallback, callback);
99                 Native.grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, metadataArray, callFlags).CheckOk();
100             }
101         }
102 
StartDuplexStreaming(IReceivedStatusOnClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)103         public void StartDuplexStreaming(IReceivedStatusOnClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
104         {
105             using (completionQueue.NewScope())
106             {
107                 var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_IReceivedStatusOnClientCallback, callback);
108                 Native.grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray, callFlags).CheckOk();
109             }
110         }
111 
StartSendMessage(ISendCompletionCallback callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata)112         public void StartSendMessage(ISendCompletionCallback callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata)
113         {
114             using (completionQueue.NewScope())
115             {
116                 var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_ISendCompletionCallback, callback);
117                 Native.grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, sendEmptyInitialMetadata ? 1 : 0).CheckOk();
118             }
119         }
120 
StartSendCloseFromClient(ISendCompletionCallback callback)121         public void StartSendCloseFromClient(ISendCompletionCallback callback)
122         {
123             using (completionQueue.NewScope())
124             {
125                 var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_ISendCompletionCallback, callback);
126                 Native.grpcsharp_call_send_close_from_client(this, ctx).CheckOk();
127             }
128         }
129 
StartSendStatusFromServer(ISendStatusFromServerCompletionCallback callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata, byte[] optionalPayload, WriteFlags writeFlags)130         public void StartSendStatusFromServer(ISendStatusFromServerCompletionCallback callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
131             byte[] optionalPayload, WriteFlags writeFlags)
132         {
133             using (completionQueue.NewScope())
134             {
135                 var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_ISendStatusFromServerCompletionCallback, callback);
136                 var optionalPayloadLength = optionalPayload != null ? new UIntPtr((ulong)optionalPayload.Length) : UIntPtr.Zero;
137                 var statusDetailBytes = MarshalUtils.GetBytesUTF8(status.Detail);
138                 Native.grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, statusDetailBytes, new UIntPtr((ulong)statusDetailBytes.Length), metadataArray, sendEmptyInitialMetadata ? 1 : 0,
139                     optionalPayload, optionalPayloadLength, writeFlags).CheckOk();
140             }
141         }
142 
StartReceiveMessage(IReceivedMessageCallback callback)143         public void StartReceiveMessage(IReceivedMessageCallback callback)
144         {
145             using (completionQueue.NewScope())
146             {
147                 var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_IReceivedMessageCallback, callback);
148                 Native.grpcsharp_call_recv_message(this, ctx).CheckOk();
149             }
150         }
151 
StartReceiveInitialMetadata(IReceivedResponseHeadersCallback callback)152         public void StartReceiveInitialMetadata(IReceivedResponseHeadersCallback callback)
153         {
154             using (completionQueue.NewScope())
155             {
156                 var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_IReceivedResponseHeadersCallback, callback);
157                 Native.grpcsharp_call_recv_initial_metadata(this, ctx).CheckOk();
158             }
159         }
160 
StartServerSide(IReceivedCloseOnServerCallback callback)161         public void StartServerSide(IReceivedCloseOnServerCallback callback)
162         {
163             using (completionQueue.NewScope())
164             {
165                 var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_IReceivedCloseOnServerCallback, callback);
166                 Native.grpcsharp_call_start_serverside(this, ctx).CheckOk();
167             }
168         }
169 
StartSendInitialMetadata(ISendCompletionCallback callback, MetadataArraySafeHandle metadataArray)170         public void StartSendInitialMetadata(ISendCompletionCallback callback, MetadataArraySafeHandle metadataArray)
171         {
172             using (completionQueue.NewScope())
173             {
174                 var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_ISendCompletionCallback, callback);
175                 Native.grpcsharp_call_send_initial_metadata(this, ctx, metadataArray).CheckOk();
176             }
177         }
178 
Cancel()179         public void Cancel()
180         {
181             Native.grpcsharp_call_cancel(this).CheckOk();
182         }
183 
CancelWithStatus(Status status)184         public void CancelWithStatus(Status status)
185         {
186             Native.grpcsharp_call_cancel_with_status(this, status.StatusCode, status.Detail).CheckOk();
187         }
188 
GetPeer()189         public string GetPeer()
190         {
191             using (var cstring = Native.grpcsharp_call_get_peer(this))
192             {
193                 return cstring.GetValue();
194             }
195         }
196 
GetAuthContext()197         public AuthContextSafeHandle GetAuthContext()
198         {
199             return Native.grpcsharp_call_auth_context(this);
200         }
201 
ReleaseHandle()202         protected override bool ReleaseHandle()
203         {
204             Native.grpcsharp_call_destroy(handle);
205             return true;
206         }
207 
GetFlags(bool buffered)208         private static uint GetFlags(bool buffered)
209         {
210             return buffered ? 0 : GRPC_WRITE_BUFFER_HINT;
211         }
212 
213         /// <summary>
214         /// Only for testing.
215         /// </summary>
CreateFake(IntPtr ptr, CompletionQueueSafeHandle cq)216         public static CallSafeHandle CreateFake(IntPtr ptr, CompletionQueueSafeHandle cq)
217         {
218             var call = new CallSafeHandle();
219             call.SetHandle(ptr);
220             call.Initialize(cq);
221             return call;
222         }
223     }
224 }
225