// Start transport stream op. static void start_transport_stream_op_batch( grpc_exec_ctx* exec_ctx, grpc_call_element* elem, grpc_transport_stream_op_batch* op) { call_data* calld = (call_data*)elem->call_data; // Check max send message size. if (op->send_message && calld->limits.max_send_size >= 0 && op->payload->send_message.send_message->length > (size_t)calld->limits.max_send_size) { char* message_string; gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)", op->payload->send_message.send_message->length, calld->limits.max_send_size); grpc_transport_stream_op_batch_finish_with_failure( exec_ctx, op, grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(message_string), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED), calld->call_combiner); gpr_free(message_string); return; } // Inject callback for receiving a message. if (op->recv_message) { calld->next_recv_message_ready = op->payload->recv_message.recv_message_ready; calld->recv_message = op->payload->recv_message.recv_message; op->payload->recv_message.recv_message_ready = &calld->recv_message_ready; } // Chain to the next filter. grpc_call_next_op(exec_ctx, elem, op); }
static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *input_error) { grpc_transport_stream_op_batch *batch = (grpc_transport_stream_op_batch *)arg; grpc_call_element *elem = batch->handler_private.extra_arg; call_data *calld = elem->call_data; reset_auth_metadata_context(&calld->auth_md_context); grpc_error *error = GRPC_ERROR_REF(input_error); if (error == GRPC_ERROR_NONE) { GPR_ASSERT(calld->md_array.size <= MAX_CREDENTIALS_METADATA_COUNT); GPR_ASSERT(batch->send_initial_metadata); grpc_metadata_batch *mdb = batch->payload->send_initial_metadata.send_initial_metadata; for (size_t i = 0; i < calld->md_array.size; ++i) { add_error(&error, grpc_metadata_batch_add_tail( exec_ctx, mdb, &calld->md_links[i], GRPC_MDELEM_REF(calld->md_array.md[i]))); } } if (error == GRPC_ERROR_NONE) { grpc_call_next_op(exec_ctx, elem, batch); } else { error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAUTHENTICATED); grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, batch, error); } }
static void on_credentials_metadata(void *user_data, grpc_credentials_md *md_elems, size_t num_md, grpc_credentials_status status) { grpc_call_element *elem = (grpc_call_element *)user_data; call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_transport_stream_op *op = &calld->op; grpc_metadata_batch *mdb; size_t i; if (status != GRPC_CREDENTIALS_OK) { bubble_up_error(elem, GRPC_STATUS_UNAUTHENTICATED, "Credentials failed to get metadata."); return; } GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT); GPR_ASSERT(op->send_ops && op->send_ops->nops > calld->op_md_idx && op->send_ops->ops[calld->op_md_idx].type == GRPC_OP_METADATA); mdb = &op->send_ops->ops[calld->op_md_idx].data.metadata; for (i = 0; i < num_md; i++) { grpc_metadata_batch_add_tail( mdb, &calld->md_links[i], grpc_mdelem_from_slices(chand->md_ctx, gpr_slice_ref(md_elems[i].key), gpr_slice_ref(md_elems[i].value))); } grpc_call_next_op(elem, op); }
static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, grpc_call_op *op) { GRPC_CALL_LOG_OP(GPR_INFO, elem, op); switch (op->type) { case GRPC_RECV_METADATA: grpc_call_recv_metadata(elem, &op->data.metadata); break; case GRPC_RECV_MESSAGE: grpc_call_recv_message(elem, op->data.message); op->done_cb(op->user_data, GRPC_OP_OK); break; case GRPC_RECV_HALF_CLOSE: grpc_call_read_closed(elem); break; case GRPC_RECV_FINISH: grpc_call_stream_closed(elem); break; case GRPC_RECV_SYNTHETIC_STATUS: grpc_call_recv_synthetic_status(elem, op->data.synthetic_status.status, op->data.synthetic_status.message); break; default: GPR_ASSERT(op->dir == GRPC_CALL_DOWN); grpc_call_next_op(elem, op); } }
static void server_start_transport_stream_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op *op) { GRPC_CALL_LOG_OP(GPR_INFO, elem, op); server_mutate_op(elem, op); grpc_call_next_op(exec_ctx, elem, op); }
static void lr_start_transport_stream_op_batch( grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op_batch *op) { GPR_TIMER_BEGIN("lr_start_transport_stream_op_batch", 0); call_data *calld = (call_data *)elem->call_data; if (op->recv_initial_metadata) { /* substitute our callback for the higher callback */ calld->recv_initial_metadata = op->payload->recv_initial_metadata.recv_initial_metadata; calld->ops_recv_initial_metadata_ready = op->payload->recv_initial_metadata.recv_initial_metadata_ready; op->payload->recv_initial_metadata.recv_initial_metadata_ready = &calld->on_initial_md_ready; } else if (op->send_trailing_metadata) { GRPC_LOG_IF_ERROR( "grpc_metadata_batch_filter", grpc_metadata_batch_filter( exec_ctx, op->payload->send_trailing_metadata.send_trailing_metadata, lr_trailing_md_filter, elem, "LR trailing metadata filtering error")); } grpc_call_next_op(exec_ctx, elem, op); GPR_TIMER_END("lr_start_transport_stream_op_batch", 0); }
static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data, grpc_credentials_md *md_elems, size_t num_md, grpc_credentials_status status) { grpc_call_element *elem = (grpc_call_element *)user_data; call_data *calld = elem->call_data; grpc_transport_stream_op *op = &calld->op; grpc_metadata_batch *mdb; size_t i; reset_auth_metadata_context(&calld->auth_md_context); if (status != GRPC_CREDENTIALS_OK) { bubble_up_error(exec_ctx, elem, GRPC_STATUS_UNAUTHENTICATED, "Credentials failed to get metadata."); return; } GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT); GPR_ASSERT(op->send_initial_metadata != NULL); mdb = op->send_initial_metadata; for (i = 0; i < num_md; i++) { grpc_metadata_batch_add_tail( mdb, &calld->md_links[i], grpc_mdelem_from_slices(gpr_slice_ref(md_elems[i].key), gpr_slice_ref(md_elems[i].value))); } grpc_call_next_op(exec_ctx, elem, op); }
static void server_start_transport_op(grpc_call_element* elem, grpc_transport_stream_op* op) { call_data* calld = elem->call_data; GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); server_mutate_op(elem, op); grpc_call_next_op(elem, op); }
static void bubble_up_error(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_status_code status, const char *error_msg) { call_data *calld = elem->call_data; gpr_log(GPR_ERROR, "Client side authentication failure: %s", error_msg); grpc_transport_stream_op_add_cancellation(&calld->op, status); grpc_call_next_op(exec_ctx, elem, &calld->op); }
void grpc_metadata_buffer_flush(grpc_metadata_buffer *buffer, grpc_call_element *elem) { grpc_metadata_buffer_impl *impl = *buffer; grpc_call_op op; qelem *qe; size_t i; if (!impl) { /* nothing to send */ return; } /* construct call_op's, and push them down the stack */ op.type = GRPC_SEND_METADATA; op.dir = GRPC_CALL_DOWN; for (i = 0; i < impl->elems; i++) { qe = &ELEMS(impl)[i]; op.done_cb = qe->cb; op.user_data = qe->user_data; op.flags = qe->flags; op.data.metadata = qe->md; grpc_call_next_op(elem, &op); } /* free data structures and reset to NULL: we can only flush once */ gpr_free(impl); *buffer = NULL; }
static void bubble_up_error(grpc_call_element *elem, const char *error_msg) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_transport_stream_op_add_cancellation( &calld->op, GRPC_STATUS_UNAUTHENTICATED, grpc_mdstr_from_string(chand->md_ctx, error_msg, 0)); grpc_call_next_op(elem, &calld->op); }
/* Called either: - in response to an API call (or similar) from above, to send something - a network event (or similar) from below, to receive something op contains type and call direction information, in addition to the data that is being sent or received. */ static void noop_start_transport_stream_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op *op) { noop_mutate_op(elem, op); /* pass control down the stack */ grpc_call_next_op(exec_ctx, elem, op); }
void grpc_call_element_send_finish(grpc_call_element *cur_elem) { grpc_call_op finish_op; finish_op.type = GRPC_SEND_FINISH; finish_op.dir = GRPC_CALL_DOWN; finish_op.done_cb = do_nothing; finish_op.user_data = NULL; finish_op.flags = 0; grpc_call_next_op(cur_elem, &finish_op); }
void grpc_call_element_send_cancel(grpc_call_element *cur_elem) { grpc_call_op cancel_op; cancel_op.type = GRPC_CANCEL_OP; cancel_op.dir = GRPC_CALL_DOWN; cancel_op.done_cb = do_nothing; cancel_op.user_data = NULL; cancel_op.flags = 0; grpc_call_next_op(cur_elem, &cancel_op); }
static void send_security_metadata(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op_batch *batch) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_client_security_context *ctx = (grpc_client_security_context *)batch->payload ->context[GRPC_CONTEXT_SECURITY] .value; grpc_call_credentials *channel_call_creds = chand->security_connector->request_metadata_creds; int call_creds_has_md = (ctx != NULL) && (ctx->creds != NULL); if (channel_call_creds == NULL && !call_creds_has_md) { /* Skip sending metadata altogether. */ grpc_call_next_op(exec_ctx, elem, batch); return; } if (channel_call_creds != NULL && call_creds_has_md) { calld->creds = grpc_composite_call_credentials_create(channel_call_creds, ctx->creds, NULL); if (calld->creds == NULL) { grpc_transport_stream_op_batch_finish_with_failure( exec_ctx, batch, grpc_error_set_int( GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Incompatible credentials set on channel and call."), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAUTHENTICATED)); return; } } else { calld->creds = grpc_call_credentials_ref( call_creds_has_md ? ctx->creds : channel_call_creds); } build_auth_metadata_context(&chand->security_connector->base, chand->auth_context, calld); grpc_error *cancel_error = set_cancel_func(elem, cancel_get_request_metadata); if (cancel_error != GRPC_ERROR_NONE) { grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, batch, cancel_error); return; } GPR_ASSERT(calld->pollent != NULL); GRPC_CLOSURE_INIT(&calld->closure, on_credentials_metadata, batch, grpc_schedule_on_exec_ctx); grpc_error *error = GRPC_ERROR_NONE; if (grpc_call_credentials_get_request_metadata( exec_ctx, calld->creds, calld->pollent, calld->auth_md_context, &calld->md_array, &calld->closure, &error)) { // Synchronous return; invoke on_credentials_metadata() directly. on_credentials_metadata(exec_ctx, batch, error); GRPC_ERROR_UNREF(error); } }
static void hc_start_transport_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op *op) { GPR_TIMER_BEGIN("hc_start_transport_op", 0); GRPC_CALL_LOG_OP(GPR_INFO, elem, op); hc_mutate_op(elem, op); GPR_TIMER_END("hc_start_transport_op", 0); grpc_call_next_op(exec_ctx, elem, op); }
/* Called either: - in response to an API call (or similar) from above, to send something - a network event (or similar) from below, to receive something op contains type and call direction information, in addition to the data that is being sent or received. */ static void compress_start_transport_stream_op(grpc_call_element *elem, grpc_transport_stream_op *op) { if (op->send_ops && op->send_ops->nops > 0) { process_send_ops(elem, op->send_ops); } /* pass control down the stack */ grpc_call_next_op(elem, op); }
static void send_up_cancelled_ops(grpc_call_element *elem) { grpc_call_op finish_op; channel_data *chand = elem->channel_data; /* send up a synthesized status */ finish_op.type = GRPC_RECV_METADATA; finish_op.dir = GRPC_CALL_UP; finish_op.flags = 0; finish_op.data.metadata = grpc_mdelem_ref(chand->cancel_status); finish_op.done_cb = do_nothing; finish_op.user_data = NULL; grpc_call_next_op(elem, &finish_op); /* send up a finish */ finish_op.type = GRPC_RECV_FINISH; finish_op.dir = GRPC_CALL_UP; finish_op.flags = 0; finish_op.done_cb = do_nothing; finish_op.user_data = NULL; grpc_call_next_op(elem, &finish_op); }
void grpc_call_element_send_metadata(grpc_call_element *cur_elem, grpc_mdelem *mdelem) { grpc_call_op metadata_op; metadata_op.type = GRPC_SEND_METADATA; metadata_op.dir = GRPC_CALL_DOWN; metadata_op.done_cb = do_nothing; metadata_op.user_data = NULL; metadata_op.flags = 0; metadata_op.data.metadata = mdelem; grpc_call_next_op(cur_elem, &metadata_op); }
static void server_start_transport_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op *op) { /* TODO(ctiller): this code fails. I don't know why. I expect it's incomplete, and someone should look at it soon. call_data *calld = elem->call_data; GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); */ server_mutate_op(elem, op); grpc_call_next_op(exec_ctx, elem, op); }
void grpc_call_element_recv_status(grpc_call_element *cur_elem, grpc_status_code status, const char *message) { grpc_call_op op; op.type = GRPC_RECV_SYNTHETIC_STATUS; op.dir = GRPC_CALL_UP; op.done_cb = do_nothing; op.user_data = NULL; op.data.synthetic_status.status = status; op.data.synthetic_status.message = message; grpc_call_next_op(cur_elem, &op); }
static void start_transport_stream_op_batch( grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op_batch *op) { call_data *calld = elem->call_data; if (op->recv_initial_metadata) { calld->recv_im_ready = op->payload->recv_initial_metadata.recv_initial_metadata_ready; op->payload->recv_initial_metadata.recv_initial_metadata_ready = grpc_closure_create(recv_im_ready, elem, grpc_schedule_on_exec_ctx); } grpc_call_next_op(exec_ctx, elem, op); }
/* Called either: - in response to an API call (or similar) from above, to send something - a network event (or similar) from below, to receive something op contains type and call direction information, in addition to the data that is being sent or received. */ static void auth_start_transport_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_linked_mdelem *l; grpc_client_security_context *sec_ctx = NULL; if (calld->security_context_set == 0 && op->cancel_with_status == GRPC_STATUS_OK) { calld->security_context_set = 1; GPR_ASSERT(op->context); if (op->context[GRPC_CONTEXT_SECURITY].value == NULL) { op->context[GRPC_CONTEXT_SECURITY].value = grpc_client_security_context_create(); op->context[GRPC_CONTEXT_SECURITY].destroy = grpc_client_security_context_destroy; } sec_ctx = op->context[GRPC_CONTEXT_SECURITY].value; GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter"); sec_ctx->auth_context = GRPC_AUTH_CONTEXT_REF(chand->auth_context, "client_auth_filter"); } if (op->send_initial_metadata != NULL) { for (l = op->send_initial_metadata->list.head; l != NULL; l = l->next) { grpc_mdelem *md = l->md; /* Pointer comparison is OK for md_elems created from the same context. */ if (md->key == GRPC_MDSTR_AUTHORITY) { if (calld->host != NULL) GRPC_MDSTR_UNREF(calld->host); calld->host = GRPC_MDSTR_REF(md->value); } else if (md->key == GRPC_MDSTR_PATH) { if (calld->method != NULL) GRPC_MDSTR_UNREF(calld->method); calld->method = GRPC_MDSTR_REF(md->value); } } if (calld->host != NULL) { const char *call_host = grpc_mdstr_as_c_string(calld->host); calld->op = *op; /* Copy op (originates from the caller's stack). */ grpc_channel_security_connector_check_call_host( exec_ctx, chand->security_connector, call_host, chand->auth_context, on_host_checked, elem); return; /* early exit */ } } /* pass control down the stack */ grpc_call_next_op(exec_ctx, elem, op); }
/* Called either: - in response to an API call (or similar) from above, to send something - a network event (or similar) from below, to receive something op contains type and call direction information, in addition to the data that is being sent or received. */ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, grpc_call_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; ignore_unused(calld); ignore_unused(channeld); switch (op->type) { default: /* pass control up or down the stack depending on op->dir */ grpc_call_next_op(elem, op); break; } }
static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) { grpc_call_element *elem = elemp; call_data *calld = elem->call_data; calld->send_message_blocked = false; grpc_slice_buffer_add(&calld->slices, calld->incoming_slice); if (calld->send_length == calld->slices.length) { /* Pass down the original send_message op that was blocked.*/ grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices, calld->send_flags); calld->send_op.send_message = &calld->replacement_stream.base; calld->post_send = calld->send_op.on_complete; calld->send_op.on_complete = &calld->send_done; grpc_call_next_op(exec_ctx, elem, &calld->send_op); } else { continue_send_message(exec_ctx, elem); } }
static void finish_send_message(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { call_data *calld = elem->call_data; int did_compress; grpc_slice_buffer tmp; grpc_slice_buffer_init(&tmp); did_compress = grpc_msg_compress(exec_ctx, calld->compression_algorithm, &calld->slices, &tmp); if (did_compress) { if (GRPC_TRACER_ON(grpc_compression_trace)) { char *algo_name; const size_t before_size = calld->slices.length; const size_t after_size = tmp.length; const float savings_ratio = 1.0f - (float)after_size / (float)before_size; GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm, &algo_name)); gpr_log(GPR_DEBUG, "Compressed[%s] %" PRIuPTR " bytes vs. %" PRIuPTR " bytes (%.2f%% savings)", algo_name, before_size, after_size, 100 * savings_ratio); } grpc_slice_buffer_swap(&calld->slices, &tmp); calld->send_flags |= GRPC_WRITE_INTERNAL_COMPRESS; } else { if (GRPC_TRACER_ON(grpc_compression_trace)) { char *algo_name; GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm, &algo_name)); gpr_log(GPR_DEBUG, "Algorithm '%s' enabled but decided not to compress. Input size: " "%" PRIuPTR, algo_name, calld->slices.length); } } grpc_slice_buffer_destroy_internal(exec_ctx, &tmp); grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices, calld->send_flags); calld->send_op->payload->send_message.send_message = &calld->replacement_stream.base; calld->post_send = calld->send_op->on_complete; calld->send_op->on_complete = &calld->send_done; grpc_call_next_op(exec_ctx, elem, calld->send_op); }
/* called from application code */ static void on_md_processing_done( void *user_data, const grpc_metadata *consumed_md, size_t num_consumed_md, const grpc_metadata *response_md, size_t num_response_md, grpc_status_code status, const char *error_details) { grpc_call_element *elem = user_data; call_data *calld = elem->call_data; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; /* TODO(jboeuf): Implement support for response_md. */ if (response_md != NULL && num_response_md > 0) { gpr_log(GPR_INFO, "response_md in auth metadata processing not supported for now. " "Ignoring..."); } if (status == GRPC_STATUS_OK) { calld->consumed_md = consumed_md; calld->num_consumed_md = num_consumed_md; grpc_metadata_batch_filter(calld->recv_initial_metadata, remove_consumed_md, elem); grpc_metadata_array_destroy(&calld->md); calld->on_done_recv->cb(&exec_ctx, calld->on_done_recv->cb_arg, 1); } else { gpr_slice message; grpc_transport_stream_op close_op; memset(&close_op, 0, sizeof(close_op)); grpc_metadata_array_destroy(&calld->md); error_details = error_details != NULL ? error_details : "Authentication metadata processing failed."; message = gpr_slice_from_copied_string(error_details); calld->transport_op.send_initial_metadata = NULL; if (calld->transport_op.send_message != NULL) { grpc_byte_stream_destroy(calld->transport_op.send_message); calld->transport_op.send_message = NULL; } calld->transport_op.send_trailing_metadata = NULL; grpc_transport_stream_op_add_close(&close_op, status, &message); grpc_call_next_op(&exec_ctx, elem, &close_op); calld->on_done_recv->cb(&exec_ctx, calld->on_done_recv->cb_arg, 0); } grpc_exec_ctx_finish(&exec_ctx); }
static void call_op(grpc_call_element *elem, grpc_call_element *from_elemn, grpc_call_op *op) { channel_data *chand = elem->channel_data; call_data *calld = elem->call_data; grpc_mdelem *md; GRPC_CALL_LOG_OP(GPR_INFO, elem, op); switch (op->type) { case GRPC_RECV_METADATA: md = op->data.metadata; if (md->key == chand->path_key) { calld->path = grpc_mdstr_ref(md->value); grpc_mdelem_unref(md); } else if (md->key == chand->authority_key) { calld->host = grpc_mdstr_ref(md->value); grpc_mdelem_unref(md); } else { grpc_call_recv_metadata(elem, md); } break; case GRPC_RECV_END_OF_INITIAL_METADATA: start_new_rpc(elem); grpc_call_initial_metadata_complete(elem); break; case GRPC_RECV_MESSAGE: grpc_call_recv_message(elem, op->data.message); op->done_cb(op->user_data, GRPC_OP_OK); break; case GRPC_RECV_HALF_CLOSE: read_closed(elem); break; case GRPC_RECV_FINISH: stream_closed(elem); break; case GRPC_RECV_DEADLINE: grpc_call_set_deadline(elem, op->data.deadline); ((call_data *)elem->call_data)->deadline = op->data.deadline; break; default: GPR_ASSERT(op->dir == GRPC_CALL_DOWN); grpc_call_next_op(elem, op); break; } }
static void lr_start_transport_stream_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op *op) { GPR_TIMER_BEGIN("lr_start_transport_stream_op", 0); call_data *calld = elem->call_data; if (op->recv_initial_metadata) { calld->recv_initial_metadata = op->recv_initial_metadata; /* substitute our callback for the higher callback */ calld->ops_recv_initial_metadata_ready = op->recv_initial_metadata_ready; op->recv_initial_metadata_ready = &calld->on_initial_md_ready; } else if (op->send_trailing_metadata) { grpc_metadata_batch_filter(op->send_trailing_metadata, lr_trailing_md_filter, elem); } grpc_call_next_op(exec_ctx, elem, op); GPR_TIMER_END("lr_start_transport_stream_op", 0); }
static void send_security_metadata(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_transport_stream_op *op) { call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_client_security_context *ctx = (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value; grpc_call_credentials *channel_call_creds = chand->security_connector->request_metadata_creds; int call_creds_has_md = (ctx != NULL) && (ctx->creds != NULL); if (channel_call_creds == NULL && !call_creds_has_md) { /* Skip sending metadata altogether. */ grpc_call_next_op(exec_ctx, elem, op); return; } if (channel_call_creds != NULL && call_creds_has_md) { calld->creds = grpc_composite_call_credentials_create(channel_call_creds, ctx->creds, NULL); if (calld->creds == NULL) { grpc_transport_stream_op_finish_with_failure( exec_ctx, op, grpc_error_set_int( GRPC_ERROR_CREATE( "Incompatible credentials set on channel and call."), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAUTHENTICATED)); return; } } else { calld->creds = grpc_call_credentials_ref( call_creds_has_md ? ctx->creds : channel_call_creds); } build_auth_metadata_context(&chand->security_connector->base, chand->auth_context, calld); calld->op = *op; /* Copy op (originates from the caller's stack). */ GPR_ASSERT(calld->pollent != NULL); grpc_call_credentials_get_request_metadata( exec_ctx, calld->creds, calld->pollent, calld->auth_md_context, on_credentials_metadata, elem); }