aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/csharp/GrpcCore/Internal/CallSafeHandle.cs
blob: bbb830b3552c24a29237be4898a3f99bf00606fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
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("grpc.dll")]
        static extern CallSafeHandle grpc_channel_create_call_old(ChannelSafeHandle channel, string method, string host, Timespec deadline);

        [DllImport("grpc.dll")]
        static extern GRPCCallError grpc_call_add_metadata(CallSafeHandle call, IntPtr metadata, UInt32 flags);

        [DllImport("grpc.dll")]
        static extern GRPCCallError grpc_call_invoke_old(CallSafeHandle call, CompletionQueueSafeHandle cq, IntPtr metadataReadTag, IntPtr finishedTag, UInt32 flags);

        [DllImport("grpc.dll", 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("grpc.dll")]
        static extern GRPCCallError grpc_call_server_accept_old(CallSafeHandle call, CompletionQueueSafeHandle completionQueue, IntPtr finishedTag);

        [DllImport("grpc.dll", 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("grpc.dll")]
        static extern GRPCCallError grpc_call_server_end_initial_metadata_old(CallSafeHandle call, UInt32 flags);

        [DllImport("grpc.dll")]
        static extern GRPCCallError grpc_call_cancel(CallSafeHandle call);

        [DllImport("grpc.dll")]
        static extern GRPCCallError grpc_call_cancel_with_status(CallSafeHandle call, StatusCode status, string description);

        [DllImport("grpc.dll")]
        static extern GRPCCallError grpc_call_start_write_status_old(CallSafeHandle call, StatusCode statusCode, string statusMessage, IntPtr tag);

        [DllImport("grpc.dll", 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("grpc.dll")]
        static extern GRPCCallError grpc_call_writes_done_old(CallSafeHandle call, IntPtr tag);

        [DllImport("grpc.dll", EntryPoint = "grpc_call_writes_done_old")]
        static extern GRPCCallError grpc_call_writes_done_old_CALLBACK(CallSafeHandle call, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);

        [DllImport("grpc.dll")]
        static extern GRPCCallError grpc_call_start_read_old(CallSafeHandle call, IntPtr tag);

        [DllImport("grpc.dll", EntryPoint = "grpc_call_start_read_old")]
        static extern GRPCCallError grpc_call_start_read_old_CALLBACK(CallSafeHandle call, [MarshalAs(UnmanagedType.FunctionPtr)] EventCallbackDelegate callback);

        [DllImport("grpc_csharp_ext.dll")]
        static extern void grpc_call_start_write_from_copied_buffer(CallSafeHandle call,
                                                                    byte[] buffer, UIntPtr length,
                                                                    IntPtr tag, UInt32 flags);

        [DllImport("grpc_csharp_ext.dll", 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("grpc.dll")]
		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;
        }
	}
}