diff options
Diffstat (limited to 'src/csharp/GrpcCore/Internal/CallSafeHandle.cs')
-rw-r--r-- | src/csharp/GrpcCore/Internal/CallSafeHandle.cs | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/src/csharp/GrpcCore/Internal/CallSafeHandle.cs b/src/csharp/GrpcCore/Internal/CallSafeHandle.cs new file mode 100644 index 0000000000..6c9c58a4c3 --- /dev/null +++ b/src/csharp/GrpcCore/Internal/CallSafeHandle.cs @@ -0,0 +1,182 @@ +using System; +using System.Runtime.InteropServices; +using System.Diagnostics; +using Google.GRPC.Core; + +namespace Google.GRPC.Core.Internal +{ + // TODO: we need to make sure that the delegates are not collected before invoked. + internal delegate void EventCallbackDelegate(IntPtr eventPtr); + + /// <summary> + /// grpc_call from <grpc/grpc.h> + /// </summary> + internal class CallSafeHandle : SafeHandleZeroIsInvalid + { + const UInt32 GRPC_WRITE_BUFFER_HINT = 1; + + [DllImport("libgrpc.so")] + static extern CallSafeHandle grpc_channel_create_call_old(ChannelSafeHandle channel, string method, string host, Timespec deadline); + + [DllImport("libgrpc.so")] + static extern GRPCCallError grpc_call_add_metadata(CallSafeHandle call, IntPtr metadata, UInt32 flags); + + [DllImport("libgrpc.so")] + static extern GRPCCallError grpc_call_invoke_old(CallSafeHandle call, CompletionQueueSafeHandle cq, IntPtr metadataReadTag, IntPtr finishedTag, UInt32 flags); + + [DllImport("libgrpc.so", EntryPoint = "grpc_call_invoke_old")] + static extern GRPCCallError grpc_call_invoke_old_CALLBACK(CallSafeHandle call, CompletionQueueSafeHandle cq, + [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate metadataReadCallback, + [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate finishedCallback, + UInt32 flags); + + [DllImport("libgrpc.so")] + static extern GRPCCallError grpc_call_server_accept_old(CallSafeHandle call, CompletionQueueSafeHandle completionQueue, IntPtr finishedTag); + + [DllImport("libgrpc.so", EntryPoint = "grpc_call_server_accept_old")] + static extern GRPCCallError grpc_call_server_accept_old_CALLBACK(CallSafeHandle call, CompletionQueueSafeHandle completionQueue, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate finishedCallback); + + [DllImport("libgrpc.so")] + static extern GRPCCallError grpc_call_server_end_initial_metadata_old(CallSafeHandle call, UInt32 flags); + + [DllImport("libgrpc.so")] + static extern GRPCCallError grpc_call_cancel(CallSafeHandle call); + + [DllImport("libgrpc.so")] + static extern GRPCCallError grpc_call_cancel_with_status(CallSafeHandle call, StatusCode status, string description); + + [DllImport("libgrpc.so")] + static extern GRPCCallError grpc_call_start_write_status_old(CallSafeHandle call, StatusCode statusCode, string statusMessage, IntPtr tag); + + [DllImport("libgrpc.so", EntryPoint = "grpc_call_start_write_status_old")] + static extern GRPCCallError grpc_call_start_write_status_old_CALLBACK(CallSafeHandle call, StatusCode statusCode, string statusMessage, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback); + + [DllImport("libgrpc.so")] + static extern GRPCCallError grpc_call_writes_done_old(CallSafeHandle call, IntPtr tag); + + [DllImport("libgrpc.so", EntryPoint = "grpc_call_writes_done_old")] + static extern GRPCCallError grpc_call_writes_done_old_CALLBACK(CallSafeHandle call, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback); + + [DllImport("libgrpc.so")] + static extern GRPCCallError grpc_call_start_read_old(CallSafeHandle call, IntPtr tag); + + [DllImport("libgrpc.so", EntryPoint = "grpc_call_start_read_old")] + static extern GRPCCallError grpc_call_start_read_old_CALLBACK(CallSafeHandle call, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback); + + [DllImport("libgrpc_csharp_ext.so")] + static extern void grpc_call_start_write_from_copied_buffer(CallSafeHandle call, + byte[] buffer, UIntPtr length, + IntPtr tag, UInt32 flags); + + [DllImport("libgrpc_csharp_ext.so", EntryPoint = "grpc_call_start_write_from_copied_buffer")] + static extern void grpc_call_start_write_from_copied_buffer_CALLBACK(CallSafeHandle call, + byte[] buffer, UIntPtr length, + [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback, + UInt32 flags); + + [DllImport("libgrpc.so")] + static extern void grpc_call_destroy(IntPtr call); + + private CallSafeHandle() + { + } + + /// <summary> + /// Creates a client call. + /// </summary> + public static CallSafeHandle Create(ChannelSafeHandle channel, string method, string host, Timespec deadline) + { + return grpc_channel_create_call_old(channel, method, host, deadline); + } + + public void Invoke(CompletionQueueSafeHandle cq, IntPtr metadataReadTag, IntPtr finishedTag, bool buffered) + { + AssertCallOk(grpc_call_invoke_old(this, cq, metadataReadTag, finishedTag, GetFlags(buffered))); + } + + public void Invoke(CompletionQueueSafeHandle cq, bool buffered, EventCallbackDelegate metadataReadCallback, EventCallbackDelegate finishedCallback) + { + AssertCallOk(grpc_call_invoke_old_CALLBACK(this, cq, metadataReadCallback, finishedCallback, GetFlags(buffered))); + } + + public void ServerAccept(CompletionQueueSafeHandle cq, IntPtr finishedTag) + { + AssertCallOk(grpc_call_server_accept_old(this, cq, finishedTag)); + } + + public void ServerAccept(CompletionQueueSafeHandle cq, EventCallbackDelegate callback) + { + AssertCallOk(grpc_call_server_accept_old_CALLBACK(this, cq, callback)); + } + + public void ServerEndInitialMetadata(UInt32 flags) + { + AssertCallOk(grpc_call_server_end_initial_metadata_old(this, flags)); + } + + public void StartWrite(byte[] payload, IntPtr tag, bool buffered) + { + grpc_call_start_write_from_copied_buffer(this, payload, new UIntPtr((ulong) payload.Length), tag, GetFlags(buffered)); + } + + public void StartWrite(byte[] payload, bool buffered, EventCallbackDelegate callback) + { + grpc_call_start_write_from_copied_buffer_CALLBACK(this, payload, new UIntPtr((ulong) payload.Length), callback, GetFlags(buffered)); + } + + public void StartWriteStatus(Status status, IntPtr tag) + { + AssertCallOk(grpc_call_start_write_status_old(this, status.StatusCode, status.Detail, tag)); + } + + public void StartWriteStatus(Status status, EventCallbackDelegate callback) + { + AssertCallOk(grpc_call_start_write_status_old_CALLBACK(this, status.StatusCode, status.Detail, callback)); + } + + public void WritesDone(IntPtr tag) + { + AssertCallOk(grpc_call_writes_done_old(this, tag)); + } + + public void WritesDone(EventCallbackDelegate callback) + { + AssertCallOk(grpc_call_writes_done_old_CALLBACK(this, callback)); + } + + public void StartRead(IntPtr tag) + { + AssertCallOk(grpc_call_start_read_old(this, tag)); + } + + public void StartRead(EventCallbackDelegate callback) + { + AssertCallOk(grpc_call_start_read_old_CALLBACK(this, callback)); + } + + public void Cancel() + { + AssertCallOk(grpc_call_cancel(this)); + } + + public void CancelWithStatus(Status status) + { + AssertCallOk(grpc_call_cancel_with_status(this, status.StatusCode, status.Detail)); + } + + protected override bool ReleaseHandle() + { + grpc_call_destroy(handle); + return true; + } + + private static void AssertCallOk(GRPCCallError callError) + { + Trace.Assert(callError == GRPCCallError.GRPC_CALL_OK, "Status not GRPC_CALL_OK"); + } + + private static UInt32 GetFlags(bool buffered) { + return buffered ? 0 : GRPC_WRITE_BUFFER_HINT; + } + } +}
\ No newline at end of file |