• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #endregion
18 
19 using System;
20 using System.Runtime.InteropServices;
21 using System.Text;
22 using Grpc.Core;
23 using Grpc.Core.Logging;
24 using Grpc.Core.Utils;
25 
26 namespace Grpc.Core.Internal
27 {
28     internal interface IOpCompletionCallback
29     {
OnComplete(bool success)30         void OnComplete(bool success);
31     }
32 
33     internal interface IBufferReader
34     {
35         int? TotalLength { get; }
36 
TryGetNextSlice(out Slice slice)37         bool TryGetNextSlice(out Slice slice);
38     }
39 
40     /// <summary>
41     /// grpcsharp_batch_context
42     /// </summary>
43     internal class BatchContextSafeHandle : SafeHandleZeroIsInvalid, IOpCompletionCallback, IPooledObject<BatchContextSafeHandle>, IBufferReader
44     {
45         static readonly NativeMethods Native = NativeMethods.Get();
46         static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<BatchContextSafeHandle>();
47 
48         Action<BatchContextSafeHandle> returnToPoolAction;
49         CompletionCallbackData completionCallbackData;
50 
BatchContextSafeHandle()51         private BatchContextSafeHandle()
52         {
53         }
54 
Create()55         public static BatchContextSafeHandle Create()
56         {
57             var ctx = Native.grpcsharp_batch_context_create();
58             return ctx;
59         }
60 
61         public IntPtr Handle
62         {
63             get
64             {
65                 return handle;
66             }
67         }
68 
SetReturnToPoolAction(Action<BatchContextSafeHandle> returnAction)69         public void SetReturnToPoolAction(Action<BatchContextSafeHandle> returnAction)
70         {
71             GrpcPreconditions.CheckState(returnToPoolAction == null);
72             returnToPoolAction = returnAction;
73         }
74 
SetCompletionCallback(BatchCompletionDelegate callback, object state)75         public void SetCompletionCallback(BatchCompletionDelegate callback, object state)
76         {
77             GrpcPreconditions.CheckState(completionCallbackData.Callback == null);
78             GrpcPreconditions.CheckNotNull(callback, nameof(callback));
79             completionCallbackData = new CompletionCallbackData(callback, state);
80         }
81 
82         // Gets data of recv_initial_metadata completion.
GetReceivedInitialMetadata()83         public Metadata GetReceivedInitialMetadata()
84         {
85             IntPtr metadataArrayPtr = Native.grpcsharp_batch_context_recv_initial_metadata(this);
86             return MetadataArraySafeHandle.ReadMetadataFromPtrUnsafe(metadataArrayPtr);
87         }
88 
89         // Gets data of recv_status_on_client completion.
GetReceivedStatusOnClient()90         public ClientSideStatus GetReceivedStatusOnClient()
91         {
92             UIntPtr detailsLength;
93             IntPtr detailsPtr = Native.grpcsharp_batch_context_recv_status_on_client_details(this, out detailsLength);
94             string details = MarshalUtils.PtrToStringUTF8(detailsPtr, (int)detailsLength.ToUInt32());
95             string debugErrorString = Marshal.PtrToStringAnsi(Native.grpcsharp_batch_context_recv_status_on_client_error_string(this));
96             var status = new Status(Native.grpcsharp_batch_context_recv_status_on_client_status(this), details, debugErrorString != null ? new CoreErrorDetailException(debugErrorString) : null);
97 
98             IntPtr metadataArrayPtr = Native.grpcsharp_batch_context_recv_status_on_client_trailing_metadata(this);
99             var metadata = MetadataArraySafeHandle.ReadMetadataFromPtrUnsafe(metadataArrayPtr);
100 
101             return new ClientSideStatus(status, metadata);
102         }
103 
GetReceivedMessageReader()104         public IBufferReader GetReceivedMessageReader()
105         {
106             return this;
107         }
108 
109         // Gets data of receive_close_on_server completion.
GetReceivedCloseOnServerCancelled()110         public bool GetReceivedCloseOnServerCancelled()
111         {
112             return Native.grpcsharp_batch_context_recv_close_on_server_cancelled(this) != 0;
113         }
114 
Recycle()115         public void Recycle()
116         {
117             if (returnToPoolAction != null)
118             {
119                 Native.grpcsharp_batch_context_reset(this);
120 
121                 var origReturnAction = returnToPoolAction;
122                 // Not clearing all the references to the pool could prevent garbage collection of the pool object
123                 // and thus cause memory leaks.
124                 returnToPoolAction = null;
125                 origReturnAction(this);
126             }
127             else
128             {
129                 Dispose();
130             }
131         }
132 
ReleaseHandle()133         protected override bool ReleaseHandle()
134         {
135             Native.grpcsharp_batch_context_destroy(handle);
136             return true;
137         }
138 
IOpCompletionCallback.OnComplete(bool success)139         void IOpCompletionCallback.OnComplete(bool success)
140         {
141             try
142             {
143                 completionCallbackData.Callback(success, this, completionCallbackData.State);
144             }
145             catch (Exception e)
146             {
147                 Logger.Error(e, "Exception occurred while invoking batch completion delegate.");
148             }
149             finally
150             {
151                 completionCallbackData = default(CompletionCallbackData);
152                 Recycle();
153             }
154         }
155 
156         int? IBufferReader.TotalLength
157         {
158             get
159             {
160                 var len = Native.grpcsharp_batch_context_recv_message_length(this);
161                 return len != new IntPtr(-1) ? (int?) len : null;
162             }
163         }
164 
IBufferReader.TryGetNextSlice(out Slice slice)165         bool IBufferReader.TryGetNextSlice(out Slice slice)
166         {
167             UIntPtr sliceLen;
168             IntPtr sliceDataPtr;
169 
170             if (0 == Native.grpcsharp_batch_context_recv_message_next_slice_peek(this, out sliceLen, out sliceDataPtr))
171             {
172                 slice = default(Slice);
173                 return false;
174             }
175             slice = new Slice(sliceDataPtr, (int) sliceLen);
176             return true;
177         }
178 
179         struct CompletionCallbackData
180         {
CompletionCallbackDataGrpc.Core.Internal.BatchContextSafeHandle.CompletionCallbackData181             public CompletionCallbackData(BatchCompletionDelegate callback, object state)
182             {
183                 this.Callback = callback;
184                 this.State = state;
185             }
186 
187             public BatchCompletionDelegate Callback { get; }
188             public object State { get; }
189         }
190     }
191 }
192