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 Grpc.Core;
22 using Grpc.Core.Logging;
23 using Grpc.Core.Utils;
24 
25 namespace Grpc.Core.Internal
26 {
27     /// <summary>
28     /// grpcsharp_request_call_context
29     /// </summary>
30     internal class RequestCallContextSafeHandle : SafeHandleZeroIsInvalid, IOpCompletionCallback, IPooledObject<RequestCallContextSafeHandle>
31     {
32         static readonly NativeMethods Native = NativeMethods.Get();
33         static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<RequestCallContextSafeHandle>();
34         Action<RequestCallContextSafeHandle> returnToPoolAction;
35 
RequestCallContextSafeHandle()36         private RequestCallContextSafeHandle()
37         {
38         }
39 
Create()40         public static RequestCallContextSafeHandle Create()
41         {
42             var ctx = Native.grpcsharp_request_call_context_create();
43             return ctx;
44         }
45 
46         public IntPtr Handle
47         {
48             get
49             {
50                 return handle;
51             }
52         }
53 
SetReturnToPoolAction(Action<RequestCallContextSafeHandle> returnAction)54         public void SetReturnToPoolAction(Action<RequestCallContextSafeHandle> returnAction)
55         {
56             GrpcPreconditions.CheckState(returnToPoolAction == null);
57             returnToPoolAction = returnAction;
58         }
59 
60         public RequestCallCompletionDelegate CompletionCallback { get; set; }
61 
62         // Gets data of server_rpc_new completion.
GetServerRpcNew(Server server)63         public ServerRpcNew GetServerRpcNew(Server server)
64         {
65             var call = Native.grpcsharp_request_call_context_call(this);
66 
67             UIntPtr methodLen;
68             IntPtr methodPtr = Native.grpcsharp_request_call_context_method(this, out methodLen);
69             var method = Marshal.PtrToStringAnsi(methodPtr, (int) methodLen.ToUInt32());
70 
71             UIntPtr hostLen;
72             IntPtr hostPtr = Native.grpcsharp_request_call_context_host(this, out hostLen);
73             var host = Marshal.PtrToStringAnsi(hostPtr, (int) hostLen.ToUInt32());
74 
75             var deadline = Native.grpcsharp_request_call_context_deadline(this);
76 
77             IntPtr metadataArrayPtr = Native.grpcsharp_request_call_context_request_metadata(this);
78             var metadata = MetadataArraySafeHandle.ReadMetadataFromPtrUnsafe(metadataArrayPtr);
79 
80             return new ServerRpcNew(server, call, method, host, deadline, metadata);
81         }
82 
Recycle()83         public void Recycle()
84         {
85             if (returnToPoolAction != null)
86             {
87                 Native.grpcsharp_request_call_context_reset(this);
88 
89                 var origReturnAction = returnToPoolAction;
90                 // Not clearing all the references to the pool could prevent garbage collection of the pool object
91                 // and thus cause memory leaks.
92                 returnToPoolAction = null;
93                 origReturnAction(this);
94             }
95             else
96             {
97                 Dispose();
98             }
99         }
100 
ReleaseHandle()101         protected override bool ReleaseHandle()
102         {
103             Native.grpcsharp_request_call_context_destroy(handle);
104             return true;
105         }
106 
IOpCompletionCallback.OnComplete(bool success)107         void IOpCompletionCallback.OnComplete(bool success)
108         {
109             try
110             {
111                 CompletionCallback(success, this);
112             }
113             catch (Exception e)
114             {
115                 Logger.Error(e, "Exception occurred while invoking request call completion delegate.");
116             }
117             finally
118             {
119                 CompletionCallback = null;
120                 Recycle();
121             }
122         }
123     }
124 }
125