void grpc_do_security_handshake( grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker, grpc_security_connector *connector, bool is_client_side, grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer, gpr_timespec deadline, grpc_security_handshake_done_cb cb, void *user_data) { grpc_security_connector_handshake_list *handshake_node; grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake)); memset(h, 0, sizeof(grpc_security_handshake)); h->handshaker = handshaker; h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake"); h->is_client_side = is_client_side; h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE; h->handshake_buffer = gpr_malloc(h->handshake_buffer_size); h->wrapped_endpoint = nonsecure_endpoint; h->user_data = user_data; h->cb = cb; gpr_ref_init(&h->refs, 2); /* timer and handshake proper each get a ref */ grpc_closure_init(&h->on_handshake_data_sent_to_peer, on_handshake_data_sent_to_peer, h); grpc_closure_init(&h->on_handshake_data_received_from_peer, on_handshake_data_received_from_peer, h); gpr_slice_buffer_init(&h->left_overs); gpr_slice_buffer_init(&h->outgoing); gpr_slice_buffer_init(&h->incoming); if (read_buffer != NULL) { gpr_slice_buffer_move_into(read_buffer, &h->incoming); gpr_free(read_buffer); } if (!is_client_side) { grpc_server_security_connector *server_connector = (grpc_server_security_connector *)connector; handshake_node = gpr_malloc(sizeof(grpc_security_connector_handshake_list)); handshake_node->handshake = h; gpr_mu_lock(&server_connector->mu); handshake_node->next = server_connector->handshaking_handshakes; server_connector->handshaking_handshakes = handshake_node; gpr_mu_unlock(&server_connector->mu); } send_handshake_bytes_to_peer(exec_ctx, h); grpc_timer_init(exec_ctx, &h->timer, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), on_timeout, h, gpr_now(GPR_CLOCK_MONOTONIC)); }
void grpc_setup_secure_transport(grpc_security_connector *connector, grpc_endpoint *nonsecure_endpoint, grpc_secure_transport_setup_done_cb cb, void *user_data) { grpc_security_status result = GRPC_SECURITY_OK; grpc_secure_transport_setup *s = gpr_malloc(sizeof(grpc_secure_transport_setup)); memset(s, 0, sizeof(grpc_secure_transport_setup)); result = grpc_security_connector_create_handshaker(connector, &s->handshaker); if (result != GRPC_SECURITY_OK) { secure_transport_setup_done(s, 0); return; } s->connector = grpc_security_connector_ref(connector); s->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE; s->handshake_buffer = gpr_malloc(s->handshake_buffer_size); s->endpoint = nonsecure_endpoint; s->user_data = user_data; s->cb = cb; gpr_slice_buffer_init(&s->left_overs); send_handshake_bytes_to_peer(s); }
static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, void *handshake, grpc_error *error) { grpc_security_handshake *h = handshake; size_t consumed_slice_size = 0; tsi_result result = TSI_OK; size_t i; size_t num_left_overs; int has_left_overs_in_current_slice = 0; if (error != GRPC_ERROR_NONE) { security_handshake_done( exec_ctx, h, GRPC_ERROR_CREATE_REFERENCING("Handshake read failed", &error, 1)); return; } for (i = 0; i < h->incoming.count; i++) { consumed_slice_size = GPR_SLICE_LENGTH(h->incoming.slices[i]); result = tsi_handshaker_process_bytes_from_peer( h->handshaker, GPR_SLICE_START_PTR(h->incoming.slices[i]), &consumed_slice_size); if (!tsi_handshaker_is_in_progress(h->handshaker)) break; } if (tsi_handshaker_is_in_progress(h->handshaker)) { /* We may need more data. */ if (result == TSI_INCOMPLETE_DATA) { grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming, &h->on_handshake_data_received_from_peer); return; } else { send_handshake_bytes_to_peer(exec_ctx, h); return; } } if (result != TSI_OK) { security_handshake_done(exec_ctx, h, grpc_set_tsi_error_result( GRPC_ERROR_CREATE("Handshake failed"), result)); return; } /* Handshake is done and successful this point. */ has_left_overs_in_current_slice = (consumed_slice_size < GPR_SLICE_LENGTH(h->incoming.slices[i])); num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) + h->incoming.count - i - 1; if (num_left_overs == 0) { check_peer(exec_ctx, h); return; } /* Put the leftovers in our buffer (ownership transfered). */ if (has_left_overs_in_current_slice) { gpr_slice_buffer_add( &h->left_overs, gpr_slice_split_tail(&h->incoming.slices[i], consumed_slice_size)); gpr_slice_unref( h->incoming.slices[i]); /* split_tail above increments refcount. */ } gpr_slice_buffer_addn( &h->left_overs, &h->incoming.slices[i + 1], num_left_overs - (size_t)has_left_overs_in_current_slice); check_peer(exec_ctx, h); }
static void on_handshake_data_received_from_peer( void *setup, gpr_slice *slices, size_t nslices, grpc_endpoint_cb_status error) { grpc_secure_transport_setup *s = setup; size_t consumed_slice_size = 0; tsi_result result = TSI_OK; size_t i; size_t num_left_overs; int has_left_overs_in_current_slice = 0; if (error != GRPC_ENDPOINT_CB_OK) { gpr_log(GPR_ERROR, "Read failed."); cleanup_slices(slices, nslices); secure_transport_setup_done(s, 0); return; } for (i = 0; i < nslices; i++) { consumed_slice_size = GPR_SLICE_LENGTH(slices[i]); result = tsi_handshaker_process_bytes_from_peer( s->handshaker, GPR_SLICE_START_PTR(slices[i]), &consumed_slice_size); if (!tsi_handshaker_is_in_progress(s->handshaker)) break; } if (tsi_handshaker_is_in_progress(s->handshaker)) { /* We may need more data. */ if (result == TSI_INCOMPLETE_DATA) { /* TODO(klempner,jboeuf): This should probably use the client setup deadline */ grpc_endpoint_notify_on_read(s->endpoint, on_handshake_data_received_from_peer, setup); cleanup_slices(slices, nslices); return; } else { send_handshake_bytes_to_peer(s); cleanup_slices(slices, nslices); return; } } if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshake failed with error %s", tsi_result_to_string(result)); cleanup_slices(slices, nslices); secure_transport_setup_done(s, 0); return; } /* Handshake is done and successful this point. */ has_left_overs_in_current_slice = (consumed_slice_size < GPR_SLICE_LENGTH(slices[i])); num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) + nslices - i - 1; if (num_left_overs == 0) { cleanup_slices(slices, nslices); check_peer(s); return; } cleanup_slices(slices, nslices - num_left_overs); /* Put the leftovers in our buffer (ownership transfered). */ if (has_left_overs_in_current_slice) { gpr_slice_buffer_add(&s->left_overs, gpr_slice_split_tail(&slices[i], consumed_slice_size)); gpr_slice_unref(slices[i]); /* split_tail above increments refcount. */ } gpr_slice_buffer_addn(&s->left_overs, &slices[i + 1], num_left_overs - has_left_overs_in_current_slice); check_peer(s); }