3 * Copyright 2015 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <grpc/byte_buffer_reader.h>
20 #include <grpc/grpc.h>
21 #include <grpc/grpc_security.h>
22 #include <grpc/slice.h>
23 #include <grpc/support/alloc.h>
24 #include <grpc/support/log.h>
25 #include <grpc/support/port_platform.h>
26 #include <grpc/support/string_util.h>
27 #include <grpc/support/thd_id.h>
32 #define GPR_EXPORT __declspec(dllexport)
33 #define GPR_CALLTYPE __stdcall
44 grpc_byte_buffer* string_to_byte_buffer(const char* buffer, size_t len) {
45 grpc_slice slice = grpc_slice_from_copied_buffer(buffer, len);
46 grpc_byte_buffer* bb = grpc_raw_byte_buffer_create(&slice, 1);
47 grpc_slice_unref(slice);
52 * Helper to maintain lifetime of batch op inputs and store batch op outputs.
54 typedef struct grpcsharp_batch_context {
55 grpc_metadata_array send_initial_metadata;
56 grpc_byte_buffer* send_message;
58 grpc_metadata_array trailing_metadata;
59 } send_status_from_server;
60 grpc_metadata_array recv_initial_metadata;
61 grpc_byte_buffer* recv_message;
63 grpc_metadata_array trailing_metadata;
64 grpc_status_code status;
65 grpc_slice status_details;
66 } recv_status_on_client;
67 int recv_close_on_server_cancelled;
68 } grpcsharp_batch_context;
70 GPR_EXPORT grpcsharp_batch_context* GPR_CALLTYPE
71 grpcsharp_batch_context_create() {
72 grpcsharp_batch_context* ctx = gpr_malloc(sizeof(grpcsharp_batch_context));
73 memset(ctx, 0, sizeof(grpcsharp_batch_context));
79 grpc_call_details call_details;
80 grpc_metadata_array request_metadata;
81 } grpcsharp_request_call_context;
83 GPR_EXPORT grpcsharp_request_call_context* GPR_CALLTYPE
84 grpcsharp_request_call_context_create() {
85 grpcsharp_request_call_context* ctx =
86 gpr_malloc(sizeof(grpcsharp_request_call_context));
87 memset(ctx, 0, sizeof(grpcsharp_request_call_context));
92 * Destroys array->metadata.
93 * The array pointer itself is not freed.
95 void grpcsharp_metadata_array_destroy_metadata_only(
96 grpc_metadata_array* array) {
97 gpr_free(array->metadata);
101 * Destroys keys, values and array->metadata.
102 * The array pointer itself is not freed.
104 void grpcsharp_metadata_array_destroy_metadata_including_entries(
105 grpc_metadata_array* array) {
107 if (array->metadata) {
108 for (i = 0; i < array->count; i++) {
109 grpc_slice_unref(array->metadata[i].key);
110 grpc_slice_unref(array->metadata[i].value);
113 gpr_free(array->metadata);
117 * Fully destroys the metadata array.
119 GPR_EXPORT void GPR_CALLTYPE
120 grpcsharp_metadata_array_destroy_full(grpc_metadata_array* array) {
124 grpcsharp_metadata_array_destroy_metadata_including_entries(array);
129 * Creates an empty metadata array with given capacity.
130 * Array can later be destroyed by grpc_metadata_array_destroy_full.
132 GPR_EXPORT grpc_metadata_array* GPR_CALLTYPE
133 grpcsharp_metadata_array_create(size_t capacity) {
134 grpc_metadata_array* array =
135 (grpc_metadata_array*)gpr_malloc(sizeof(grpc_metadata_array));
136 grpc_metadata_array_init(array);
137 array->capacity = capacity;
141 (grpc_metadata*)gpr_malloc(sizeof(grpc_metadata) * capacity);
142 memset(array->metadata, 0, sizeof(grpc_metadata) * capacity);
144 array->metadata = NULL;
149 GPR_EXPORT void GPR_CALLTYPE
150 grpcsharp_metadata_array_add(grpc_metadata_array* array, const char* key,
151 const char* value, size_t value_length) {
152 size_t i = array->count;
153 GPR_ASSERT(array->count < array->capacity);
154 array->metadata[i].key = grpc_slice_from_copied_string(key);
155 array->metadata[i].value = grpc_slice_from_copied_buffer(value, value_length);
159 GPR_EXPORT intptr_t GPR_CALLTYPE
160 grpcsharp_metadata_array_count(grpc_metadata_array* array) {
161 return (intptr_t)array->count;
164 GPR_EXPORT const char* GPR_CALLTYPE grpcsharp_metadata_array_get_key(
165 grpc_metadata_array* array, size_t index, size_t* key_length) {
166 GPR_ASSERT(index < array->count);
167 *key_length = GRPC_SLICE_LENGTH(array->metadata[index].key);
168 return (char*)GRPC_SLICE_START_PTR(array->metadata[index].key);
171 GPR_EXPORT const char* GPR_CALLTYPE grpcsharp_metadata_array_get_value(
172 grpc_metadata_array* array, size_t index, size_t* value_length) {
173 GPR_ASSERT(index < array->count);
174 *value_length = GRPC_SLICE_LENGTH(array->metadata[index].value);
175 return (char*)GRPC_SLICE_START_PTR(array->metadata[index].value);
178 /* Move contents of metadata array */
179 void grpcsharp_metadata_array_move(grpc_metadata_array* dest,
180 grpc_metadata_array* src) {
184 dest->metadata = NULL;
188 dest->capacity = src->capacity;
189 dest->count = src->count;
190 dest->metadata = src->metadata;
194 src->metadata = NULL;
197 GPR_EXPORT void GPR_CALLTYPE
198 grpcsharp_batch_context_reset(grpcsharp_batch_context* ctx) {
199 grpcsharp_metadata_array_destroy_metadata_including_entries(
200 &(ctx->send_initial_metadata));
202 grpc_byte_buffer_destroy(ctx->send_message);
204 grpcsharp_metadata_array_destroy_metadata_including_entries(
205 &(ctx->send_status_from_server.trailing_metadata));
207 grpcsharp_metadata_array_destroy_metadata_only(&(ctx->recv_initial_metadata));
209 grpc_byte_buffer_destroy(ctx->recv_message);
211 grpcsharp_metadata_array_destroy_metadata_only(
212 &(ctx->recv_status_on_client.trailing_metadata));
213 grpc_slice_unref(ctx->recv_status_on_client.status_details);
214 memset(ctx, 0, sizeof(grpcsharp_batch_context));
217 GPR_EXPORT void GPR_CALLTYPE
218 grpcsharp_batch_context_destroy(grpcsharp_batch_context* ctx) {
222 grpcsharp_batch_context_reset(ctx);
226 GPR_EXPORT void GPR_CALLTYPE
227 grpcsharp_request_call_context_reset(grpcsharp_request_call_context* ctx) {
228 /* NOTE: ctx->server_rpc_new.call is not destroyed because callback handler is
230 to take its ownership. */
232 grpc_call_details_destroy(&(ctx->call_details));
233 grpcsharp_metadata_array_destroy_metadata_only(&(ctx->request_metadata));
234 memset(ctx, 0, sizeof(grpcsharp_request_call_context));
237 GPR_EXPORT void GPR_CALLTYPE
238 grpcsharp_request_call_context_destroy(grpcsharp_request_call_context* ctx) {
242 grpcsharp_request_call_context_reset(ctx);
246 GPR_EXPORT const grpc_metadata_array* GPR_CALLTYPE
247 grpcsharp_batch_context_recv_initial_metadata(
248 const grpcsharp_batch_context* ctx) {
249 return &(ctx->recv_initial_metadata);
252 GPR_EXPORT intptr_t GPR_CALLTYPE grpcsharp_batch_context_recv_message_length(
253 const grpcsharp_batch_context* ctx) {
254 grpc_byte_buffer_reader reader;
255 if (!ctx->recv_message) {
259 GPR_ASSERT(grpc_byte_buffer_reader_init(&reader, ctx->recv_message));
260 intptr_t result = (intptr_t)grpc_byte_buffer_length(reader.buffer_out);
261 grpc_byte_buffer_reader_destroy(&reader);
267 * Copies data from recv_message to a buffer. Fatal error occurs if
268 * buffer is too small.
270 GPR_EXPORT void GPR_CALLTYPE grpcsharp_batch_context_recv_message_to_buffer(
271 const grpcsharp_batch_context* ctx, char* buffer, size_t buffer_len) {
272 grpc_byte_buffer_reader reader;
276 GPR_ASSERT(grpc_byte_buffer_reader_init(&reader, ctx->recv_message));
278 while (grpc_byte_buffer_reader_next(&reader, &slice)) {
279 size_t len = GRPC_SLICE_LENGTH(slice);
280 GPR_ASSERT(offset + len <= buffer_len);
281 memcpy(buffer + offset, GRPC_SLICE_START_PTR(slice),
282 GRPC_SLICE_LENGTH(slice));
284 grpc_slice_unref(slice);
287 grpc_byte_buffer_reader_destroy(&reader);
290 GPR_EXPORT grpc_status_code GPR_CALLTYPE
291 grpcsharp_batch_context_recv_status_on_client_status(
292 const grpcsharp_batch_context* ctx) {
293 return ctx->recv_status_on_client.status;
296 GPR_EXPORT const char* GPR_CALLTYPE
297 grpcsharp_batch_context_recv_status_on_client_details(
298 const grpcsharp_batch_context* ctx, size_t* details_length) {
300 GRPC_SLICE_LENGTH(ctx->recv_status_on_client.status_details);
301 return (char*)GRPC_SLICE_START_PTR(ctx->recv_status_on_client.status_details);
304 GPR_EXPORT const grpc_metadata_array* GPR_CALLTYPE
305 grpcsharp_batch_context_recv_status_on_client_trailing_metadata(
306 const grpcsharp_batch_context* ctx) {
307 return &(ctx->recv_status_on_client.trailing_metadata);
310 GPR_EXPORT grpc_call* GPR_CALLTYPE
311 grpcsharp_request_call_context_call(const grpcsharp_request_call_context* ctx) {
315 GPR_EXPORT const char* GPR_CALLTYPE grpcsharp_request_call_context_method(
316 const grpcsharp_request_call_context* ctx, size_t* method_length) {
317 *method_length = GRPC_SLICE_LENGTH(ctx->call_details.method);
318 return (char*)GRPC_SLICE_START_PTR(ctx->call_details.method);
321 GPR_EXPORT const char* GPR_CALLTYPE grpcsharp_request_call_context_host(
322 const grpcsharp_request_call_context* ctx, size_t* host_length) {
323 *host_length = GRPC_SLICE_LENGTH(ctx->call_details.host);
324 return (char*)GRPC_SLICE_START_PTR(ctx->call_details.host);
327 GPR_EXPORT gpr_timespec GPR_CALLTYPE grpcsharp_request_call_context_deadline(
328 const grpcsharp_request_call_context* ctx) {
329 return ctx->call_details.deadline;
332 GPR_EXPORT const grpc_metadata_array* GPR_CALLTYPE
333 grpcsharp_request_call_context_request_metadata(
334 const grpcsharp_request_call_context* ctx) {
335 return &(ctx->request_metadata);
338 GPR_EXPORT int32_t GPR_CALLTYPE
339 grpcsharp_batch_context_recv_close_on_server_cancelled(
340 const grpcsharp_batch_context* ctx) {
341 return (int32_t)ctx->recv_close_on_server_cancelled;
344 /* Init & shutdown */
346 GPR_EXPORT void GPR_CALLTYPE grpcsharp_init(void) { grpc_init(); }
348 GPR_EXPORT void GPR_CALLTYPE grpcsharp_shutdown(void) { grpc_shutdown(); }
350 /* Completion queue */
352 GPR_EXPORT grpc_completion_queue* GPR_CALLTYPE
353 grpcsharp_completion_queue_create_async(void) {
354 return grpc_completion_queue_create_for_next(NULL);
357 GPR_EXPORT grpc_completion_queue* GPR_CALLTYPE
358 grpcsharp_completion_queue_create_sync(void) {
359 return grpc_completion_queue_create_for_pluck(NULL);
362 GPR_EXPORT void GPR_CALLTYPE
363 grpcsharp_completion_queue_shutdown(grpc_completion_queue* cq) {
364 grpc_completion_queue_shutdown(cq);
367 GPR_EXPORT void GPR_CALLTYPE
368 grpcsharp_completion_queue_destroy(grpc_completion_queue* cq) {
369 grpc_completion_queue_destroy(cq);
372 GPR_EXPORT grpc_event GPR_CALLTYPE
373 grpcsharp_completion_queue_next(grpc_completion_queue* cq) {
374 return grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME),
378 GPR_EXPORT grpc_event GPR_CALLTYPE
379 grpcsharp_completion_queue_pluck(grpc_completion_queue* cq, void* tag) {
380 return grpc_completion_queue_pluck(cq, tag,
381 gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
386 GPR_EXPORT grpc_channel* GPR_CALLTYPE
388 grpcsharp_insecure_channel_create(const char* target,
389 const grpc_channel_args* args) {
390 return grpc_insecure_channel_create(target, args, NULL);
393 GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_destroy(grpc_channel* channel) {
394 grpc_channel_destroy(channel);
397 GPR_EXPORT grpc_call* GPR_CALLTYPE grpcsharp_channel_create_call(
398 grpc_channel* channel, grpc_call* parent_call, uint32_t propagation_mask,
399 grpc_completion_queue* cq, const char* method, const char* host,
400 gpr_timespec deadline) {
401 grpc_slice method_slice = grpc_slice_from_copied_string(method);
402 grpc_slice* host_slice_ptr = NULL;
403 grpc_slice host_slice;
405 host_slice = grpc_slice_from_copied_string(host);
406 host_slice_ptr = &host_slice;
409 grpc_channel_create_call(channel, parent_call, propagation_mask, cq,
410 method_slice, host_slice_ptr, deadline, NULL);
411 grpc_slice_unref(method_slice);
413 grpc_slice_unref(host_slice);
418 GPR_EXPORT grpc_connectivity_state GPR_CALLTYPE
419 grpcsharp_channel_check_connectivity_state(grpc_channel* channel,
420 int32_t try_to_connect) {
421 return grpc_channel_check_connectivity_state(channel, try_to_connect);
424 GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_watch_connectivity_state(
425 grpc_channel* channel, grpc_connectivity_state last_observed_state,
426 gpr_timespec deadline, grpc_completion_queue* cq,
427 grpcsharp_batch_context* ctx) {
428 grpc_channel_watch_connectivity_state(channel, last_observed_state, deadline,
432 GPR_EXPORT char* GPR_CALLTYPE
433 grpcsharp_channel_get_target(grpc_channel* channel) {
434 return grpc_channel_get_target(channel);
439 GPR_EXPORT grpc_channel_args* GPR_CALLTYPE
440 grpcsharp_channel_args_create(size_t num_args) {
441 grpc_channel_args* args =
442 (grpc_channel_args*)gpr_malloc(sizeof(grpc_channel_args));
443 memset(args, 0, sizeof(grpc_channel_args));
445 args->num_args = num_args;
446 args->args = (grpc_arg*)gpr_malloc(sizeof(grpc_arg) * num_args);
447 memset(args->args, 0, sizeof(grpc_arg) * num_args);
451 GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_args_set_string(
452 grpc_channel_args* args, size_t index, const char* key, const char* value) {
454 GPR_ASSERT(index < args->num_args);
455 args->args[index].type = GRPC_ARG_STRING;
456 args->args[index].key = gpr_strdup(key);
457 args->args[index].value.string = gpr_strdup(value);
460 GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_args_set_integer(
461 grpc_channel_args* args, size_t index, const char* key, int value) {
463 GPR_ASSERT(index < args->num_args);
464 args->args[index].type = GRPC_ARG_INTEGER;
465 args->args[index].key = gpr_strdup(key);
466 args->args[index].value.integer = value;
469 GPR_EXPORT void GPR_CALLTYPE
470 grpcsharp_channel_args_destroy(grpc_channel_args* args) {
473 for (i = 0; i < args->num_args; i++) {
474 gpr_free(args->args[i].key);
475 if (args->args[i].type == GRPC_ARG_STRING) {
476 gpr_free(args->args[i].value.string);
479 gpr_free(args->args);
486 GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_now(gpr_clock_type clock_type) {
487 return gpr_now(clock_type);
490 GPR_EXPORT gpr_timespec GPR_CALLTYPE
491 gprsharp_inf_future(gpr_clock_type clock_type) {
492 return gpr_inf_future(clock_type);
495 GPR_EXPORT gpr_timespec GPR_CALLTYPE
496 gprsharp_inf_past(gpr_clock_type clock_type) {
497 return gpr_inf_past(clock_type);
500 GPR_EXPORT gpr_timespec GPR_CALLTYPE
501 gprsharp_convert_clock_type(gpr_timespec t, gpr_clock_type target_clock) {
502 return gpr_convert_clock_type(t, target_clock);
505 GPR_EXPORT int32_t GPR_CALLTYPE gprsharp_sizeof_timespec(void) {
506 return sizeof(gpr_timespec);
511 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_cancel(grpc_call* call) {
512 return grpc_call_cancel(call, NULL);
515 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_cancel_with_status(
516 grpc_call* call, grpc_status_code status, const char* description) {
517 return grpc_call_cancel_with_status(call, status, description, NULL);
520 GPR_EXPORT char* GPR_CALLTYPE grpcsharp_call_get_peer(grpc_call* call) {
521 return grpc_call_get_peer(call);
524 GPR_EXPORT void GPR_CALLTYPE gprsharp_free(void* p) { gpr_free(p); }
526 GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_destroy(grpc_call* call) {
527 grpc_call_unref(call);
530 typedef grpc_call_error (*grpcsharp_call_start_batch_func)(grpc_call* call,
536 /* Only for testing */
537 static grpc_call_error grpcsharp_call_start_batch_nop(grpc_call* call,
539 size_t nops, void* tag,
544 static grpc_call_error grpcsharp_call_start_batch_default(grpc_call* call,
549 return grpc_call_start_batch(call, ops, nops, tag, reserved);
552 static grpcsharp_call_start_batch_func g_call_start_batch_func =
553 grpcsharp_call_start_batch_default;
555 static grpc_call_error grpcsharp_call_start_batch(grpc_call* call,
557 size_t nops, void* tag,
559 return g_call_start_batch_func(call, ops, nops, tag, reserved);
562 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_unary(
563 grpc_call* call, grpcsharp_batch_context* ctx, const char* send_buffer,
564 size_t send_buffer_len, uint32_t write_flags,
565 grpc_metadata_array* initial_metadata, uint32_t initial_metadata_flags) {
566 /* TODO: don't use magic number */
568 memset(ops, 0, sizeof(ops));
569 ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
570 grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
572 ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
573 ops[0].data.send_initial_metadata.metadata =
574 ctx->send_initial_metadata.metadata;
575 ops[0].flags = initial_metadata_flags;
576 ops[0].reserved = NULL;
578 ops[1].op = GRPC_OP_SEND_MESSAGE;
579 ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
580 ops[1].data.send_message.send_message = ctx->send_message;
581 ops[1].flags = write_flags;
582 ops[1].reserved = NULL;
584 ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
586 ops[2].reserved = NULL;
588 ops[3].op = GRPC_OP_RECV_INITIAL_METADATA;
589 ops[3].data.recv_initial_metadata.recv_initial_metadata =
590 &(ctx->recv_initial_metadata);
592 ops[3].reserved = NULL;
594 ops[4].op = GRPC_OP_RECV_MESSAGE;
595 ops[4].data.recv_message.recv_message = &(ctx->recv_message);
597 ops[4].reserved = NULL;
599 ops[5].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
600 ops[5].data.recv_status_on_client.trailing_metadata =
601 &(ctx->recv_status_on_client.trailing_metadata);
602 ops[5].data.recv_status_on_client.status =
603 &(ctx->recv_status_on_client.status);
604 ops[5].data.recv_status_on_client.status_details =
605 &(ctx->recv_status_on_client.status_details);
607 ops[5].reserved = NULL;
609 return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
613 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_client_streaming(
614 grpc_call* call, grpcsharp_batch_context* ctx,
615 grpc_metadata_array* initial_metadata, uint32_t initial_metadata_flags) {
616 /* TODO: don't use magic number */
618 memset(ops, 0, sizeof(ops));
619 ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
620 grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
622 ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
623 ops[0].data.send_initial_metadata.metadata =
624 ctx->send_initial_metadata.metadata;
625 ops[0].flags = initial_metadata_flags;
626 ops[0].reserved = NULL;
628 ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
629 ops[1].data.recv_initial_metadata.recv_initial_metadata =
630 &(ctx->recv_initial_metadata);
632 ops[1].reserved = NULL;
634 ops[2].op = GRPC_OP_RECV_MESSAGE;
635 ops[2].data.recv_message.recv_message = &(ctx->recv_message);
637 ops[2].reserved = NULL;
639 ops[3].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
640 ops[3].data.recv_status_on_client.trailing_metadata =
641 &(ctx->recv_status_on_client.trailing_metadata);
642 ops[3].data.recv_status_on_client.status =
643 &(ctx->recv_status_on_client.status);
644 ops[3].data.recv_status_on_client.status_details =
645 &(ctx->recv_status_on_client.status_details);
647 ops[3].reserved = NULL;
649 return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
653 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
654 grpc_call* call, grpcsharp_batch_context* ctx, const char* send_buffer,
655 size_t send_buffer_len, uint32_t write_flags,
656 grpc_metadata_array* initial_metadata, uint32_t initial_metadata_flags) {
657 /* TODO: don't use magic number */
659 memset(ops, 0, sizeof(ops));
660 ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
661 grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
663 ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
664 ops[0].data.send_initial_metadata.metadata =
665 ctx->send_initial_metadata.metadata;
666 ops[0].flags = initial_metadata_flags;
667 ops[0].reserved = NULL;
669 ops[1].op = GRPC_OP_SEND_MESSAGE;
670 ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
671 ops[1].data.send_message.send_message = ctx->send_message;
672 ops[1].flags = write_flags;
673 ops[1].reserved = NULL;
675 ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
677 ops[2].reserved = NULL;
679 ops[3].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
680 ops[3].data.recv_status_on_client.trailing_metadata =
681 &(ctx->recv_status_on_client.trailing_metadata);
682 ops[3].data.recv_status_on_client.status =
683 &(ctx->recv_status_on_client.status);
684 ops[3].data.recv_status_on_client.status_details =
685 &(ctx->recv_status_on_client.status_details);
687 ops[3].reserved = NULL;
689 return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
693 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_duplex_streaming(
694 grpc_call* call, grpcsharp_batch_context* ctx,
695 grpc_metadata_array* initial_metadata, uint32_t initial_metadata_flags) {
696 /* TODO: don't use magic number */
698 memset(ops, 0, sizeof(ops));
699 ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
700 grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
702 ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
703 ops[0].data.send_initial_metadata.metadata =
704 ctx->send_initial_metadata.metadata;
705 ops[0].flags = initial_metadata_flags;
706 ops[0].reserved = NULL;
708 ops[1].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
709 ops[1].data.recv_status_on_client.trailing_metadata =
710 &(ctx->recv_status_on_client.trailing_metadata);
711 ops[1].data.recv_status_on_client.status =
712 &(ctx->recv_status_on_client.status);
713 ops[1].data.recv_status_on_client.status_details =
714 &(ctx->recv_status_on_client.status_details);
716 ops[1].reserved = NULL;
718 return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
722 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_recv_initial_metadata(
723 grpc_call* call, grpcsharp_batch_context* ctx) {
724 /* TODO: don't use magic number */
726 ops[0].op = GRPC_OP_RECV_INITIAL_METADATA;
727 ops[0].data.recv_initial_metadata.recv_initial_metadata =
728 &(ctx->recv_initial_metadata);
730 ops[0].reserved = NULL;
732 return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
736 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_message(
737 grpc_call* call, grpcsharp_batch_context* ctx, const char* send_buffer,
738 size_t send_buffer_len, uint32_t write_flags,
739 int32_t send_empty_initial_metadata) {
740 /* TODO: don't use magic number */
742 memset(ops, 0, sizeof(ops));
743 size_t nops = send_empty_initial_metadata ? 2 : 1;
744 ops[0].op = GRPC_OP_SEND_MESSAGE;
745 ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
746 ops[0].data.send_message.send_message = ctx->send_message;
747 ops[0].flags = write_flags;
748 ops[0].reserved = NULL;
749 ops[1].op = GRPC_OP_SEND_INITIAL_METADATA;
751 ops[1].reserved = NULL;
753 return grpcsharp_call_start_batch(call, ops, nops, ctx, NULL);
756 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_close_from_client(
757 grpc_call* call, grpcsharp_batch_context* ctx) {
758 /* TODO: don't use magic number */
760 ops[0].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
762 ops[0].reserved = NULL;
764 return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
768 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
769 grpc_call* call, grpcsharp_batch_context* ctx, grpc_status_code status_code,
770 const char* status_details, size_t status_details_len,
771 grpc_metadata_array* trailing_metadata, int32_t send_empty_initial_metadata,
772 const char* optional_send_buffer, size_t optional_send_buffer_len,
773 uint32_t write_flags) {
774 /* TODO: don't use magic number */
776 memset(ops, 0, sizeof(ops));
778 grpc_slice status_details_slice =
779 grpc_slice_from_copied_buffer(status_details, status_details_len);
780 ops[0].op = GRPC_OP_SEND_STATUS_FROM_SERVER;
781 ops[0].data.send_status_from_server.status = status_code;
782 ops[0].data.send_status_from_server.status_details = &status_details_slice;
783 grpcsharp_metadata_array_move(
784 &(ctx->send_status_from_server.trailing_metadata), trailing_metadata);
785 ops[0].data.send_status_from_server.trailing_metadata_count =
786 ctx->send_status_from_server.trailing_metadata.count;
787 ops[0].data.send_status_from_server.trailing_metadata =
788 ctx->send_status_from_server.trailing_metadata.metadata;
790 ops[0].reserved = NULL;
791 if (optional_send_buffer) {
792 ops[nops].op = GRPC_OP_SEND_MESSAGE;
794 string_to_byte_buffer(optional_send_buffer, optional_send_buffer_len);
795 ops[nops].data.send_message.send_message = ctx->send_message;
796 ops[nops].flags = write_flags;
797 ops[nops].reserved = NULL;
800 if (send_empty_initial_metadata) {
801 ops[nops].op = GRPC_OP_SEND_INITIAL_METADATA;
803 ops[nops].reserved = NULL;
806 grpc_call_error ret = grpcsharp_call_start_batch(call, ops, nops, ctx, NULL);
807 grpc_slice_unref(status_details_slice);
811 GPR_EXPORT grpc_call_error GPR_CALLTYPE
812 grpcsharp_call_recv_message(grpc_call* call, grpcsharp_batch_context* ctx) {
813 /* TODO: don't use magic number */
815 ops[0].op = GRPC_OP_RECV_MESSAGE;
816 ops[0].data.recv_message.recv_message = &(ctx->recv_message);
818 ops[0].reserved = NULL;
819 return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
823 GPR_EXPORT grpc_call_error GPR_CALLTYPE
824 grpcsharp_call_start_serverside(grpc_call* call, grpcsharp_batch_context* ctx) {
825 /* TODO: don't use magic number */
827 ops[0].op = GRPC_OP_RECV_CLOSE_ON_SERVER;
828 ops[0].data.recv_close_on_server.cancelled =
829 (&ctx->recv_close_on_server_cancelled);
831 ops[0].reserved = NULL;
833 return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
837 GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_initial_metadata(
838 grpc_call* call, grpcsharp_batch_context* ctx,
839 grpc_metadata_array* initial_metadata) {
840 /* TODO: don't use magic number */
842 memset(ops, 0, sizeof(ops));
843 ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
844 grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
846 ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
847 ops[0].data.send_initial_metadata.metadata =
848 ctx->send_initial_metadata.metadata;
850 ops[0].reserved = NULL;
852 return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
856 GPR_EXPORT grpc_call_error GPR_CALLTYPE
857 grpcsharp_call_set_credentials(grpc_call* call, grpc_call_credentials* creds) {
858 return grpc_call_set_credentials(call, creds);
863 GPR_EXPORT grpc_server* GPR_CALLTYPE
864 grpcsharp_server_create(const grpc_channel_args* args) {
865 return grpc_server_create(args, NULL);
868 GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_register_completion_queue(
869 grpc_server* server, grpc_completion_queue* cq) {
870 grpc_server_register_completion_queue(server, cq, NULL);
873 GPR_EXPORT int32_t GPR_CALLTYPE grpcsharp_server_add_insecure_http2_port(
874 grpc_server* server, const char* addr) {
875 return grpc_server_add_insecure_http2_port(server, addr);
878 GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_start(grpc_server* server) {
879 grpc_server_start(server);
882 GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_shutdown_and_notify_callback(
883 grpc_server* server, grpc_completion_queue* cq,
884 grpcsharp_batch_context* ctx) {
885 grpc_server_shutdown_and_notify(server, cq, ctx);
888 GPR_EXPORT void GPR_CALLTYPE
889 grpcsharp_server_cancel_all_calls(grpc_server* server) {
890 grpc_server_cancel_all_calls(server);
893 GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_destroy(grpc_server* server) {
894 grpc_server_destroy(server);
897 GPR_EXPORT grpc_call_error GPR_CALLTYPE
898 grpcsharp_server_request_call(grpc_server* server, grpc_completion_queue* cq,
899 grpcsharp_request_call_context* ctx) {
900 return grpc_server_request_call(server, &(ctx->call), &(ctx->call_details),
901 &(ctx->request_metadata), cq, cq, ctx);
906 static char* default_pem_root_certs = NULL;
908 static grpc_ssl_roots_override_result override_ssl_roots_handler(
909 char** pem_root_certs) {
910 if (!default_pem_root_certs) {
911 *pem_root_certs = NULL;
912 return GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY;
914 *pem_root_certs = gpr_strdup(default_pem_root_certs);
915 return GRPC_SSL_ROOTS_OVERRIDE_OK;
918 GPR_EXPORT void GPR_CALLTYPE
919 grpcsharp_override_default_ssl_roots(const char* pem_root_certs) {
921 * This currently wastes ~300kB of memory by keeping a copy of roots
922 * in a static variable, but for desktop/server use, the overhead
923 * is negligible. In the future, we might want to change the behavior
924 * for mobile (e.g. Xamarin).
926 default_pem_root_certs = gpr_strdup(pem_root_certs);
927 grpc_set_ssl_roots_override_callback(override_ssl_roots_handler);
930 GPR_EXPORT grpc_channel_credentials* GPR_CALLTYPE
931 grpcsharp_ssl_credentials_create(const char* pem_root_certs,
932 const char* key_cert_pair_cert_chain,
933 const char* key_cert_pair_private_key) {
934 grpc_ssl_pem_key_cert_pair key_cert_pair;
935 if (key_cert_pair_cert_chain || key_cert_pair_private_key) {
936 key_cert_pair.cert_chain = key_cert_pair_cert_chain;
937 key_cert_pair.private_key = key_cert_pair_private_key;
938 return grpc_ssl_credentials_create(pem_root_certs, &key_cert_pair, NULL,
941 GPR_ASSERT(!key_cert_pair_cert_chain);
942 GPR_ASSERT(!key_cert_pair_private_key);
943 return grpc_ssl_credentials_create(pem_root_certs, NULL, NULL, NULL);
947 GPR_EXPORT void GPR_CALLTYPE
948 grpcsharp_channel_credentials_release(grpc_channel_credentials* creds) {
949 grpc_channel_credentials_release(creds);
952 GPR_EXPORT void GPR_CALLTYPE
953 grpcsharp_call_credentials_release(grpc_call_credentials* creds) {
954 grpc_call_credentials_release(creds);
957 GPR_EXPORT grpc_channel* GPR_CALLTYPE grpcsharp_secure_channel_create(
958 grpc_channel_credentials* creds, const char* target,
959 const grpc_channel_args* args) {
960 return grpc_secure_channel_create(creds, target, args, NULL);
963 GPR_EXPORT grpc_server_credentials* GPR_CALLTYPE
964 grpcsharp_ssl_server_credentials_create(
965 const char* pem_root_certs, const char** key_cert_pair_cert_chain_array,
966 const char** key_cert_pair_private_key_array, size_t num_key_cert_pairs,
967 grpc_ssl_client_certificate_request_type client_request_type) {
969 grpc_server_credentials* creds;
970 grpc_ssl_pem_key_cert_pair* key_cert_pairs =
971 gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs);
972 memset(key_cert_pairs, 0,
973 sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs);
975 for (i = 0; i < num_key_cert_pairs; i++) {
976 if (key_cert_pair_cert_chain_array[i] ||
977 key_cert_pair_private_key_array[i]) {
978 key_cert_pairs[i].cert_chain = key_cert_pair_cert_chain_array[i];
979 key_cert_pairs[i].private_key = key_cert_pair_private_key_array[i];
982 creds = grpc_ssl_server_credentials_create_ex(pem_root_certs, key_cert_pairs,
984 client_request_type, NULL);
985 gpr_free(key_cert_pairs);
989 GPR_EXPORT void GPR_CALLTYPE
990 grpcsharp_server_credentials_release(grpc_server_credentials* creds) {
991 grpc_server_credentials_release(creds);
994 GPR_EXPORT int32_t GPR_CALLTYPE grpcsharp_server_add_secure_http2_port(
995 grpc_server* server, const char* addr, grpc_server_credentials* creds) {
996 return grpc_server_add_secure_http2_port(server, addr, creds);
999 GPR_EXPORT grpc_channel_credentials* GPR_CALLTYPE
1000 grpcsharp_composite_channel_credentials_create(
1001 grpc_channel_credentials* channel_creds,
1002 grpc_call_credentials* call_creds) {
1003 return grpc_composite_channel_credentials_create(channel_creds, call_creds,
1007 GPR_EXPORT grpc_call_credentials* GPR_CALLTYPE
1008 grpcsharp_composite_call_credentials_create(grpc_call_credentials* creds1,
1009 grpc_call_credentials* creds2) {
1010 return grpc_composite_call_credentials_create(creds1, creds2, NULL);
1013 /* Native callback dispatcher */
1015 typedef int(GPR_CALLTYPE* grpcsharp_native_callback_dispatcher_func)(
1016 void* tag, void* arg0, void* arg1, void* arg2, void* arg3, void* arg4,
1019 static grpcsharp_native_callback_dispatcher_func native_callback_dispatcher =
1022 GPR_EXPORT void GPR_CALLTYPE grpcsharp_native_callback_dispatcher_init(
1023 grpcsharp_native_callback_dispatcher_func func) {
1025 native_callback_dispatcher = func;
1028 /* Metadata credentials plugin */
1030 GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin(
1031 grpc_credentials_plugin_metadata_cb cb, void* user_data,
1032 grpc_metadata_array* metadata, grpc_status_code status,
1033 const char* error_details) {
1035 cb(user_data, metadata->metadata, metadata->count, status, error_details);
1037 cb(user_data, NULL, 0, status, error_details);
1041 static int grpcsharp_get_metadata_handler(
1042 void* state, grpc_auth_metadata_context context,
1043 grpc_credentials_plugin_metadata_cb cb, void* user_data,
1044 grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
1045 size_t* num_creds_md, grpc_status_code* status,
1046 const char** error_details) {
1047 native_callback_dispatcher(state, (void*)context.service_url,
1048 (void*)context.method_name, cb, user_data,
1050 return 0; /* Asynchronous return. */
1053 static void grpcsharp_metadata_credentials_destroy_handler(void* state) {
1054 native_callback_dispatcher(state, NULL, NULL, NULL, NULL, (void*)1, NULL);
1057 GPR_EXPORT grpc_call_credentials* GPR_CALLTYPE
1058 grpcsharp_metadata_credentials_create_from_plugin(void* callback_tag) {
1059 grpc_metadata_credentials_plugin plugin;
1060 plugin.get_metadata = grpcsharp_get_metadata_handler;
1061 plugin.destroy = grpcsharp_metadata_credentials_destroy_handler;
1062 plugin.state = callback_tag;
1064 return grpc_metadata_credentials_create_from_plugin(plugin, NULL);
1069 GPR_EXPORT grpc_auth_context* GPR_CALLTYPE
1070 grpcsharp_call_auth_context(grpc_call* call) {
1071 return grpc_call_auth_context(call);
1074 GPR_EXPORT const char* GPR_CALLTYPE
1075 grpcsharp_auth_context_peer_identity_property_name(
1076 const grpc_auth_context* ctx) {
1077 return grpc_auth_context_peer_identity_property_name(ctx);
1080 GPR_EXPORT grpc_auth_property_iterator GPR_CALLTYPE
1081 grpcsharp_auth_context_property_iterator(const grpc_auth_context* ctx) {
1082 return grpc_auth_context_property_iterator(ctx);
1085 GPR_EXPORT const grpc_auth_property* GPR_CALLTYPE
1086 grpcsharp_auth_property_iterator_next(grpc_auth_property_iterator* it) {
1087 return grpc_auth_property_iterator_next(it);
1090 GPR_EXPORT void GPR_CALLTYPE
1091 grpcsharp_auth_context_release(grpc_auth_context* ctx) {
1092 grpc_auth_context_release(ctx);
1097 typedef void(GPR_CALLTYPE* grpcsharp_log_func)(const char* file, int32_t line,
1099 const char* severity_string,
1101 static grpcsharp_log_func log_func = NULL;
1103 /* Redirects gpr_log to log_func callback */
1104 static void grpcsharp_log_handler(gpr_log_func_args* args) {
1105 log_func(args->file, args->line, gpr_thd_currentid(),
1106 gpr_log_severity_string(args->severity), args->message);
1109 GPR_EXPORT void GPR_CALLTYPE grpcsharp_redirect_log(grpcsharp_log_func func) {
1112 gpr_set_log_function(grpcsharp_log_handler);
1115 typedef void(GPR_CALLTYPE* test_callback_funcptr)(int32_t success);
1118 GPR_EXPORT const char* GPR_CALLTYPE grpcsharp_version_string() {
1119 return grpc_version_string();
1123 GPR_EXPORT void GPR_CALLTYPE
1124 grpcsharp_test_callback(test_callback_funcptr callback) {
1129 GPR_EXPORT void* GPR_CALLTYPE grpcsharp_test_nop(void* ptr) { return ptr; }
1132 GPR_EXPORT int32_t GPR_CALLTYPE grpcsharp_sizeof_grpc_event(void) {
1133 return sizeof(grpc_event);
1136 /* Override a method for testing */
1137 GPR_EXPORT void GPR_CALLTYPE
1138 grpcsharp_test_override_method(const char* method_name, const char* variant) {
1139 if (strcmp("grpcsharp_call_start_batch", method_name) == 0) {
1140 if (strcmp("nop", variant) == 0) {
1141 g_call_start_batch_func = grpcsharp_call_start_batch_nop;