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