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