1 /*
2  *
3  * Copyright 2015, Google Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following disclaimer
14  * in the documentation and/or other materials provided with the
15  * distribution.
16  *     * Neither the name of Google Inc. nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  */
33 
34 // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
35 
36 // Because rust's union implementation is unstable and possibly buggy
37 // (rust-lang/rust#32836),
38 // so we need to wrap the type and expose more safer interfaces.
39 
40 #include <grpc/support/port_platform.h>
41 
42 #include <grpc/byte_buffer_reader.h>
43 #include <grpc/grpc.h>
44 #include <grpc/slice.h>
45 #include <grpc/support/alloc.h>
46 #include <grpc/support/log.h>
47 #include <grpc/support/string_util.h>
48 #include <grpc/support/thd_id.h>
49 
50 #ifdef GRPC_SYS_SECURE
51 #include <grpc/grpc_security.h>
52 #endif
53 
54 #include <string.h>
55 
56 #ifdef GPR_WINDOWS
57 #define GPR_EXPORT extern "C" __declspec(dllexport)
58 #define GPR_CALLTYPE __cdecl
59 #endif
60 
61 #ifndef GPR_EXPORT
62 #define GPR_EXPORT extern "C"
63 #endif
64 
65 #ifndef GPR_CALLTYPE
66 #define GPR_CALLTYPE
67 #endif
68 
string_to_byte_buffer(const char * buffer,size_t len)69 grpc_byte_buffer* string_to_byte_buffer(const char* buffer, size_t len) {
70   grpc_slice slice = grpc_slice_from_copied_buffer(buffer, len);
71   grpc_byte_buffer* bb = grpc_raw_byte_buffer_create(&slice, 1);
72   grpc_slice_unref(slice);
73   return bb;
74 }
75 
76 /*
77  * Helper to maintain lifetime of batch op inputs and store batch op outputs.
78  */
79 typedef struct grpcwrap_batch_context {
80   grpc_metadata_array send_initial_metadata;
81   grpc_byte_buffer* send_message;
82   struct {
83     grpc_metadata_array trailing_metadata;
84   } send_status_from_server;
85   grpc_metadata_array recv_initial_metadata;
86   grpc_byte_buffer* recv_message;
87   struct {
88     grpc_metadata_array trailing_metadata;
89     grpc_status_code status;
90     grpc_slice status_details;
91     const char* error_string;
92   } recv_status_on_client;
93   int recv_close_on_server_cancelled;
94 } grpcwrap_batch_context;
95 
96 GPR_EXPORT grpcwrap_batch_context* GPR_CALLTYPE
grpcwrap_batch_context_create()97 grpcwrap_batch_context_create() {
98   auto* ctx =
99       (grpcwrap_batch_context*)gpr_malloc(sizeof(grpcwrap_batch_context));
100   memset(ctx, 0, sizeof(grpcwrap_batch_context));
101   return ctx;
102 }
103 
104 typedef struct {
105   grpc_call* call;
106   grpc_call_details call_details;
107   grpc_metadata_array request_metadata;
108 } grpcwrap_request_call_context;
109 
110 GPR_EXPORT grpcwrap_request_call_context* GPR_CALLTYPE
grpcwrap_request_call_context_create()111 grpcwrap_request_call_context_create() {
112   auto* ctx = (grpcwrap_request_call_context*)gpr_malloc(
113       sizeof(grpcwrap_request_call_context));
114   memset(ctx, 0, sizeof(grpcwrap_request_call_context));
115   return ctx;
116 }
117 
118 /*
119  * Destroys array->metadata.
120  * The array pointer itself is not freed.
121  */
grpcwrap_metadata_array_destroy_metadata_only(grpc_metadata_array * array)122 GPR_EXPORT void grpcwrap_metadata_array_destroy_metadata_only(
123     grpc_metadata_array* array) {
124   gpr_free(array->metadata);
125 }
126 
127 /*
128  * Destroys keys, values and array->metadata.
129  * The array pointer itself is not freed.
130  */
grpcwrap_metadata_array_destroy_metadata_including_entries(grpc_metadata_array * array)131 GPR_EXPORT void grpcwrap_metadata_array_destroy_metadata_including_entries(
132     grpc_metadata_array* array) {
133   size_t i;
134   if (array->metadata) {
135     for (i = 0; i < array->count; i++) {
136       grpc_slice_unref(array->metadata[i].key);
137       grpc_slice_unref(array->metadata[i].value);
138     }
139   }
140   gpr_free(array->metadata);
141 }
142 
143 /*
144  * Fully destroys the metadata array.
145  */
146 GPR_EXPORT void GPR_CALLTYPE
grpcwrap_metadata_array_destroy_full(grpc_metadata_array * array)147 grpcwrap_metadata_array_destroy_full(grpc_metadata_array* array) {
148   if (!array) {
149     return;
150   }
151   grpcwrap_metadata_array_destroy_metadata_including_entries(array);
152   gpr_free(array);
153 }
154 
155 /*
156  * Allocate metadata array with given capacity.
157  */
158 GPR_EXPORT void GPR_CALLTYPE
grpcwrap_metadata_array_init(grpc_metadata_array * array,size_t capacity)159 grpcwrap_metadata_array_init(grpc_metadata_array* array, size_t capacity) {
160   array->count = 0;
161   array->capacity = capacity;
162   if (!capacity) {
163     array->metadata = nullptr;
164     return;
165   }
166 
167   auto* arr = (grpc_metadata*)gpr_malloc(sizeof(grpc_metadata) * capacity);
168   memset(arr, 0, sizeof(grpc_metadata) * capacity);
169   array->metadata = arr;
170 }
171 
grpcwrap_metadata_array_add(grpc_metadata_array * array,const char * key,size_t key_length,const char * value,size_t value_length)172 GPR_EXPORT void GPR_CALLTYPE grpcwrap_metadata_array_add(
173     grpc_metadata_array* array, const char* key, size_t key_length,
174     const char* value, size_t value_length) {
175   GPR_ASSERT(array->count <= array->capacity);
176   size_t i = array->count;
177   if (i == array->capacity) {
178     array->capacity = array->capacity ? array->capacity * 2 : 4;
179     array->metadata = (grpc_metadata*)gpr_realloc(
180         array->metadata, array->capacity * sizeof(grpc_metadata));
181     memset(array->metadata + i, 0,
182            sizeof(grpc_metadata) * (array->capacity - i));
183   }
184   array->metadata[i].key = grpc_slice_from_copied_buffer(key, key_length);
185   array->metadata[i].value = grpc_slice_from_copied_buffer(value, value_length);
186   array->count++;
187 }
188 
grpcwrap_metadata_array_get_key(const grpc_metadata_array * array,size_t index,size_t * key_length)189 GPR_EXPORT const char* GPR_CALLTYPE grpcwrap_metadata_array_get_key(
190     const grpc_metadata_array* array, size_t index, size_t* key_length) {
191   GPR_ASSERT(index < array->count);
192   *key_length = GRPC_SLICE_LENGTH(array->metadata[index].key);
193   return (char*)GRPC_SLICE_START_PTR(array->metadata[index].key);
194 }
195 
grpcwrap_metadata_array_get_value(const grpc_metadata_array * array,size_t index,size_t * value_length)196 GPR_EXPORT const char* GPR_CALLTYPE grpcwrap_metadata_array_get_value(
197     const grpc_metadata_array* array, size_t index, size_t* value_length) {
198   GPR_ASSERT(index < array->count);
199   *value_length = GRPC_SLICE_LENGTH(array->metadata[index].value);
200   return (char*)GRPC_SLICE_START_PTR(array->metadata[index].value);
201 }
202 
203 GPR_EXPORT void GPR_CALLTYPE
grpcwrap_metadata_array_cleanup(grpc_metadata_array * array)204 grpcwrap_metadata_array_cleanup(grpc_metadata_array* array) {
205   grpcwrap_metadata_array_destroy_metadata_including_entries(array);
206 }
207 
208 GPR_EXPORT void GPR_CALLTYPE
grpcwrap_metadata_array_shrink_to_fit(grpc_metadata_array * array)209 grpcwrap_metadata_array_shrink_to_fit(grpc_metadata_array* array) {
210   GPR_ASSERT(array->count <= array->capacity);
211   if (array->count == array->capacity) {
212     return;
213   }
214   if (array->count) {
215     array->metadata = (grpc_metadata*)gpr_realloc(
216         array->metadata, array->count * sizeof(grpc_metadata));
217     array->capacity = array->count;
218   } else {
219     grpcwrap_metadata_array_cleanup(array);
220     array->capacity = 0;
221     array->metadata = nullptr;
222   }
223 }
224 
225 /* Move contents of metadata array */
grpcwrap_metadata_array_move(grpc_metadata_array * dest,grpc_metadata_array * src)226 GPR_EXPORT void grpcwrap_metadata_array_move(grpc_metadata_array* dest,
227                                              grpc_metadata_array* src) {
228   if (!src) {
229     dest->capacity = 0;
230     dest->count = 0;
231     dest->metadata = nullptr;
232     return;
233   }
234 
235   dest->capacity = src->capacity;
236   dest->count = src->count;
237   dest->metadata = src->metadata;
238 
239   src->capacity = 0;
240   src->count = 0;
241   src->metadata = nullptr;
242 }
243 
244 GPR_EXPORT void GPR_CALLTYPE
grpcwrap_batch_context_destroy(grpcwrap_batch_context * ctx)245 grpcwrap_batch_context_destroy(grpcwrap_batch_context* ctx) {
246   if (!ctx) {
247     return;
248   }
249   grpcwrap_metadata_array_destroy_metadata_including_entries(
250       &(ctx->send_initial_metadata));
251 
252   grpc_byte_buffer_destroy(ctx->send_message);
253 
254   grpcwrap_metadata_array_destroy_metadata_including_entries(
255       &(ctx->send_status_from_server.trailing_metadata));
256 
257   grpcwrap_metadata_array_destroy_metadata_only(&(ctx->recv_initial_metadata));
258 
259   grpc_byte_buffer_destroy(ctx->recv_message);
260 
261   grpcwrap_metadata_array_destroy_metadata_only(
262       &(ctx->recv_status_on_client.trailing_metadata));
263   grpc_slice_unref(ctx->recv_status_on_client.status_details);
264   gpr_free((void*)ctx->recv_status_on_client.error_string);
265 
266   gpr_free(ctx);
267 }
268 
269 GPR_EXPORT void GPR_CALLTYPE
grpcwrap_request_call_context_destroy(grpcwrap_request_call_context * ctx)270 grpcwrap_request_call_context_destroy(grpcwrap_request_call_context* ctx) {
271   if (!ctx) {
272     return;
273   }
274 
275   if (ctx->call) {
276     grpc_call_unref(ctx->call);
277   }
278 
279   grpc_call_details_destroy(&(ctx->call_details));
280   grpcwrap_metadata_array_destroy_metadata_only(&(ctx->request_metadata));
281 
282   gpr_free(ctx);
283 }
284 
grpcwrap_batch_context_take_recv_initial_metadata(grpcwrap_batch_context * ctx,grpc_metadata_array * res)285 GPR_EXPORT void GPR_CALLTYPE grpcwrap_batch_context_take_recv_initial_metadata(
286     grpcwrap_batch_context* ctx, grpc_metadata_array* res) {
287   grpcwrap_metadata_array_move(res, &(ctx->recv_initial_metadata));
288 }
289 
290 GPR_EXPORT void GPR_CALLTYPE
grpcwrap_batch_context_take_recv_status_on_client_trailing_metadata(grpcwrap_batch_context * ctx,grpc_metadata_array * res)291 grpcwrap_batch_context_take_recv_status_on_client_trailing_metadata(
292     grpcwrap_batch_context* ctx, grpc_metadata_array* res) {
293   grpcwrap_metadata_array_move(res,
294                                &(ctx->recv_status_on_client.trailing_metadata));
295 }
296 
297 GPR_EXPORT const char* GPR_CALLTYPE
grpcwrap_slice_raw_offset(const grpc_slice * slice,size_t offset,size_t * len)298 grpcwrap_slice_raw_offset(const grpc_slice* slice, size_t offset, size_t* len) {
299   *len = GRPC_SLICE_LENGTH(*slice) - offset;
300   return (const char*)(GRPC_SLICE_START_PTR(*slice)) + offset;
301 }
302 
303 GPR_EXPORT grpc_slice GPR_CALLTYPE
grpcwrap_slice_copy(const grpc_slice * slice)304 grpcwrap_slice_copy(const grpc_slice* slice) {
305   return grpc_slice_copy(*slice);
306 }
307 
grpcwrap_slice_unref(const grpc_slice * slice)308 GPR_EXPORT void GPR_CALLTYPE grpcwrap_slice_unref(const grpc_slice* slice) {
309   grpc_slice_unref(*slice);
310 }
311 
grpcwrap_slice_ref(const grpc_slice * slice)312 GPR_EXPORT grpc_slice GPR_CALLTYPE grpcwrap_slice_ref(const grpc_slice* slice) {
313   return grpc_slice_ref(*slice);
314 }
315 
grpcwrap_slice_length(const grpc_slice * slice)316 GPR_EXPORT size_t GPR_CALLTYPE grpcwrap_slice_length(const grpc_slice* slice) {
317   return GRPC_SLICE_LENGTH(*slice);
318 }
319 
320 GPR_EXPORT grpc_byte_buffer* GPR_CALLTYPE
grpcwrap_batch_context_take_recv_message(grpcwrap_batch_context * ctx)321 grpcwrap_batch_context_take_recv_message(grpcwrap_batch_context* ctx) {
322   grpc_byte_buffer* buf = nullptr;
323   if (ctx->recv_message) {
324     buf = ctx->recv_message;
325     ctx->recv_message = nullptr;
326   }
327   return buf;
328 }
329 
330 GPR_EXPORT grpc_status_code GPR_CALLTYPE
grpcwrap_batch_context_recv_status_on_client_status(const grpcwrap_batch_context * ctx)331 grpcwrap_batch_context_recv_status_on_client_status(
332     const grpcwrap_batch_context* ctx) {
333   return ctx->recv_status_on_client.status;
334 }
335 
336 GPR_EXPORT const char* GPR_CALLTYPE
grpcwrap_batch_context_recv_status_on_client_details(const grpcwrap_batch_context * ctx,size_t * details_length)337 grpcwrap_batch_context_recv_status_on_client_details(
338     const grpcwrap_batch_context* ctx, size_t* details_length) {
339   *details_length =
340       GRPC_SLICE_LENGTH(ctx->recv_status_on_client.status_details);
341   return (char*)GRPC_SLICE_START_PTR(ctx->recv_status_on_client.status_details);
342 }
343 
344 GPR_EXPORT const grpc_metadata_array* GPR_CALLTYPE
grpcwrap_batch_context_recv_status_on_client_trailing_metadata(const grpcwrap_batch_context * ctx)345 grpcwrap_batch_context_recv_status_on_client_trailing_metadata(
346     const grpcwrap_batch_context* ctx) {
347   return &(ctx->recv_status_on_client.trailing_metadata);
348 }
349 
350 GPR_EXPORT const char* GPR_CALLTYPE
grpcwrap_batch_context_recv_status_on_client_error_string(const grpcwrap_batch_context * ctx)351 grpcwrap_batch_context_recv_status_on_client_error_string(
352     const grpcwrap_batch_context* ctx) {
353   return ctx->recv_status_on_client.error_string;
354 }
355 
356 GPR_EXPORT grpc_call* GPR_CALLTYPE
grpcwrap_request_call_context_ref_call(grpcwrap_request_call_context * ctx)357 grpcwrap_request_call_context_ref_call(grpcwrap_request_call_context* ctx) {
358   grpc_call* call = ctx->call;
359   grpc_call_ref(call);
360   return call;
361 }
362 
363 GPR_EXPORT grpc_call* GPR_CALLTYPE
grpcwrap_request_call_context_get_call(grpcwrap_request_call_context * ctx)364 grpcwrap_request_call_context_get_call(grpcwrap_request_call_context* ctx) {
365   return ctx->call;
366 }
367 
grpcwrap_request_call_context_method(const grpcwrap_request_call_context * ctx,size_t * method_length)368 GPR_EXPORT const char* GPR_CALLTYPE grpcwrap_request_call_context_method(
369     const grpcwrap_request_call_context* ctx, size_t* method_length) {
370   *method_length = GRPC_SLICE_LENGTH(ctx->call_details.method);
371   return (char*)GRPC_SLICE_START_PTR(ctx->call_details.method);
372 }
373 
grpcwrap_request_call_context_host(const grpcwrap_request_call_context * ctx,size_t * host_length)374 GPR_EXPORT const char* GPR_CALLTYPE grpcwrap_request_call_context_host(
375     const grpcwrap_request_call_context* ctx, size_t* host_length) {
376   *host_length = GRPC_SLICE_LENGTH(ctx->call_details.host);
377   return (char*)GRPC_SLICE_START_PTR(ctx->call_details.host);
378 }
379 
grpcwrap_request_call_context_deadline(const grpcwrap_request_call_context * ctx)380 GPR_EXPORT gpr_timespec GPR_CALLTYPE grpcwrap_request_call_context_deadline(
381     const grpcwrap_request_call_context* ctx) {
382   return ctx->call_details.deadline;
383 }
384 
385 GPR_EXPORT const grpc_metadata_array* GPR_CALLTYPE
grpcwrap_request_call_context_metadata_array(const grpcwrap_request_call_context * ctx)386 grpcwrap_request_call_context_metadata_array(
387     const grpcwrap_request_call_context* ctx) {
388   return &(ctx->request_metadata);
389 }
390 
391 GPR_EXPORT int32_t GPR_CALLTYPE
grpcwrap_batch_context_recv_close_on_server_cancelled(const grpcwrap_batch_context * ctx)392 grpcwrap_batch_context_recv_close_on_server_cancelled(
393     const grpcwrap_batch_context* ctx) {
394   return (int32_t)ctx->recv_close_on_server_cancelled;
395 }
396 
397 /* Channel */
398 
grpcwrap_channel_create_call(grpc_channel * channel,grpc_call * parent_call,uint32_t propagation_mask,grpc_completion_queue * cq,const char * method,size_t method_len,const char * host,size_t host_len,gpr_timespec deadline)399 GPR_EXPORT grpc_call* GPR_CALLTYPE grpcwrap_channel_create_call(
400     grpc_channel* channel, grpc_call* parent_call, uint32_t propagation_mask,
401     grpc_completion_queue* cq, const char* method, size_t method_len,
402     const char* host, size_t host_len, gpr_timespec deadline) {
403   grpc_slice method_slice = grpc_slice_from_copied_buffer(method, method_len);
404   grpc_slice* host_slice_ptr = nullptr;
405   grpc_slice host_slice;
406   if (host != nullptr) {
407     host_slice = grpc_slice_from_copied_buffer(host, host_len);
408     host_slice_ptr = &host_slice;
409   } else {
410     // to silent msvc false warning
411     host_slice = grpc_empty_slice();
412   }
413   grpc_call* ret =
414       grpc_channel_create_call(channel, parent_call, propagation_mask, cq,
415                                method_slice, host_slice_ptr, deadline, nullptr);
416   grpc_slice_unref(method_slice);
417   if (host != nullptr) {
418     grpc_slice_unref(host_slice);
419   }
420   return ret;
421 }
422 
423 /* Channel args */
424 
425 GPR_EXPORT grpc_channel_args* GPR_CALLTYPE
grpcwrap_channel_args_create(size_t num_args)426 grpcwrap_channel_args_create(size_t num_args) {
427   auto* args = (grpc_channel_args*)gpr_malloc(sizeof(grpc_channel_args));
428   memset(args, 0, sizeof(grpc_channel_args));
429 
430   args->num_args = num_args;
431   args->args = (grpc_arg*)gpr_malloc(sizeof(grpc_arg) * num_args);
432   memset(args->args, 0, sizeof(grpc_arg) * num_args);
433   return args;
434 }
435 
grpcwrap_channel_args_set_string(grpc_channel_args * args,size_t index,const char * key,const char * value)436 GPR_EXPORT void GPR_CALLTYPE grpcwrap_channel_args_set_string(
437     grpc_channel_args* args, size_t index, const char* key, const char* value) {
438   GPR_ASSERT(args);
439   GPR_ASSERT(index < args->num_args);
440   args->args[index].type = GRPC_ARG_STRING;
441   args->args[index].key = gpr_strdup(key);
442   args->args[index].value.string = gpr_strdup(value);
443 }
444 
grpcwrap_channel_args_set_integer(grpc_channel_args * args,size_t index,const char * key,int value)445 GPR_EXPORT void GPR_CALLTYPE grpcwrap_channel_args_set_integer(
446     grpc_channel_args* args, size_t index, const char* key, int value) {
447   GPR_ASSERT(args);
448   GPR_ASSERT(index < args->num_args);
449   args->args[index].type = GRPC_ARG_INTEGER;
450   args->args[index].key = gpr_strdup(key);
451   args->args[index].value.integer = value;
452 }
453 
grpcwrap_channel_args_set_pointer_vtable(grpc_channel_args * args,size_t index,const char * key,void * value,const grpc_arg_pointer_vtable * vtable)454 GPR_EXPORT void GPR_CALLTYPE grpcwrap_channel_args_set_pointer_vtable(
455     grpc_channel_args* args, size_t index, const char* key, void* value,
456     const grpc_arg_pointer_vtable* vtable) {
457   GPR_ASSERT(args);
458   GPR_ASSERT(index < args->num_args);
459   args->args[index].type = GRPC_ARG_POINTER;
460   args->args[index].key = gpr_strdup(key);
461   args->args[index].value.pointer.p = vtable->copy(value);
462   args->args[index].value.pointer.vtable = vtable;
463 }
464 
465 GPR_EXPORT void GPR_CALLTYPE
grpcwrap_channel_args_destroy(grpc_channel_args * args)466 grpcwrap_channel_args_destroy(grpc_channel_args* args) {
467   size_t i;
468   if (args) {
469     for (i = 0; i < args->num_args; i++) {
470       gpr_free(args->args[i].key);
471       if (args->args[i].type == GRPC_ARG_STRING) {
472         gpr_free(args->args[i].value.string);
473       }
474       if (args->args[i].type == GRPC_ARG_POINTER) {
475         args->args[i].value.pointer.vtable->destroy(
476             args->args[i].value.pointer.p);
477       }
478     }
479     gpr_free(args->args);
480     gpr_free(args);
481   }
482 }
483 
484 /* Call */
485 
grpcwrap_call_start_unary(grpc_call * call,grpcwrap_batch_context * ctx,grpc_slice * send_buffer,uint32_t write_flags,grpc_metadata_array * initial_metadata,uint32_t initial_metadata_flags,void * tag)486 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcwrap_call_start_unary(
487     grpc_call* call, grpcwrap_batch_context* ctx, grpc_slice* send_buffer,
488     uint32_t write_flags, grpc_metadata_array* initial_metadata,
489     uint32_t initial_metadata_flags, void* tag) {
490   /* TODO: don't use magic number */
491   grpc_op ops[6];
492   memset(ops, 0, sizeof(ops));
493   ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
494   grpcwrap_metadata_array_move(&(ctx->send_initial_metadata), initial_metadata);
495   ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
496   ops[0].data.send_initial_metadata.metadata =
497       ctx->send_initial_metadata.metadata;
498   ops[0].flags = initial_metadata_flags;
499   ops[0].reserved = nullptr;
500 
501   ops[1].op = GRPC_OP_SEND_MESSAGE;
502   ctx->send_message = grpc_raw_byte_buffer_create(send_buffer, 1);
503   ops[1].data.send_message.send_message = ctx->send_message;
504   ops[1].flags = write_flags;
505   ops[1].reserved = nullptr;
506 
507   ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
508   ops[2].flags = 0;
509   ops[2].reserved = nullptr;
510 
511   ops[3].op = GRPC_OP_RECV_INITIAL_METADATA;
512   ops[3].data.recv_initial_metadata.recv_initial_metadata =
513       &(ctx->recv_initial_metadata);
514   ops[3].flags = 0;
515   ops[3].reserved = nullptr;
516 
517   ops[4].op = GRPC_OP_RECV_MESSAGE;
518   ops[4].data.recv_message.recv_message = &(ctx->recv_message);
519   ops[4].flags = 0;
520   ops[4].reserved = nullptr;
521 
522   ops[5].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
523   ops[5].data.recv_status_on_client.trailing_metadata =
524       &(ctx->recv_status_on_client.trailing_metadata);
525   ops[5].data.recv_status_on_client.status =
526       &(ctx->recv_status_on_client.status);
527   ops[5].data.recv_status_on_client.status_details =
528       &(ctx->recv_status_on_client.status_details);
529   ops[5].data.recv_status_on_client.error_string =
530       &(ctx->recv_status_on_client.error_string);
531   ops[5].flags = 0;
532   ops[5].reserved = nullptr;
533 
534   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), tag,
535                                nullptr);
536 }
537 
grpcwrap_call_start_client_streaming(grpc_call * call,grpcwrap_batch_context * ctx,grpc_metadata_array * initial_metadata,uint32_t initial_metadata_flags,void * tag)538 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcwrap_call_start_client_streaming(
539     grpc_call* call, grpcwrap_batch_context* ctx,
540     grpc_metadata_array* initial_metadata, uint32_t initial_metadata_flags,
541     void* tag) {
542   /* TODO: don't use magic number */
543   grpc_op ops[4];
544   memset(ops, 0, sizeof(ops));
545   ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
546   grpcwrap_metadata_array_move(&(ctx->send_initial_metadata), initial_metadata);
547   ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
548   ops[0].data.send_initial_metadata.metadata =
549       ctx->send_initial_metadata.metadata;
550   ops[0].flags = initial_metadata_flags;
551   ops[0].reserved = nullptr;
552 
553   ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
554   ops[1].data.recv_initial_metadata.recv_initial_metadata =
555       &(ctx->recv_initial_metadata);
556   ops[1].flags = 0;
557   ops[1].reserved = nullptr;
558 
559   ops[2].op = GRPC_OP_RECV_MESSAGE;
560   ops[2].data.recv_message.recv_message = &(ctx->recv_message);
561   ops[2].flags = 0;
562   ops[2].reserved = nullptr;
563 
564   ops[3].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
565   ops[3].data.recv_status_on_client.trailing_metadata =
566       &(ctx->recv_status_on_client.trailing_metadata);
567   ops[3].data.recv_status_on_client.status =
568       &(ctx->recv_status_on_client.status);
569   ops[3].data.recv_status_on_client.status_details =
570       &(ctx->recv_status_on_client.status_details);
571   ops[3].data.recv_status_on_client.error_string =
572       &(ctx->recv_status_on_client.error_string);
573   ops[3].flags = 0;
574   ops[3].reserved = nullptr;
575 
576   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), tag,
577                                nullptr);
578 }
579 
grpcwrap_call_start_server_streaming(grpc_call * call,grpcwrap_batch_context * ctx,grpc_slice * send_buffer,uint32_t write_flags,grpc_metadata_array * initial_metadata,uint32_t initial_metadata_flags,void * tag)580 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcwrap_call_start_server_streaming(
581     grpc_call* call, grpcwrap_batch_context* ctx, grpc_slice* send_buffer,
582     uint32_t write_flags, grpc_metadata_array* initial_metadata,
583     uint32_t initial_metadata_flags, void* tag) {
584   /* TODO: don't use magic number */
585   grpc_op ops[4];
586   memset(ops, 0, sizeof(ops));
587   ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
588   grpcwrap_metadata_array_move(&(ctx->send_initial_metadata), initial_metadata);
589   ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
590   ops[0].data.send_initial_metadata.metadata =
591       ctx->send_initial_metadata.metadata;
592   ops[0].flags = initial_metadata_flags;
593   ops[0].reserved = nullptr;
594 
595   ops[1].op = GRPC_OP_SEND_MESSAGE;
596   ctx->send_message = grpc_raw_byte_buffer_create(send_buffer, 1);
597   ops[1].data.send_message.send_message = ctx->send_message;
598   ops[1].flags = write_flags;
599   ops[1].reserved = nullptr;
600 
601   ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
602   ops[2].flags = 0;
603   ops[2].reserved = nullptr;
604 
605   ops[3].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
606   ops[3].data.recv_status_on_client.trailing_metadata =
607       &(ctx->recv_status_on_client.trailing_metadata);
608   ops[3].data.recv_status_on_client.status =
609       &(ctx->recv_status_on_client.status);
610   ops[3].data.recv_status_on_client.status_details =
611       &(ctx->recv_status_on_client.status_details);
612   ops[3].data.recv_status_on_client.error_string =
613       &(ctx->recv_status_on_client.error_string);
614   ops[3].flags = 0;
615   ops[3].reserved = nullptr;
616 
617   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), tag,
618                                nullptr);
619 }
620 
grpcwrap_call_start_duplex_streaming(grpc_call * call,grpcwrap_batch_context * ctx,grpc_metadata_array * initial_metadata,uint32_t initial_metadata_flags,void * tag)621 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcwrap_call_start_duplex_streaming(
622     grpc_call* call, grpcwrap_batch_context* ctx,
623     grpc_metadata_array* initial_metadata, uint32_t initial_metadata_flags,
624     void* tag) {
625   /* TODO: don't use magic number */
626   grpc_op ops[2];
627   memset(ops, 0, sizeof(ops));
628   ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
629   grpcwrap_metadata_array_move(&(ctx->send_initial_metadata), initial_metadata);
630   ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
631   ops[0].data.send_initial_metadata.metadata =
632       ctx->send_initial_metadata.metadata;
633   ops[0].flags = initial_metadata_flags;
634   ops[0].reserved = nullptr;
635 
636   ops[1].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
637   ops[1].data.recv_status_on_client.trailing_metadata =
638       &(ctx->recv_status_on_client.trailing_metadata);
639   ops[1].data.recv_status_on_client.status =
640       &(ctx->recv_status_on_client.status);
641   ops[1].data.recv_status_on_client.status_details =
642       &(ctx->recv_status_on_client.status_details);
643   ops[1].data.recv_status_on_client.error_string =
644       &(ctx->recv_status_on_client.error_string);
645   ops[1].flags = 0;
646   ops[1].reserved = nullptr;
647 
648   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), tag,
649                                nullptr);
650 }
651 
grpcwrap_call_recv_initial_metadata(grpc_call * call,grpcwrap_batch_context * ctx,void * tag)652 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcwrap_call_recv_initial_metadata(
653     grpc_call* call, grpcwrap_batch_context* ctx, void* tag) {
654   /* TODO: don't use magic number */
655   grpc_op ops[1];
656   ops[0].op = GRPC_OP_RECV_INITIAL_METADATA;
657   ops[0].data.recv_initial_metadata.recv_initial_metadata =
658       &(ctx->recv_initial_metadata);
659   ops[0].flags = 0;
660   ops[0].reserved = nullptr;
661 
662   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), tag,
663                                nullptr);
664 }
665 
grpcwrap_call_send_message(grpc_call * call,grpcwrap_batch_context * ctx,grpc_slice * send_buffer,uint32_t write_flags,grpc_metadata_array * initial_metadata,uint32_t initial_metadata_flags,void * tag)666 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcwrap_call_send_message(
667     grpc_call* call, grpcwrap_batch_context* ctx, grpc_slice* send_buffer,
668     uint32_t write_flags, grpc_metadata_array* initial_metadata,
669     uint32_t initial_metadata_flags, void* tag) {
670   /* TODO: don't use magic number */
671   grpc_op ops[2];
672   memset(ops, 0, sizeof(ops));
673   size_t nops = 1;
674 
675   ops[0].op = GRPC_OP_SEND_MESSAGE;
676   ctx->send_message = grpc_raw_byte_buffer_create(send_buffer, 1);
677   ops[0].data.send_message.send_message = ctx->send_message;
678   ops[0].flags = write_flags;
679   ops[0].reserved = nullptr;
680 
681   if (initial_metadata) {
682     ops[nops].op = GRPC_OP_SEND_INITIAL_METADATA;
683     grpcwrap_metadata_array_move(&(ctx->send_initial_metadata),
684                                  initial_metadata);
685     ops[nops].data.send_initial_metadata.count =
686         ctx->send_initial_metadata.count;
687     ops[nops].data.send_initial_metadata.metadata =
688         ctx->send_initial_metadata.metadata;
689     ops[nops].flags = initial_metadata_flags;
690     ops[nops].reserved = nullptr;
691     nops++;
692   }
693   return grpc_call_start_batch(call, ops, nops, tag, nullptr);
694 }
695 
696 GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcwrap_call_send_close_from_client(grpc_call * call,void * tag)697 grpcwrap_call_send_close_from_client(grpc_call* call, void* tag) {
698   /* TODO: don't use magic number */
699   grpc_op ops[1];
700   ops[0].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
701   ops[0].flags = 0;
702   ops[0].reserved = nullptr;
703 
704   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), tag,
705                                nullptr);
706 }
707 
grpcwrap_call_send_status_from_server(grpc_call * call,grpcwrap_batch_context * ctx,grpc_status_code status_code,const char * status_details,size_t status_details_len,grpc_metadata_array * initial_metadata,uint32_t initial_metadata_flags,grpc_metadata_array * trailing_metadata,grpc_slice * optional_send_buffer,uint32_t write_flags,void * tag)708 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcwrap_call_send_status_from_server(
709     grpc_call* call, grpcwrap_batch_context* ctx, grpc_status_code status_code,
710     const char* status_details, size_t status_details_len,
711     grpc_metadata_array* initial_metadata, uint32_t initial_metadata_flags,
712     grpc_metadata_array* trailing_metadata, grpc_slice* optional_send_buffer,
713     uint32_t write_flags, void* tag) {
714   /* TODO: don't use magic number */
715   grpc_op ops[3];
716   memset(ops, 0, sizeof(ops));
717   size_t nops = 1;
718 
719   grpc_slice status_details_slice =
720       grpc_slice_from_copied_buffer(status_details, status_details_len);
721 
722   ops[0].op = GRPC_OP_SEND_STATUS_FROM_SERVER;
723   ops[0].data.send_status_from_server.status = status_code;
724   ops[0].data.send_status_from_server.status_details = &status_details_slice;
725   grpcwrap_metadata_array_move(
726       &(ctx->send_status_from_server.trailing_metadata), trailing_metadata);
727   ops[0].data.send_status_from_server.trailing_metadata_count =
728       ctx->send_status_from_server.trailing_metadata.count;
729   ops[0].data.send_status_from_server.trailing_metadata =
730       ctx->send_status_from_server.trailing_metadata.metadata;
731   ops[0].flags = 0;
732   ops[0].reserved = nullptr;
733 
734   if (optional_send_buffer) {
735     ops[nops].op = GRPC_OP_SEND_MESSAGE;
736     ctx->send_message = grpc_raw_byte_buffer_create(optional_send_buffer, 1);
737     ops[nops].data.send_message.send_message = ctx->send_message;
738     ops[nops].flags = write_flags;
739     ops[nops].reserved = nullptr;
740     nops++;
741   }
742   if (initial_metadata) {
743     ops[nops].op = GRPC_OP_SEND_INITIAL_METADATA;
744     grpcwrap_metadata_array_move(&(ctx->send_initial_metadata),
745                                  initial_metadata);
746     ops[nops].data.send_initial_metadata.count =
747         ctx->send_initial_metadata.count;
748     ops[nops].data.send_initial_metadata.metadata =
749         ctx->send_initial_metadata.metadata;
750     ops[nops].flags = initial_metadata_flags;
751     ops[nops].reserved = nullptr;
752     nops++;
753   }
754 
755   grpc_call_error ret = grpc_call_start_batch(call, ops, nops, tag, nullptr);
756   grpc_slice_unref(status_details_slice);
757   return ret;
758 }
759 
grpcwrap_call_recv_message(grpc_call * call,grpcwrap_batch_context * ctx,void * tag)760 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcwrap_call_recv_message(
761     grpc_call* call, grpcwrap_batch_context* ctx, void* tag) {
762   /* TODO: don't use magic number */
763   grpc_op ops[1];
764   ops[0].op = GRPC_OP_RECV_MESSAGE;
765   ops[0].data.recv_message.recv_message = &(ctx->recv_message);
766   ops[0].flags = 0;
767   ops[0].reserved = nullptr;
768   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), tag,
769                                nullptr);
770 }
771 
grpcwrap_call_start_serverside(grpc_call * call,grpcwrap_batch_context * ctx,void * tag)772 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcwrap_call_start_serverside(
773     grpc_call* call, grpcwrap_batch_context* ctx, void* tag) {
774   /* TODO: don't use magic number */
775   grpc_op ops[1];
776   ops[0].op = GRPC_OP_RECV_CLOSE_ON_SERVER;
777   ops[0].data.recv_close_on_server.cancelled =
778       (&ctx->recv_close_on_server_cancelled);
779   ops[0].flags = 0;
780   ops[0].reserved = nullptr;
781 
782   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), tag,
783                                nullptr);
784 }
785 
grpcwrap_call_send_initial_metadata(grpc_call * call,grpcwrap_batch_context * ctx,grpc_metadata_array * initial_metadata,void * tag)786 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcwrap_call_send_initial_metadata(
787     grpc_call* call, grpcwrap_batch_context* ctx,
788     grpc_metadata_array* initial_metadata, void* tag) {
789   /* TODO: don't use magic number */
790   grpc_op ops[1];
791   memset(ops, 0, sizeof(ops));
792   ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
793   grpcwrap_metadata_array_move(&(ctx->send_initial_metadata), initial_metadata);
794   ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
795   ops[0].data.send_initial_metadata.metadata =
796       ctx->send_initial_metadata.metadata;
797   ops[0].flags = 0;
798   ops[0].reserved = nullptr;
799 
800   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), tag,
801                                nullptr);
802 }
803 
804 /** Kick call's completion queue, it should be called after there is an event
805     ready to poll.
806     THREAD SAFETY: grpcwrap_call_kick_completion_queue is thread-safe
807     because it does not change the call's state. */
808 GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcwrap_call_kick_completion_queue(grpc_call * call,void * tag)809 grpcwrap_call_kick_completion_queue(grpc_call* call, void* tag) {
810   // Empty batch grpc_op kicks call's completion queue immediately.
811   return grpc_call_start_batch(call, nullptr, 0, tag, nullptr);
812 }
813 
814 /* Server */
815 
816 GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcwrap_server_request_call(grpc_server * server,grpc_completion_queue * cq,grpcwrap_request_call_context * ctx,void * tag)817 grpcwrap_server_request_call(grpc_server* server, grpc_completion_queue* cq,
818                              grpcwrap_request_call_context* ctx, void* tag) {
819   return grpc_server_request_call(server, &(ctx->call), &(ctx->call_details),
820                                   &(ctx->request_metadata), cq, cq, tag);
821 }
822