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