Imported Upstream version 1.41.0
[platform/upstream/grpc.git] / src / csharp / ext / grpc_csharp_ext.c
1 /*
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  */
18
19 #include <grpc/support/port_platform.h>
20
21 #include <string.h>
22
23 #include <grpc/byte_buffer_reader.h>
24 #include <grpc/grpc.h>
25 #include <grpc/grpc_security.h>
26 #include <grpc/slice.h>
27 #include <grpc/support/alloc.h>
28 #include <grpc/support/log.h>
29 #include <grpc/support/string_util.h>
30 #include <grpc/support/thd_id.h>
31
32 #ifdef GPR_WINDOWS
33 #define GPR_EXPORT __declspec(dllexport)
34 #define GPR_CALLTYPE __stdcall
35 #endif
36
37 #ifndef GPR_EXPORT
38 #define GPR_EXPORT
39 #endif
40
41 #ifndef GPR_CALLTYPE
42 #define GPR_CALLTYPE
43 #endif
44
45 static grpc_byte_buffer* grpcsharp_create_byte_buffer_from_stolen_slices(
46     grpc_slice_buffer* slice_buffer) {
47   grpc_byte_buffer* bb =
48       (grpc_byte_buffer*)gpr_zalloc(sizeof(grpc_byte_buffer));
49   bb->type = GRPC_BB_RAW;
50   bb->data.raw.compression = GRPC_COMPRESS_NONE;
51   grpc_slice_buffer_init(&bb->data.raw.slice_buffer);
52
53   grpc_slice_buffer_swap(&bb->data.raw.slice_buffer, slice_buffer);
54   return bb;
55 }
56
57 /*
58  * Helper to maintain lifetime of batch op inputs and store batch op outputs.
59  */
60 typedef struct grpcsharp_batch_context {
61   grpc_metadata_array send_initial_metadata;
62   grpc_byte_buffer* send_message;
63   struct {
64     grpc_metadata_array trailing_metadata;
65   } send_status_from_server;
66   grpc_metadata_array recv_initial_metadata;
67   grpc_byte_buffer* recv_message;
68   grpc_byte_buffer_reader* recv_message_reader;
69   struct {
70     grpc_metadata_array trailing_metadata;
71     grpc_status_code status;
72     grpc_slice status_details;
73     const char* error_string;
74   } recv_status_on_client;
75   int recv_close_on_server_cancelled;
76
77   /* reserve space for byte_buffer_reader */
78   grpc_byte_buffer_reader reserved_recv_message_reader;
79 } grpcsharp_batch_context;
80
81 GPR_EXPORT grpcsharp_batch_context* GPR_CALLTYPE
82 grpcsharp_batch_context_create() {
83   grpcsharp_batch_context* ctx = gpr_malloc(sizeof(grpcsharp_batch_context));
84   memset(ctx, 0, sizeof(grpcsharp_batch_context));
85   return ctx;
86 }
87
88 typedef struct {
89   grpc_call* call;
90   grpc_call_details call_details;
91   grpc_metadata_array request_metadata;
92 } grpcsharp_request_call_context;
93
94 GPR_EXPORT grpcsharp_request_call_context* GPR_CALLTYPE
95 grpcsharp_request_call_context_create() {
96   grpcsharp_request_call_context* ctx =
97       gpr_malloc(sizeof(grpcsharp_request_call_context));
98   memset(ctx, 0, sizeof(grpcsharp_request_call_context));
99   return ctx;
100 }
101
102 /*
103  * Destroys array->metadata.
104  * The array pointer itself is not freed.
105  */
106 void grpcsharp_metadata_array_destroy_metadata_only(
107     grpc_metadata_array* array) {
108   gpr_free(array->metadata);
109 }
110
111 /*
112  * Destroys keys, values and array->metadata.
113  * The array pointer itself is not freed.
114  */
115 void grpcsharp_metadata_array_destroy_metadata_including_entries(
116     grpc_metadata_array* array) {
117   size_t i;
118   if (array->metadata) {
119     for (i = 0; i < array->count; i++) {
120       grpc_slice_unref(array->metadata[i].key);
121       grpc_slice_unref(array->metadata[i].value);
122     }
123   }
124   gpr_free(array->metadata);
125 }
126
127 /*
128  * Fully destroys the metadata array.
129  */
130 GPR_EXPORT void GPR_CALLTYPE
131 grpcsharp_metadata_array_destroy_full(grpc_metadata_array* array) {
132   if (!array) {
133     return;
134   }
135   grpcsharp_metadata_array_destroy_metadata_including_entries(array);
136   gpr_free(array);
137 }
138
139 /*
140  * Creates an empty metadata array with given capacity.
141  * Array can later be destroyed by grpc_metadata_array_destroy_full.
142  */
143 GPR_EXPORT grpc_metadata_array* GPR_CALLTYPE
144 grpcsharp_metadata_array_create(size_t capacity) {
145   grpc_metadata_array* array =
146       (grpc_metadata_array*)gpr_malloc(sizeof(grpc_metadata_array));
147   grpc_metadata_array_init(array);
148   array->capacity = capacity;
149   array->count = 0;
150   if (capacity > 0) {
151     array->metadata =
152         (grpc_metadata*)gpr_malloc(sizeof(grpc_metadata) * capacity);
153     memset(array->metadata, 0, sizeof(grpc_metadata) * capacity);
154   } else {
155     array->metadata = NULL;
156   }
157   return array;
158 }
159
160 GPR_EXPORT void GPR_CALLTYPE
161 grpcsharp_metadata_array_add(grpc_metadata_array* array, const char* key,
162                              const char* value, size_t value_length) {
163   size_t i = array->count;
164   GPR_ASSERT(array->count < array->capacity);
165   array->metadata[i].key = grpc_slice_from_copied_string(key);
166   array->metadata[i].value = grpc_slice_from_copied_buffer(value, value_length);
167   array->count++;
168 }
169
170 GPR_EXPORT intptr_t GPR_CALLTYPE
171 grpcsharp_metadata_array_count(grpc_metadata_array* array) {
172   return (intptr_t)array->count;
173 }
174
175 GPR_EXPORT const char* GPR_CALLTYPE grpcsharp_metadata_array_get_key(
176     grpc_metadata_array* array, size_t index, size_t* key_length) {
177   GPR_ASSERT(index < array->count);
178   *key_length = GRPC_SLICE_LENGTH(array->metadata[index].key);
179   return (char*)GRPC_SLICE_START_PTR(array->metadata[index].key);
180 }
181
182 GPR_EXPORT const char* GPR_CALLTYPE grpcsharp_metadata_array_get_value(
183     grpc_metadata_array* array, size_t index, size_t* value_length) {
184   GPR_ASSERT(index < array->count);
185   *value_length = GRPC_SLICE_LENGTH(array->metadata[index].value);
186   return (char*)GRPC_SLICE_START_PTR(array->metadata[index].value);
187 }
188
189 /* Move contents of metadata array */
190 void grpcsharp_metadata_array_move(grpc_metadata_array* dest,
191                                    grpc_metadata_array* src) {
192   if (!src) {
193     dest->capacity = 0;
194     dest->count = 0;
195     dest->metadata = NULL;
196     return;
197   }
198
199   dest->capacity = src->capacity;
200   dest->count = src->count;
201   dest->metadata = src->metadata;
202
203   src->capacity = 0;
204   src->count = 0;
205   src->metadata = NULL;
206 }
207
208 GPR_EXPORT void GPR_CALLTYPE
209 grpcsharp_batch_context_reset(grpcsharp_batch_context* ctx) {
210   grpcsharp_metadata_array_destroy_metadata_including_entries(
211       &(ctx->send_initial_metadata));
212
213   grpc_byte_buffer_destroy(ctx->send_message);
214
215   grpcsharp_metadata_array_destroy_metadata_including_entries(
216       &(ctx->send_status_from_server.trailing_metadata));
217
218   grpcsharp_metadata_array_destroy_metadata_only(&(ctx->recv_initial_metadata));
219
220   if (ctx->recv_message_reader) {
221     grpc_byte_buffer_reader_destroy(ctx->recv_message_reader);
222   }
223   grpc_byte_buffer_destroy(ctx->recv_message);
224
225   grpcsharp_metadata_array_destroy_metadata_only(
226       &(ctx->recv_status_on_client.trailing_metadata));
227   grpc_slice_unref(ctx->recv_status_on_client.status_details);
228   gpr_free((void*)ctx->recv_status_on_client.error_string);
229   memset(ctx, 0, sizeof(grpcsharp_batch_context));
230 }
231
232 GPR_EXPORT void GPR_CALLTYPE
233 grpcsharp_batch_context_destroy(grpcsharp_batch_context* ctx) {
234   if (!ctx) {
235     return;
236   }
237   grpcsharp_batch_context_reset(ctx);
238   gpr_free(ctx);
239 }
240
241 GPR_EXPORT void GPR_CALLTYPE
242 grpcsharp_request_call_context_reset(grpcsharp_request_call_context* ctx) {
243   /* NOTE: ctx->server_rpc_new.call is not destroyed because callback handler is
244      supposed
245      to take its ownership. */
246
247   grpc_call_details_destroy(&(ctx->call_details));
248   grpcsharp_metadata_array_destroy_metadata_only(&(ctx->request_metadata));
249   memset(ctx, 0, sizeof(grpcsharp_request_call_context));
250 }
251
252 GPR_EXPORT void GPR_CALLTYPE
253 grpcsharp_request_call_context_destroy(grpcsharp_request_call_context* ctx) {
254   if (!ctx) {
255     return;
256   }
257   grpcsharp_request_call_context_reset(ctx);
258   gpr_free(ctx);
259 }
260
261 GPR_EXPORT const grpc_metadata_array* GPR_CALLTYPE
262 grpcsharp_batch_context_recv_initial_metadata(
263     const grpcsharp_batch_context* ctx) {
264   return &(ctx->recv_initial_metadata);
265 }
266
267 GPR_EXPORT intptr_t GPR_CALLTYPE grpcsharp_batch_context_recv_message_length(
268     const grpcsharp_batch_context* ctx) {
269   grpc_byte_buffer_reader reader;
270   if (!ctx->recv_message) {
271     return -1;
272   }
273
274   GPR_ASSERT(grpc_byte_buffer_reader_init(&reader, ctx->recv_message));
275   intptr_t result = (intptr_t)grpc_byte_buffer_length(reader.buffer_out);
276   grpc_byte_buffer_reader_destroy(&reader);
277
278   return result;
279 }
280
281 /*
282  * Gets the next slice from recv_message byte buffer.
283  * Returns 1 if a slice was get successfully, 0 if there are no more slices to
284  * read. Set slice_len to the length of the slice and the slice_data_ptr to
285  * point to slice's data. Caller must ensure that the byte buffer being read
286  * from stays alive as long as the data of the slice are being accessed
287  * (grpc_byte_buffer_reader_peek method is used internally)
288  *
289  * Remarks:
290  * Slices can only be iterated once.
291  * Initializes recv_message_buffer_reader if it was not initialized yet.
292  */
293 GPR_EXPORT int GPR_CALLTYPE
294 grpcsharp_batch_context_recv_message_next_slice_peek(
295     grpcsharp_batch_context* ctx, size_t* slice_len, uint8_t** slice_data_ptr) {
296   *slice_len = 0;
297   *slice_data_ptr = NULL;
298
299   if (!ctx->recv_message) {
300     return 0;
301   }
302
303   if (!ctx->recv_message_reader) {
304     ctx->recv_message_reader = &ctx->reserved_recv_message_reader;
305     GPR_ASSERT(grpc_byte_buffer_reader_init(ctx->recv_message_reader,
306                                             ctx->recv_message));
307   }
308
309   grpc_slice* slice_ptr;
310   if (!grpc_byte_buffer_reader_peek(ctx->recv_message_reader, &slice_ptr)) {
311     return 0;
312   }
313
314   /* recv_message buffer must not be deleted before all the data is read */
315   *slice_len = GRPC_SLICE_LENGTH(*slice_ptr);
316   *slice_data_ptr = GRPC_SLICE_START_PTR(*slice_ptr);
317   return 1;
318 }
319
320 GPR_EXPORT grpc_status_code GPR_CALLTYPE
321 grpcsharp_batch_context_recv_status_on_client_status(
322     const grpcsharp_batch_context* ctx) {
323   return ctx->recv_status_on_client.status;
324 }
325
326 GPR_EXPORT const char* GPR_CALLTYPE
327 grpcsharp_batch_context_recv_status_on_client_details(
328     const grpcsharp_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 char* GPR_CALLTYPE
335 grpcsharp_batch_context_recv_status_on_client_error_string(
336     const grpcsharp_batch_context* ctx) {
337   return ctx->recv_status_on_client.error_string;
338 }
339
340 GPR_EXPORT const grpc_metadata_array* GPR_CALLTYPE
341 grpcsharp_batch_context_recv_status_on_client_trailing_metadata(
342     const grpcsharp_batch_context* ctx) {
343   return &(ctx->recv_status_on_client.trailing_metadata);
344 }
345
346 GPR_EXPORT grpc_call* GPR_CALLTYPE
347 grpcsharp_request_call_context_call(const grpcsharp_request_call_context* ctx) {
348   return ctx->call;
349 }
350
351 GPR_EXPORT const char* GPR_CALLTYPE grpcsharp_request_call_context_method(
352     const grpcsharp_request_call_context* ctx, size_t* method_length) {
353   *method_length = GRPC_SLICE_LENGTH(ctx->call_details.method);
354   return (char*)GRPC_SLICE_START_PTR(ctx->call_details.method);
355 }
356
357 GPR_EXPORT const char* GPR_CALLTYPE grpcsharp_request_call_context_host(
358     const grpcsharp_request_call_context* ctx, size_t* host_length) {
359   *host_length = GRPC_SLICE_LENGTH(ctx->call_details.host);
360   return (char*)GRPC_SLICE_START_PTR(ctx->call_details.host);
361 }
362
363 GPR_EXPORT gpr_timespec GPR_CALLTYPE grpcsharp_request_call_context_deadline(
364     const grpcsharp_request_call_context* ctx) {
365   return ctx->call_details.deadline;
366 }
367
368 GPR_EXPORT const grpc_metadata_array* GPR_CALLTYPE
369 grpcsharp_request_call_context_request_metadata(
370     const grpcsharp_request_call_context* ctx) {
371   return &(ctx->request_metadata);
372 }
373
374 GPR_EXPORT int32_t GPR_CALLTYPE
375 grpcsharp_batch_context_recv_close_on_server_cancelled(
376     const grpcsharp_batch_context* ctx) {
377   return (int32_t)ctx->recv_close_on_server_cancelled;
378 }
379
380 /* Init & shutdown */
381
382 GPR_EXPORT void GPR_CALLTYPE grpcsharp_init(void) { grpc_init(); }
383
384 GPR_EXPORT void GPR_CALLTYPE grpcsharp_shutdown(void) { grpc_shutdown(); }
385
386 /* Completion queue */
387
388 GPR_EXPORT grpc_completion_queue* GPR_CALLTYPE
389 grpcsharp_completion_queue_create_async(void) {
390   return grpc_completion_queue_create_for_next(NULL);
391 }
392
393 GPR_EXPORT grpc_completion_queue* GPR_CALLTYPE
394 grpcsharp_completion_queue_create_sync(void) {
395   return grpc_completion_queue_create_for_pluck(NULL);
396 }
397
398 GPR_EXPORT void GPR_CALLTYPE
399 grpcsharp_completion_queue_shutdown(grpc_completion_queue* cq) {
400   grpc_completion_queue_shutdown(cq);
401 }
402
403 GPR_EXPORT void GPR_CALLTYPE
404 grpcsharp_completion_queue_destroy(grpc_completion_queue* cq) {
405   grpc_completion_queue_destroy(cq);
406 }
407
408 GPR_EXPORT grpc_event GPR_CALLTYPE
409 grpcsharp_completion_queue_next(grpc_completion_queue* cq) {
410   return grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME),
411                                     NULL);
412 }
413
414 GPR_EXPORT grpc_event GPR_CALLTYPE
415 grpcsharp_completion_queue_pluck(grpc_completion_queue* cq, void* tag) {
416   return grpc_completion_queue_pluck(cq, tag,
417                                      gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
418 }
419
420 /* Channel */
421
422 GPR_EXPORT grpc_channel* GPR_CALLTYPE
423
424 grpcsharp_insecure_channel_create(const char* target,
425                                   const grpc_channel_args* args) {
426   return grpc_insecure_channel_create(target, args, NULL);
427 }
428
429 GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_destroy(grpc_channel* channel) {
430   grpc_channel_destroy(channel);
431 }
432
433 GPR_EXPORT grpc_call* GPR_CALLTYPE grpcsharp_channel_create_call(
434     grpc_channel* channel, grpc_call* parent_call, uint32_t propagation_mask,
435     grpc_completion_queue* cq, const char* method, const char* host,
436     gpr_timespec deadline) {
437   grpc_slice method_slice = grpc_slice_from_copied_string(method);
438   grpc_slice* host_slice_ptr = NULL;
439   grpc_slice host_slice;
440   if (host != NULL) {
441     host_slice = grpc_slice_from_copied_string(host);
442     host_slice_ptr = &host_slice;
443   }
444   grpc_call* ret =
445       grpc_channel_create_call(channel, parent_call, propagation_mask, cq,
446                                method_slice, host_slice_ptr, deadline, NULL);
447   grpc_slice_unref(method_slice);
448   if (host != NULL) {
449     grpc_slice_unref(host_slice);
450   }
451   return ret;
452 }
453
454 GPR_EXPORT grpc_connectivity_state GPR_CALLTYPE
455 grpcsharp_channel_check_connectivity_state(grpc_channel* channel,
456                                            int32_t try_to_connect) {
457   return grpc_channel_check_connectivity_state(channel, try_to_connect);
458 }
459
460 GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_watch_connectivity_state(
461     grpc_channel* channel, grpc_connectivity_state last_observed_state,
462     gpr_timespec deadline, grpc_completion_queue* cq,
463     grpcsharp_batch_context* ctx) {
464   grpc_channel_watch_connectivity_state(channel, last_observed_state, deadline,
465                                         cq, ctx);
466 }
467
468 GPR_EXPORT char* GPR_CALLTYPE
469 grpcsharp_channel_get_target(grpc_channel* channel) {
470   return grpc_channel_get_target(channel);
471 }
472
473 /* Channel args */
474
475 GPR_EXPORT grpc_channel_args* GPR_CALLTYPE
476 grpcsharp_channel_args_create(size_t num_args) {
477   grpc_channel_args* args =
478       (grpc_channel_args*)gpr_malloc(sizeof(grpc_channel_args));
479   memset(args, 0, sizeof(grpc_channel_args));
480
481   args->num_args = num_args;
482   args->args = (grpc_arg*)gpr_malloc(sizeof(grpc_arg) * num_args);
483   memset(args->args, 0, sizeof(grpc_arg) * num_args);
484   return args;
485 }
486
487 GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_args_set_string(
488     grpc_channel_args* args, size_t index, const char* key, const char* value) {
489   GPR_ASSERT(args);
490   GPR_ASSERT(index < args->num_args);
491   args->args[index].type = GRPC_ARG_STRING;
492   args->args[index].key = gpr_strdup(key);
493   args->args[index].value.string = gpr_strdup(value);
494 }
495
496 GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_args_set_integer(
497     grpc_channel_args* args, size_t index, const char* key, int value) {
498   GPR_ASSERT(args);
499   GPR_ASSERT(index < args->num_args);
500   args->args[index].type = GRPC_ARG_INTEGER;
501   args->args[index].key = gpr_strdup(key);
502   args->args[index].value.integer = value;
503 }
504
505 GPR_EXPORT void GPR_CALLTYPE
506 grpcsharp_channel_args_destroy(grpc_channel_args* args) {
507   size_t i;
508   if (args) {
509     for (i = 0; i < args->num_args; i++) {
510       gpr_free(args->args[i].key);
511       if (args->args[i].type == GRPC_ARG_STRING) {
512         gpr_free(args->args[i].value.string);
513       }
514     }
515     gpr_free(args->args);
516     gpr_free(args);
517   }
518 }
519
520 /* Timespec */
521
522 GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_now(gpr_clock_type clock_type) {
523   return gpr_now(clock_type);
524 }
525
526 GPR_EXPORT gpr_timespec GPR_CALLTYPE
527 gprsharp_inf_future(gpr_clock_type clock_type) {
528   return gpr_inf_future(clock_type);
529 }
530
531 GPR_EXPORT gpr_timespec GPR_CALLTYPE
532 gprsharp_inf_past(gpr_clock_type clock_type) {
533   return gpr_inf_past(clock_type);
534 }
535
536 GPR_EXPORT gpr_timespec GPR_CALLTYPE
537 gprsharp_convert_clock_type(gpr_timespec t, gpr_clock_type target_clock) {
538   return gpr_convert_clock_type(t, target_clock);
539 }
540
541 GPR_EXPORT int32_t GPR_CALLTYPE gprsharp_sizeof_timespec(void) {
542   return sizeof(gpr_timespec);
543 }
544
545 /* Call */
546
547 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_cancel(grpc_call* call) {
548   return grpc_call_cancel(call, NULL);
549 }
550
551 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_cancel_with_status(
552     grpc_call* call, grpc_status_code status, const char* description) {
553   return grpc_call_cancel_with_status(call, status, description, NULL);
554 }
555
556 GPR_EXPORT char* GPR_CALLTYPE grpcsharp_call_get_peer(grpc_call* call) {
557   return grpc_call_get_peer(call);
558 }
559
560 GPR_EXPORT void GPR_CALLTYPE gprsharp_free(void* p) { gpr_free(p); }
561
562 GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_destroy(grpc_call* call) {
563   grpc_call_unref(call);
564 }
565
566 typedef grpc_call_error (*grpcsharp_call_start_batch_func)(grpc_call* call,
567                                                            const grpc_op* ops,
568                                                            size_t nops,
569                                                            void* tag,
570                                                            void* reserved);
571
572 /* Only for testing */
573 static grpc_call_error grpcsharp_call_start_batch_nop(grpc_call* call,
574                                                       const grpc_op* ops,
575                                                       size_t nops, void* tag,
576                                                       void* reserved) {
577   (void)call;
578   (void)ops;
579   (void)nops;
580   (void)tag;
581   (void)reserved;
582   return GRPC_CALL_OK;
583 }
584
585 static grpc_call_error grpcsharp_call_start_batch_default(grpc_call* call,
586                                                           const grpc_op* ops,
587                                                           size_t nops,
588                                                           void* tag,
589                                                           void* reserved) {
590   return grpc_call_start_batch(call, ops, nops, tag, reserved);
591 }
592
593 static grpcsharp_call_start_batch_func g_call_start_batch_func =
594     grpcsharp_call_start_batch_default;
595
596 static grpc_call_error grpcsharp_call_start_batch(grpc_call* call,
597                                                   const grpc_op* ops,
598                                                   size_t nops, void* tag,
599                                                   void* reserved) {
600   return g_call_start_batch_func(call, ops, nops, tag, reserved);
601 }
602
603 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_unary(
604     grpc_call* call, grpcsharp_batch_context* ctx,
605     grpc_slice_buffer* send_buffer, uint32_t write_flags,
606     grpc_metadata_array* initial_metadata, uint32_t initial_metadata_flags) {
607   /* TODO: don't use magic number */
608   grpc_op ops[6];
609   memset(ops, 0, sizeof(ops));
610   ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
611   grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
612                                 initial_metadata);
613   ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
614   ops[0].data.send_initial_metadata.metadata =
615       ctx->send_initial_metadata.metadata;
616   ops[0].flags = initial_metadata_flags;
617   ops[0].reserved = NULL;
618
619   ops[1].op = GRPC_OP_SEND_MESSAGE;
620   ctx->send_message =
621       grpcsharp_create_byte_buffer_from_stolen_slices(send_buffer);
622   ops[1].data.send_message.send_message = ctx->send_message;
623   ops[1].flags = write_flags;
624   ops[1].reserved = NULL;
625
626   ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
627   ops[2].flags = 0;
628   ops[2].reserved = NULL;
629
630   ops[3].op = GRPC_OP_RECV_INITIAL_METADATA;
631   ops[3].data.recv_initial_metadata.recv_initial_metadata =
632       &(ctx->recv_initial_metadata);
633   ops[3].flags = 0;
634   ops[3].reserved = NULL;
635
636   ops[4].op = GRPC_OP_RECV_MESSAGE;
637   ops[4].data.recv_message.recv_message = &(ctx->recv_message);
638   ops[4].flags = 0;
639   ops[4].reserved = NULL;
640
641   ops[5].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
642   ops[5].data.recv_status_on_client.trailing_metadata =
643       &(ctx->recv_status_on_client.trailing_metadata);
644   ops[5].data.recv_status_on_client.status =
645       &(ctx->recv_status_on_client.status);
646   ops[5].data.recv_status_on_client.status_details =
647       &(ctx->recv_status_on_client.status_details);
648   ops[5].data.recv_status_on_client.error_string =
649       &(ctx->recv_status_on_client.error_string);
650   ops[5].flags = 0;
651   ops[5].reserved = NULL;
652
653   return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
654                                     ctx, NULL);
655 }
656
657 /* Only for testing. Shortcircuits the unary call logic and only echoes the
658    message as if it was received from the server */
659 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_test_call_start_unary_echo(
660     grpc_call* call, grpcsharp_batch_context* ctx,
661     grpc_slice_buffer* send_buffer, uint32_t write_flags,
662     grpc_metadata_array* initial_metadata, uint32_t initial_metadata_flags) {
663   (void)call;
664   (void)write_flags;
665   (void)initial_metadata_flags;
666   // prepare as if we were performing a normal RPC.
667   grpc_byte_buffer* send_message =
668       grpcsharp_create_byte_buffer_from_stolen_slices(send_buffer);
669
670   ctx->recv_message = send_message;  // echo message sent by the client as if
671                                      // received from server.
672   ctx->recv_status_on_client.status = GRPC_STATUS_OK;
673   ctx->recv_status_on_client.status_details = grpc_empty_slice();
674   ctx->recv_status_on_client.error_string = NULL;
675   // echo initial metadata as if received from server (as trailing metadata)
676   grpcsharp_metadata_array_move(&(ctx->recv_status_on_client.trailing_metadata),
677                                 initial_metadata);
678   return GRPC_CALL_OK;
679 }
680
681 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_client_streaming(
682     grpc_call* call, grpcsharp_batch_context* ctx,
683     grpc_metadata_array* initial_metadata, uint32_t initial_metadata_flags) {
684   /* TODO: don't use magic number */
685   grpc_op ops[4];
686   memset(ops, 0, sizeof(ops));
687   ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
688   grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
689                                 initial_metadata);
690   ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
691   ops[0].data.send_initial_metadata.metadata =
692       ctx->send_initial_metadata.metadata;
693   ops[0].flags = initial_metadata_flags;
694   ops[0].reserved = NULL;
695
696   ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
697   ops[1].data.recv_initial_metadata.recv_initial_metadata =
698       &(ctx->recv_initial_metadata);
699   ops[1].flags = 0;
700   ops[1].reserved = NULL;
701
702   ops[2].op = GRPC_OP_RECV_MESSAGE;
703   ops[2].data.recv_message.recv_message = &(ctx->recv_message);
704   ops[2].flags = 0;
705   ops[2].reserved = NULL;
706
707   ops[3].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
708   ops[3].data.recv_status_on_client.trailing_metadata =
709       &(ctx->recv_status_on_client.trailing_metadata);
710   ops[3].data.recv_status_on_client.status =
711       &(ctx->recv_status_on_client.status);
712   ops[3].data.recv_status_on_client.status_details =
713       &(ctx->recv_status_on_client.status_details);
714   ops[3].data.recv_status_on_client.error_string =
715       &(ctx->recv_status_on_client.error_string);
716   ops[3].flags = 0;
717   ops[3].reserved = NULL;
718
719   return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
720                                     ctx, NULL);
721 }
722
723 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
724     grpc_call* call, grpcsharp_batch_context* ctx,
725     grpc_slice_buffer* send_buffer, uint32_t write_flags,
726     grpc_metadata_array* initial_metadata, uint32_t initial_metadata_flags) {
727   /* TODO: don't use magic number */
728   grpc_op ops[4];
729   memset(ops, 0, sizeof(ops));
730   ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
731   grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
732                                 initial_metadata);
733   ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
734   ops[0].data.send_initial_metadata.metadata =
735       ctx->send_initial_metadata.metadata;
736   ops[0].flags = initial_metadata_flags;
737   ops[0].reserved = NULL;
738
739   ops[1].op = GRPC_OP_SEND_MESSAGE;
740   ctx->send_message =
741       grpcsharp_create_byte_buffer_from_stolen_slices(send_buffer);
742   ops[1].data.send_message.send_message = ctx->send_message;
743   ops[1].flags = write_flags;
744   ops[1].reserved = NULL;
745
746   ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
747   ops[2].flags = 0;
748   ops[2].reserved = NULL;
749
750   ops[3].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
751   ops[3].data.recv_status_on_client.trailing_metadata =
752       &(ctx->recv_status_on_client.trailing_metadata);
753   ops[3].data.recv_status_on_client.status =
754       &(ctx->recv_status_on_client.status);
755   ops[3].data.recv_status_on_client.status_details =
756       &(ctx->recv_status_on_client.status_details);
757   ops[3].data.recv_status_on_client.error_string =
758       &(ctx->recv_status_on_client.error_string);
759   ops[3].flags = 0;
760   ops[3].reserved = NULL;
761
762   return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
763                                     ctx, NULL);
764 }
765
766 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_duplex_streaming(
767     grpc_call* call, grpcsharp_batch_context* ctx,
768     grpc_metadata_array* initial_metadata, uint32_t initial_metadata_flags) {
769   /* TODO: don't use magic number */
770   grpc_op ops[2];
771   memset(ops, 0, sizeof(ops));
772   ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
773   grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
774                                 initial_metadata);
775   ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
776   ops[0].data.send_initial_metadata.metadata =
777       ctx->send_initial_metadata.metadata;
778   ops[0].flags = initial_metadata_flags;
779   ops[0].reserved = NULL;
780
781   ops[1].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
782   ops[1].data.recv_status_on_client.trailing_metadata =
783       &(ctx->recv_status_on_client.trailing_metadata);
784   ops[1].data.recv_status_on_client.status =
785       &(ctx->recv_status_on_client.status);
786   ops[1].data.recv_status_on_client.status_details =
787       &(ctx->recv_status_on_client.status_details);
788   ops[1].data.recv_status_on_client.error_string =
789       &(ctx->recv_status_on_client.error_string);
790   ops[1].flags = 0;
791   ops[1].reserved = NULL;
792
793   return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
794                                     ctx, NULL);
795 }
796
797 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_recv_initial_metadata(
798     grpc_call* call, grpcsharp_batch_context* ctx) {
799   /* TODO: don't use magic number */
800   grpc_op ops[1];
801   ops[0].op = GRPC_OP_RECV_INITIAL_METADATA;
802   ops[0].data.recv_initial_metadata.recv_initial_metadata =
803       &(ctx->recv_initial_metadata);
804   ops[0].flags = 0;
805   ops[0].reserved = NULL;
806
807   return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
808                                     ctx, NULL);
809 }
810
811 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_message(
812     grpc_call* call, grpcsharp_batch_context* ctx,
813     grpc_slice_buffer* send_buffer, uint32_t write_flags,
814     int32_t send_empty_initial_metadata) {
815   /* TODO: don't use magic number */
816   grpc_op ops[2];
817   memset(ops, 0, sizeof(ops));
818   size_t nops = send_empty_initial_metadata ? 2 : 1;
819   ops[0].op = GRPC_OP_SEND_MESSAGE;
820   ctx->send_message =
821       grpcsharp_create_byte_buffer_from_stolen_slices(send_buffer);
822   ops[0].data.send_message.send_message = ctx->send_message;
823   ops[0].flags = write_flags;
824   ops[0].reserved = NULL;
825   ops[1].op = GRPC_OP_SEND_INITIAL_METADATA;
826   ops[1].flags = 0;
827   ops[1].reserved = NULL;
828
829   return grpcsharp_call_start_batch(call, ops, nops, ctx, NULL);
830 }
831
832 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_close_from_client(
833     grpc_call* call, grpcsharp_batch_context* ctx) {
834   /* TODO: don't use magic number */
835   grpc_op ops[1];
836   ops[0].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
837   ops[0].flags = 0;
838   ops[0].reserved = NULL;
839
840   return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
841                                     ctx, NULL);
842 }
843
844 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
845     grpc_call* call, grpcsharp_batch_context* ctx, grpc_status_code status_code,
846     const char* status_details, size_t status_details_len,
847     grpc_metadata_array* trailing_metadata, int32_t send_empty_initial_metadata,
848     grpc_slice_buffer* optional_send_buffer, uint32_t write_flags) {
849   /* TODO: don't use magic number */
850   grpc_op ops[3];
851   memset(ops, 0, sizeof(ops));
852   size_t nops = 1;
853   grpc_slice status_details_slice =
854       grpc_slice_from_copied_buffer(status_details, status_details_len);
855   ops[0].op = GRPC_OP_SEND_STATUS_FROM_SERVER;
856   ops[0].data.send_status_from_server.status = status_code;
857   ops[0].data.send_status_from_server.status_details = &status_details_slice;
858   grpcsharp_metadata_array_move(
859       &(ctx->send_status_from_server.trailing_metadata), trailing_metadata);
860   ops[0].data.send_status_from_server.trailing_metadata_count =
861       ctx->send_status_from_server.trailing_metadata.count;
862   ops[0].data.send_status_from_server.trailing_metadata =
863       ctx->send_status_from_server.trailing_metadata.metadata;
864   ops[0].flags = 0;
865   ops[0].reserved = NULL;
866   if (optional_send_buffer) {
867     ops[nops].op = GRPC_OP_SEND_MESSAGE;
868     ctx->send_message =
869         grpcsharp_create_byte_buffer_from_stolen_slices(optional_send_buffer);
870     ops[nops].data.send_message.send_message = ctx->send_message;
871     ops[nops].flags = write_flags;
872     ops[nops].reserved = NULL;
873     nops++;
874   }
875   if (send_empty_initial_metadata) {
876     ops[nops].op = GRPC_OP_SEND_INITIAL_METADATA;
877     ops[nops].flags = 0;
878     ops[nops].reserved = NULL;
879     nops++;
880   }
881   grpc_call_error ret = grpcsharp_call_start_batch(call, ops, nops, ctx, NULL);
882   grpc_slice_unref(status_details_slice);
883   return ret;
884 }
885
886 GPR_EXPORT grpc_call_error GPR_CALLTYPE
887 grpcsharp_call_recv_message(grpc_call* call, grpcsharp_batch_context* ctx) {
888   /* TODO: don't use magic number */
889   grpc_op ops[1];
890   ops[0].op = GRPC_OP_RECV_MESSAGE;
891   ops[0].data.recv_message.recv_message = &(ctx->recv_message);
892   ops[0].flags = 0;
893   ops[0].reserved = NULL;
894   return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
895                                     ctx, NULL);
896 }
897
898 GPR_EXPORT grpc_call_error GPR_CALLTYPE
899 grpcsharp_call_start_serverside(grpc_call* call, grpcsharp_batch_context* ctx) {
900   /* TODO: don't use magic number */
901   grpc_op ops[1];
902   ops[0].op = GRPC_OP_RECV_CLOSE_ON_SERVER;
903   ops[0].data.recv_close_on_server.cancelled =
904       (&ctx->recv_close_on_server_cancelled);
905   ops[0].flags = 0;
906   ops[0].reserved = NULL;
907
908   return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
909                                     ctx, NULL);
910 }
911
912 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_initial_metadata(
913     grpc_call* call, grpcsharp_batch_context* ctx,
914     grpc_metadata_array* initial_metadata) {
915   /* TODO: don't use magic number */
916   grpc_op ops[1];
917   memset(ops, 0, sizeof(ops));
918   ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
919   grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
920                                 initial_metadata);
921   ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
922   ops[0].data.send_initial_metadata.metadata =
923       ctx->send_initial_metadata.metadata;
924   ops[0].flags = 0;
925   ops[0].reserved = NULL;
926
927   return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
928                                     ctx, NULL);
929 }
930
931 GPR_EXPORT grpc_call_error GPR_CALLTYPE
932 grpcsharp_call_set_credentials(grpc_call* call, grpc_call_credentials* creds) {
933   return grpc_call_set_credentials(call, creds);
934 }
935
936 /* Server */
937
938 GPR_EXPORT grpc_server* GPR_CALLTYPE
939 grpcsharp_server_create(const grpc_channel_args* args) {
940   return grpc_server_create(args, NULL);
941 }
942
943 GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_register_completion_queue(
944     grpc_server* server, grpc_completion_queue* cq) {
945   grpc_server_register_completion_queue(server, cq, NULL);
946 }
947
948 GPR_EXPORT int32_t GPR_CALLTYPE grpcsharp_server_add_insecure_http2_port(
949     grpc_server* server, const char* addr) {
950   return grpc_server_add_insecure_http2_port(server, addr);
951 }
952
953 GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_start(grpc_server* server) {
954   grpc_server_start(server);
955 }
956
957 GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_shutdown_and_notify_callback(
958     grpc_server* server, grpc_completion_queue* cq,
959     grpcsharp_batch_context* ctx) {
960   grpc_server_shutdown_and_notify(server, cq, ctx);
961 }
962
963 GPR_EXPORT void GPR_CALLTYPE
964 grpcsharp_server_cancel_all_calls(grpc_server* server) {
965   grpc_server_cancel_all_calls(server);
966 }
967
968 GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_destroy(grpc_server* server) {
969   grpc_server_destroy(server);
970 }
971
972 GPR_EXPORT grpc_call_error GPR_CALLTYPE
973 grpcsharp_server_request_call(grpc_server* server, grpc_completion_queue* cq,
974                               grpcsharp_request_call_context* ctx) {
975   return grpc_server_request_call(server, &(ctx->call), &(ctx->call_details),
976                                   &(ctx->request_metadata), cq, cq, ctx);
977 }
978
979 /* Native callback dispatcher */
980
981 typedef int(GPR_CALLTYPE* grpcsharp_native_callback_dispatcher_func)(
982     void* tag, void* arg0, void* arg1, void* arg2, void* arg3, void* arg4,
983     void* arg5);
984
985 static grpcsharp_native_callback_dispatcher_func native_callback_dispatcher =
986     NULL;
987
988 GPR_EXPORT void GPR_CALLTYPE grpcsharp_native_callback_dispatcher_init(
989     grpcsharp_native_callback_dispatcher_func func) {
990   GPR_ASSERT(func);
991   native_callback_dispatcher = func;
992 }
993
994 /* Security */
995
996 static char* default_pem_root_certs = NULL;
997
998 static grpc_ssl_roots_override_result override_ssl_roots_handler(
999     char** pem_root_certs) {
1000   if (!default_pem_root_certs) {
1001     *pem_root_certs = NULL;
1002     return GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY;
1003   }
1004   *pem_root_certs = gpr_strdup(default_pem_root_certs);
1005   return GRPC_SSL_ROOTS_OVERRIDE_OK;
1006 }
1007
1008 GPR_EXPORT void GPR_CALLTYPE
1009 grpcsharp_override_default_ssl_roots(const char* pem_root_certs) {
1010   /*
1011    * This currently wastes ~300kB of memory by keeping a copy of roots
1012    * in a static variable, but for desktop/server use, the overhead
1013    * is negligible. In the future, we might want to change the behavior
1014    * for mobile (e.g. Xamarin).
1015    */
1016   default_pem_root_certs = gpr_strdup(pem_root_certs);
1017   grpc_set_ssl_roots_override_callback(override_ssl_roots_handler);
1018 }
1019
1020 static void grpcsharp_verify_peer_destroy_handler(void* userdata) {
1021   native_callback_dispatcher(userdata, NULL, NULL, (void*)1, NULL, NULL, NULL);
1022 }
1023
1024 static int grpcsharp_verify_peer_handler(const char* target_name,
1025                                          const char* peer_pem, void* userdata) {
1026   return native_callback_dispatcher(userdata, (void*)target_name,
1027                                     (void*)peer_pem, (void*)0, NULL, NULL,
1028                                     NULL);
1029 }
1030
1031 GPR_EXPORT grpc_channel_credentials* GPR_CALLTYPE
1032 grpcsharp_ssl_credentials_create(const char* pem_root_certs,
1033                                  const char* key_cert_pair_cert_chain,
1034                                  const char* key_cert_pair_private_key,
1035                                  void* verify_peer_callback_tag) {
1036   grpc_ssl_pem_key_cert_pair key_cert_pair;
1037   verify_peer_options verify_options;
1038   grpc_ssl_pem_key_cert_pair* key_cert_pair_ptr = NULL;
1039   verify_peer_options* verify_options_ptr = NULL;
1040
1041   if (key_cert_pair_cert_chain || key_cert_pair_private_key) {
1042     memset(&key_cert_pair, 0, sizeof(key_cert_pair));
1043     key_cert_pair.cert_chain = key_cert_pair_cert_chain;
1044     key_cert_pair.private_key = key_cert_pair_private_key;
1045     key_cert_pair_ptr = &key_cert_pair;
1046   } else {
1047     GPR_ASSERT(!key_cert_pair_cert_chain);
1048     GPR_ASSERT(!key_cert_pair_private_key);
1049   }
1050
1051   if (verify_peer_callback_tag != NULL) {
1052     memset(&verify_options, 0, sizeof(verify_peer_options));
1053     verify_options.verify_peer_callback_userdata = verify_peer_callback_tag;
1054     verify_options.verify_peer_destruct = grpcsharp_verify_peer_destroy_handler;
1055     verify_options.verify_peer_callback = grpcsharp_verify_peer_handler;
1056     verify_options_ptr = &verify_options;
1057   }
1058
1059   return grpc_ssl_credentials_create(pem_root_certs, key_cert_pair_ptr,
1060                                      verify_options_ptr, NULL);
1061 }
1062
1063 GPR_EXPORT void GPR_CALLTYPE
1064 grpcsharp_channel_credentials_release(grpc_channel_credentials* creds) {
1065   grpc_channel_credentials_release(creds);
1066 }
1067
1068 GPR_EXPORT void GPR_CALLTYPE
1069 grpcsharp_call_credentials_release(grpc_call_credentials* creds) {
1070   grpc_call_credentials_release(creds);
1071 }
1072
1073 GPR_EXPORT grpc_channel* GPR_CALLTYPE grpcsharp_secure_channel_create(
1074     grpc_channel_credentials* creds, const char* target,
1075     const grpc_channel_args* args) {
1076   return grpc_secure_channel_create(creds, target, args, NULL);
1077 }
1078
1079 GPR_EXPORT grpc_server_credentials* GPR_CALLTYPE
1080 grpcsharp_ssl_server_credentials_create(
1081     const char* pem_root_certs, const char** key_cert_pair_cert_chain_array,
1082     const char** key_cert_pair_private_key_array, size_t num_key_cert_pairs,
1083     grpc_ssl_client_certificate_request_type client_request_type) {
1084   size_t i;
1085   grpc_server_credentials* creds;
1086   grpc_ssl_pem_key_cert_pair* key_cert_pairs =
1087       gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs);
1088   memset(key_cert_pairs, 0,
1089          sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs);
1090
1091   for (i = 0; i < num_key_cert_pairs; i++) {
1092     if (key_cert_pair_cert_chain_array[i] ||
1093         key_cert_pair_private_key_array[i]) {
1094       key_cert_pairs[i].cert_chain = key_cert_pair_cert_chain_array[i];
1095       key_cert_pairs[i].private_key = key_cert_pair_private_key_array[i];
1096     }
1097   }
1098   creds = grpc_ssl_server_credentials_create_ex(pem_root_certs, key_cert_pairs,
1099                                                 num_key_cert_pairs,
1100                                                 client_request_type, NULL);
1101   gpr_free(key_cert_pairs);
1102   return creds;
1103 }
1104
1105 GPR_EXPORT void GPR_CALLTYPE
1106 grpcsharp_server_credentials_release(grpc_server_credentials* creds) {
1107   grpc_server_credentials_release(creds);
1108 }
1109
1110 GPR_EXPORT int32_t GPR_CALLTYPE grpcsharp_server_add_secure_http2_port(
1111     grpc_server* server, const char* addr, grpc_server_credentials* creds) {
1112   return grpc_server_add_secure_http2_port(server, addr, creds);
1113 }
1114
1115 GPR_EXPORT grpc_channel_credentials* GPR_CALLTYPE
1116 grpcsharp_composite_channel_credentials_create(
1117     grpc_channel_credentials* channel_creds,
1118     grpc_call_credentials* call_creds) {
1119   return grpc_composite_channel_credentials_create(channel_creds, call_creds,
1120                                                    NULL);
1121 }
1122
1123 GPR_EXPORT grpc_call_credentials* GPR_CALLTYPE
1124 grpcsharp_composite_call_credentials_create(grpc_call_credentials* creds1,
1125                                             grpc_call_credentials* creds2) {
1126   return grpc_composite_call_credentials_create(creds1, creds2, NULL);
1127 }
1128
1129 /* Metadata credentials plugin */
1130
1131 GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin(
1132     grpc_credentials_plugin_metadata_cb cb, void* user_data,
1133     grpc_metadata_array* metadata, grpc_status_code status,
1134     const char* error_details) {
1135   if (metadata) {
1136     cb(user_data, metadata->metadata, metadata->count, status, error_details);
1137   } else {
1138     cb(user_data, NULL, 0, status, error_details);
1139   }
1140 }
1141
1142 static int grpcsharp_get_metadata_handler(
1143     void* state, grpc_auth_metadata_context context,
1144     grpc_credentials_plugin_metadata_cb cb, void* user_data,
1145     grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
1146     size_t* num_creds_md, grpc_status_code* status,
1147     const char** error_details) {
1148   (void)creds_md;
1149   (void)num_creds_md;
1150   (void)status;
1151   (void)error_details;
1152   // the "context" object and its contents are only guaranteed to live until
1153   // this handler returns (which could result in use-after-free for async
1154   // handling of the callback), so the C# counterpart of this handler
1155   // must make a copy of the "service_url" and "method_name" strings before
1156   // it returns if it wants to uses these strings.
1157   native_callback_dispatcher(state, (void*)context.service_url,
1158                              (void*)context.method_name, cb, user_data,
1159                              (void*)0, NULL);
1160   return 0; /* Asynchronous return. */
1161 }
1162
1163 static void grpcsharp_metadata_credentials_destroy_handler(void* state) {
1164   native_callback_dispatcher(state, NULL, NULL, NULL, NULL, (void*)1, NULL);
1165 }
1166
1167 GPR_EXPORT grpc_call_credentials* GPR_CALLTYPE
1168 grpcsharp_metadata_credentials_create_from_plugin(void* callback_tag) {
1169   grpc_metadata_credentials_plugin plugin;
1170   plugin.get_metadata = grpcsharp_get_metadata_handler;
1171   plugin.destroy = grpcsharp_metadata_credentials_destroy_handler;
1172   plugin.state = callback_tag;
1173   plugin.type = "";
1174   // TODO(yihuazhang): Expose min_security_level via the C# API so
1175   // that applications can decide what minimum security level their
1176   // plugins require.
1177   return grpc_metadata_credentials_create_from_plugin(
1178       plugin, GRPC_PRIVACY_AND_INTEGRITY, NULL);
1179 }
1180
1181 /* Auth context */
1182
1183 GPR_EXPORT grpc_auth_context* GPR_CALLTYPE
1184 grpcsharp_call_auth_context(grpc_call* call) {
1185   return grpc_call_auth_context(call);
1186 }
1187
1188 GPR_EXPORT const char* GPR_CALLTYPE
1189 grpcsharp_auth_context_peer_identity_property_name(
1190     const grpc_auth_context* ctx) {
1191   return grpc_auth_context_peer_identity_property_name(ctx);
1192 }
1193
1194 GPR_EXPORT grpc_auth_property_iterator GPR_CALLTYPE
1195 grpcsharp_auth_context_property_iterator(const grpc_auth_context* ctx) {
1196   return grpc_auth_context_property_iterator(ctx);
1197 }
1198
1199 GPR_EXPORT const grpc_auth_property* GPR_CALLTYPE
1200 grpcsharp_auth_property_iterator_next(grpc_auth_property_iterator* it) {
1201   return grpc_auth_property_iterator_next(it);
1202 }
1203
1204 GPR_EXPORT void GPR_CALLTYPE
1205 grpcsharp_auth_context_release(grpc_auth_context* ctx) {
1206   grpc_auth_context_release(ctx);
1207 }
1208
1209 /* Logging */
1210
1211 typedef void(GPR_CALLTYPE* grpcsharp_log_func)(const char* file, int32_t line,
1212                                                uint64_t thd_id,
1213                                                const char* severity_string,
1214                                                const char* msg);
1215 static grpcsharp_log_func log_func = NULL;
1216
1217 /* Redirects gpr_log to log_func callback */
1218 static void grpcsharp_log_handler(gpr_log_func_args* args) {
1219   log_func(args->file, args->line, gpr_thd_currentid(),
1220            gpr_log_severity_string(args->severity), args->message);
1221 }
1222
1223 GPR_EXPORT void GPR_CALLTYPE grpcsharp_redirect_log(grpcsharp_log_func func) {
1224   GPR_ASSERT(func);
1225   log_func = func;
1226   gpr_set_log_function(grpcsharp_log_handler);
1227 }
1228
1229 typedef void(GPR_CALLTYPE* test_callback_funcptr)(int32_t success);
1230
1231 /* Slice buffer functionality */
1232 GPR_EXPORT grpc_slice_buffer* GPR_CALLTYPE grpcsharp_slice_buffer_create() {
1233   grpc_slice_buffer* slice_buffer =
1234       (grpc_slice_buffer*)gpr_malloc(sizeof(grpc_slice_buffer));
1235   grpc_slice_buffer_init(slice_buffer);
1236   return slice_buffer;
1237 }
1238
1239 GPR_EXPORT void GPR_CALLTYPE
1240 grpcsharp_slice_buffer_reset_and_unref(grpc_slice_buffer* buffer) {
1241   grpc_slice_buffer_reset_and_unref(buffer);
1242 }
1243
1244 GPR_EXPORT void GPR_CALLTYPE
1245 grpcsharp_slice_buffer_destroy(grpc_slice_buffer* buffer) {
1246   grpc_slice_buffer_destroy(buffer);
1247   gpr_free(buffer);
1248 }
1249
1250 GPR_EXPORT size_t GPR_CALLTYPE
1251 grpcsharp_slice_buffer_slice_count(grpc_slice_buffer* buffer) {
1252   return buffer->count;
1253 }
1254
1255 GPR_EXPORT void GPR_CALLTYPE
1256 grpcsharp_slice_buffer_slice_peek(grpc_slice_buffer* buffer, size_t index,
1257                                   size_t* slice_len, uint8_t** slice_data_ptr) {
1258   GPR_ASSERT(buffer->count > index);
1259   grpc_slice* slice_ptr = &buffer->slices[index];
1260   *slice_len = GRPC_SLICE_LENGTH(*slice_ptr);
1261   *slice_data_ptr = GRPC_SLICE_START_PTR(*slice_ptr);
1262 }
1263
1264 GPR_EXPORT void* GPR_CALLTYPE grpcsharp_slice_buffer_adjust_tail_space(
1265     grpc_slice_buffer* buffer, size_t available_tail_space,
1266     size_t requested_tail_space) {
1267   if (available_tail_space == requested_tail_space) {
1268     // nothing to do
1269   } else if (available_tail_space >= requested_tail_space) {
1270     grpc_slice_buffer_trim_end(
1271         buffer, available_tail_space - requested_tail_space, NULL);
1272   } else {
1273     if (available_tail_space > 0) {
1274       grpc_slice_buffer_trim_end(buffer, available_tail_space, NULL);
1275     }
1276
1277     grpc_slice new_slice = grpc_slice_malloc(requested_tail_space);
1278     // grpc_slice_buffer_add_indexed always adds as a new slice entry into the
1279     // sb (which is suboptimal in some cases) but it doesn't have the problem of
1280     // sometimes splitting the continguous new_slice across two different slices
1281     // (like grpc_slice_buffer_add would)
1282     grpc_slice_buffer_add_indexed(buffer, new_slice);
1283   }
1284
1285   if (buffer->count == 0) {
1286     return NULL;
1287   }
1288   grpc_slice* last_slice = &(buffer->slices[buffer->count - 1]);
1289   return GRPC_SLICE_END_PTR(*last_slice) - requested_tail_space;
1290 }
1291
1292 /* Version info */
1293 GPR_EXPORT const char* GPR_CALLTYPE grpcsharp_version_string() {
1294   return grpc_version_string();
1295 }
1296
1297 /* For testing */
1298 GPR_EXPORT void GPR_CALLTYPE
1299 grpcsharp_test_callback(test_callback_funcptr callback) {
1300   callback(1);
1301 }
1302
1303 /* For testing */
1304 GPR_EXPORT void* GPR_CALLTYPE grpcsharp_test_nop(void* ptr) { return ptr; }
1305
1306 /* For testing */
1307 GPR_EXPORT int32_t GPR_CALLTYPE grpcsharp_sizeof_grpc_event(void) {
1308   return sizeof(grpc_event);
1309 }
1310
1311 /* Override a method for testing */
1312 GPR_EXPORT void GPR_CALLTYPE
1313 grpcsharp_test_override_method(const char* method_name, const char* variant) {
1314   if (strcmp("grpcsharp_call_start_batch", method_name) == 0) {
1315     if (strcmp("nop", variant) == 0) {
1316       g_call_start_batch_func = grpcsharp_call_start_batch_nop;
1317     } else {
1318       GPR_ASSERT(0);
1319     }
1320   } else {
1321     GPR_ASSERT(0);
1322   }
1323 }