|
|
|
@ -149,6 +149,9 @@ struct write_state { |
|
|
|
|
struct op_state { |
|
|
|
|
bool state_op_done[OP_NUM_OPS]; |
|
|
|
|
bool state_callback_received[OP_NUM_OPS]; |
|
|
|
|
bool fail_state; |
|
|
|
|
bool flush_read; |
|
|
|
|
grpc_error *cancel_error; |
|
|
|
|
/* data structure for storing data coming from server */ |
|
|
|
|
struct read_state rs; |
|
|
|
|
/* data structure for storing data going to the server */ |
|
|
|
@ -248,6 +251,12 @@ static void free_read_buffer(stream_obj *s) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_error *make_error_with_desc(int error_code, const char *desc) { |
|
|
|
|
grpc_error *error = GRPC_ERROR_CREATE(desc); |
|
|
|
|
error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, error_code); |
|
|
|
|
return error; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Add a new stream op to op storage. |
|
|
|
|
*/ |
|
|
|
@ -433,6 +442,18 @@ static void on_response_headers_received( |
|
|
|
|
grpc_mdstr_from_string(headers->headers[i].value))); |
|
|
|
|
} |
|
|
|
|
s->state.state_callback_received[OP_RECV_INITIAL_METADATA] = true; |
|
|
|
|
if (!(s->state.state_op_done[OP_CANCEL_ERROR] || |
|
|
|
|
s->state.state_callback_received[OP_FAILED])) { |
|
|
|
|
/* Do an extra read to trigger on_succeeded() callback in case connection
|
|
|
|
|
is closed */ |
|
|
|
|
GPR_ASSERT(s->state.rs.length_field_received == false); |
|
|
|
|
s->state.rs.read_buffer = s->state.rs.grpc_header_bytes; |
|
|
|
|
s->state.rs.received_bytes = 0; |
|
|
|
|
s->state.rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES; |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs); |
|
|
|
|
cronet_bidirectional_stream_read(s->cbs, s->state.rs.read_buffer, |
|
|
|
|
s->state.rs.remaining_bytes); |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(&s->mu); |
|
|
|
|
execute_from_storage(s); |
|
|
|
|
} |
|
|
|
@ -464,7 +485,11 @@ static void on_read_completed(cronet_bidirectional_stream *stream, char *data, |
|
|
|
|
count); |
|
|
|
|
gpr_mu_lock(&s->mu); |
|
|
|
|
s->state.state_callback_received[OP_RECV_MESSAGE] = true; |
|
|
|
|
if (count > 0) { |
|
|
|
|
if (count > 0 && s->state.flush_read) { |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs); |
|
|
|
|
cronet_bidirectional_stream_read(s->cbs, s->state.rs.read_buffer, 4096); |
|
|
|
|
gpr_mu_unlock(&s->mu); |
|
|
|
|
} else if (count > 0) { |
|
|
|
|
s->state.rs.received_bytes += count; |
|
|
|
|
s->state.rs.remaining_bytes -= count; |
|
|
|
|
if (s->state.rs.remaining_bytes > 0) { |
|
|
|
@ -479,6 +504,10 @@ static void on_read_completed(cronet_bidirectional_stream *stream, char *data, |
|
|
|
|
execute_from_storage(s); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if (s->state.flush_read) { |
|
|
|
|
gpr_free(s->state.rs.read_buffer); |
|
|
|
|
s->state.rs.read_buffer = NULL; |
|
|
|
|
} |
|
|
|
|
s->state.rs.read_stream_closed = true; |
|
|
|
|
gpr_mu_unlock(&s->mu); |
|
|
|
|
execute_from_storage(s); |
|
|
|
@ -508,10 +537,27 @@ static void on_response_trailers_received( |
|
|
|
|
grpc_mdstr_from_string(trailers->headers[i].key), |
|
|
|
|
grpc_mdstr_from_string(trailers->headers[i].value))); |
|
|
|
|
s->state.rs.trailing_metadata_valid = true; |
|
|
|
|
if (0 == strcmp(trailers->headers[i].key, "grpc-status") && |
|
|
|
|
0 != strcmp(trailers->headers[i].value, "0")) { |
|
|
|
|
s->state.fail_state = true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
s->state.state_callback_received[OP_RECV_TRAILING_METADATA] = true; |
|
|
|
|
gpr_mu_unlock(&s->mu); |
|
|
|
|
execute_from_storage(s); |
|
|
|
|
/* Send a EOS when server terminates the stream (testServerFinishesRequest) to
|
|
|
|
|
* trigger on_succeeded */ |
|
|
|
|
if (!s->state.state_op_done[OP_SEND_TRAILING_METADATA] && |
|
|
|
|
!(s->state.state_op_done[OP_CANCEL_ERROR] || |
|
|
|
|
s->state.state_callback_received[OP_FAILED])) { |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_write (%p, 0)", s->cbs); |
|
|
|
|
s->state.state_callback_received[OP_SEND_MESSAGE] = false; |
|
|
|
|
cronet_bidirectional_stream_write(s->cbs, "", 0, true); |
|
|
|
|
s->state.state_op_done[OP_SEND_TRAILING_METADATA] = true; |
|
|
|
|
|
|
|
|
|
gpr_mu_unlock(&s->mu); |
|
|
|
|
} else { |
|
|
|
|
gpr_mu_unlock(&s->mu); |
|
|
|
|
execute_from_storage(s); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -632,9 +678,9 @@ static bool op_can_be_run(grpc_transport_stream_op *curr_op, |
|
|
|
|
/* When call is canceled, every op can be run, except under following
|
|
|
|
|
conditions |
|
|
|
|
*/ |
|
|
|
|
bool is_canceled_of_failed = stream_state->state_op_done[OP_CANCEL_ERROR] || |
|
|
|
|
bool is_canceled_or_failed = stream_state->state_op_done[OP_CANCEL_ERROR] || |
|
|
|
|
stream_state->state_callback_received[OP_FAILED]; |
|
|
|
|
if (is_canceled_of_failed) { |
|
|
|
|
if (is_canceled_or_failed) { |
|
|
|
|
if (op_id == OP_SEND_INITIAL_METADATA) result = false; |
|
|
|
|
if (op_id == OP_SEND_MESSAGE) result = false; |
|
|
|
|
if (op_id == OP_SEND_TRAILING_METADATA) result = false; |
|
|
|
@ -778,16 +824,10 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx, |
|
|
|
|
op_can_be_run(stream_op, stream_state, &oas->state, |
|
|
|
|
OP_SEND_INITIAL_METADATA)) { |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "running: %p OP_SEND_INITIAL_METADATA", oas); |
|
|
|
|
/* This OP is the beginning. Reset various states */ |
|
|
|
|
memset(&s->header_array, 0, sizeof(s->header_array)); |
|
|
|
|
memset(&stream_state->rs, 0, sizeof(stream_state->rs)); |
|
|
|
|
memset(&stream_state->ws, 0, sizeof(stream_state->ws)); |
|
|
|
|
memset(stream_state->state_op_done, 0, sizeof(stream_state->state_op_done)); |
|
|
|
|
memset(stream_state->state_callback_received, 0, |
|
|
|
|
sizeof(stream_state->state_callback_received)); |
|
|
|
|
/* Start new cronet stream. It is destroyed in on_succeeded, on_canceled,
|
|
|
|
|
* on_failed */ |
|
|
|
|
GPR_ASSERT(s->cbs == NULL); |
|
|
|
|
GPR_ASSERT(!stream_state->state_op_done[OP_SEND_INITIAL_METADATA]); |
|
|
|
|
s->cbs = cronet_bidirectional_stream_create(s->curr_ct.engine, s->curr_gs, |
|
|
|
|
&cronet_callbacks); |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "%p = cronet_bidirectional_stream_create()", s->cbs); |
|
|
|
@ -808,10 +848,13 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx, |
|
|
|
|
op_can_be_run(stream_op, stream_state, &oas->state, |
|
|
|
|
OP_RECV_INITIAL_METADATA)) { |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "running: %p OP_RECV_INITIAL_METADATA", oas); |
|
|
|
|
if (stream_state->state_op_done[OP_CANCEL_ERROR] || |
|
|
|
|
stream_state->state_callback_received[OP_FAILED]) { |
|
|
|
|
if (stream_state->state_op_done[OP_CANCEL_ERROR]) { |
|
|
|
|
grpc_exec_ctx_sched(exec_ctx, stream_op->recv_initial_metadata_ready, |
|
|
|
|
GRPC_ERROR_CANCELLED, NULL); |
|
|
|
|
} else if (stream_state->state_callback_received[OP_FAILED]) { |
|
|
|
|
grpc_exec_ctx_sched( |
|
|
|
|
exec_ctx, stream_op->recv_initial_metadata_ready, |
|
|
|
|
make_error_with_desc(GRPC_STATUS_UNAVAILABLE, "Unavailable."), NULL); |
|
|
|
|
} else { |
|
|
|
|
grpc_chttp2_incoming_metadata_buffer_publish( |
|
|
|
|
&oas->s->state.rs.initial_metadata, stream_op->recv_initial_metadata); |
|
|
|
@ -865,12 +908,19 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx, |
|
|
|
|
op_can_be_run(stream_op, stream_state, &oas->state, |
|
|
|
|
OP_RECV_MESSAGE)) { |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "running: %p OP_RECV_MESSAGE", oas); |
|
|
|
|
if (stream_state->state_op_done[OP_CANCEL_ERROR] || |
|
|
|
|
stream_state->state_callback_received[OP_FAILED]) { |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "Stream is either cancelled or failed."); |
|
|
|
|
if (stream_state->state_op_done[OP_CANCEL_ERROR]) { |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "Stream is cancelled."); |
|
|
|
|
grpc_exec_ctx_sched(exec_ctx, stream_op->recv_message_ready, |
|
|
|
|
GRPC_ERROR_CANCELLED, NULL); |
|
|
|
|
stream_state->state_op_done[OP_RECV_MESSAGE] = true; |
|
|
|
|
result = ACTION_TAKEN_NO_CALLBACK; |
|
|
|
|
} else if (stream_state->state_callback_received[OP_FAILED]) { |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "Stream failed."); |
|
|
|
|
grpc_exec_ctx_sched( |
|
|
|
|
exec_ctx, stream_op->recv_message_ready, |
|
|
|
|
make_error_with_desc(GRPC_STATUS_UNAVAILABLE, "Unavailable."), NULL); |
|
|
|
|
stream_state->state_op_done[OP_RECV_MESSAGE] = true; |
|
|
|
|
result = ACTION_TAKEN_NO_CALLBACK; |
|
|
|
|
} else if (stream_state->rs.read_stream_closed == true) { |
|
|
|
|
/* No more data will be received */ |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "read stream closed"); |
|
|
|
@ -878,6 +928,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx, |
|
|
|
|
GRPC_ERROR_NONE, NULL); |
|
|
|
|
stream_state->state_op_done[OP_RECV_MESSAGE] = true; |
|
|
|
|
oas->state.state_op_done[OP_RECV_MESSAGE] = true; |
|
|
|
|
result = ACTION_TAKEN_NO_CALLBACK; |
|
|
|
|
} else if (stream_state->rs.length_field_received == false) { |
|
|
|
|
if (stream_state->rs.received_bytes == GRPC_HEADER_SIZE_IN_BYTES && |
|
|
|
|
stream_state->rs.remaining_bytes == 0) { |
|
|
|
@ -946,10 +997,15 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx, |
|
|
|
|
GRPC_ERROR_NONE, NULL); |
|
|
|
|
stream_state->state_op_done[OP_RECV_MESSAGE] = true; |
|
|
|
|
oas->state.state_op_done[OP_RECV_MESSAGE] = true; |
|
|
|
|
/* Clear read state of the stream, so next read op (if it were to come)
|
|
|
|
|
* will work */ |
|
|
|
|
stream_state->rs.received_bytes = stream_state->rs.remaining_bytes = |
|
|
|
|
stream_state->rs.length_field_received = 0; |
|
|
|
|
/* Do an extra read to trigger on_succeeded() callback in case connection
|
|
|
|
|
is closed */ |
|
|
|
|
stream_state->rs.read_buffer = stream_state->rs.grpc_header_bytes; |
|
|
|
|
stream_state->rs.received_bytes = 0; |
|
|
|
|
stream_state->rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES; |
|
|
|
|
stream_state->rs.length_field_received = false; |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs); |
|
|
|
|
cronet_bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer, |
|
|
|
|
stream_state->rs.remaining_bytes); |
|
|
|
|
result = ACTION_TAKEN_NO_CALLBACK; |
|
|
|
|
} |
|
|
|
|
} else if (stream_op->recv_trailing_metadata && |
|
|
|
@ -986,17 +1042,25 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx, |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "W: cronet_bidirectional_stream_cancel(%p)", s->cbs); |
|
|
|
|
if (s->cbs) { |
|
|
|
|
cronet_bidirectional_stream_cancel(s->cbs); |
|
|
|
|
result = ACTION_TAKEN_WITH_CALLBACK; |
|
|
|
|
} else { |
|
|
|
|
result = ACTION_TAKEN_NO_CALLBACK; |
|
|
|
|
} |
|
|
|
|
stream_state->state_op_done[OP_CANCEL_ERROR] = true; |
|
|
|
|
result = ACTION_TAKEN_WITH_CALLBACK; |
|
|
|
|
if (!stream_state->cancel_error) { |
|
|
|
|
stream_state->cancel_error = GRPC_ERROR_REF(stream_op->cancel_error); |
|
|
|
|
} |
|
|
|
|
} else if (stream_op->on_complete && |
|
|
|
|
op_can_be_run(stream_op, stream_state, &oas->state, |
|
|
|
|
OP_ON_COMPLETE)) { |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "running: %p OP_ON_COMPLETE", oas); |
|
|
|
|
if (stream_state->state_op_done[OP_CANCEL_ERROR] || |
|
|
|
|
stream_state->state_callback_received[OP_FAILED]) { |
|
|
|
|
if (stream_state->state_op_done[OP_CANCEL_ERROR]) { |
|
|
|
|
grpc_exec_ctx_sched(exec_ctx, stream_op->on_complete, |
|
|
|
|
GRPC_ERROR_CANCELLED, NULL); |
|
|
|
|
GRPC_ERROR_REF(stream_state->cancel_error), NULL); |
|
|
|
|
} else if (stream_state->state_callback_received[OP_FAILED]) { |
|
|
|
|
grpc_exec_ctx_sched( |
|
|
|
|
exec_ctx, stream_op->on_complete, |
|
|
|
|
make_error_with_desc(GRPC_STATUS_UNAVAILABLE, "Unavailable."), NULL); |
|
|
|
|
} else { |
|
|
|
|
/* All actions in this stream_op are complete. Call the on_complete
|
|
|
|
|
* callback |
|
|
|
@ -1017,6 +1081,15 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx, |
|
|
|
|
make a note */ |
|
|
|
|
if (stream_op->recv_message) |
|
|
|
|
stream_state->state_op_done[OP_RECV_MESSAGE_AND_ON_COMPLETE] = true; |
|
|
|
|
} else if (stream_state->fail_state && !stream_state->flush_read) { |
|
|
|
|
CRONET_LOG(GPR_DEBUG, "running: %p flush read", oas); |
|
|
|
|
if (stream_state->rs.read_buffer && |
|
|
|
|
stream_state->rs.read_buffer != stream_state->rs.grpc_header_bytes) { |
|
|
|
|
gpr_free(stream_state->rs.read_buffer); |
|
|
|
|
stream_state->rs.read_buffer = NULL; |
|
|
|
|
} |
|
|
|
|
stream_state->rs.read_buffer = gpr_malloc(4096); |
|
|
|
|
stream_state->flush_read = true; |
|
|
|
|
} else { |
|
|
|
|
result = NO_ACTION_POSSIBLE; |
|
|
|
|
} |
|
|
|
@ -1042,6 +1115,8 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, |
|
|
|
|
memset(s->state.state_op_done, 0, sizeof(s->state.state_op_done)); |
|
|
|
|
memset(s->state.state_callback_received, 0, |
|
|
|
|
sizeof(s->state.state_callback_received)); |
|
|
|
|
s->state.fail_state = s->state.flush_read = false; |
|
|
|
|
s->state.cancel_error = NULL; |
|
|
|
|
gpr_mu_init(&s->mu); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
@ -1088,7 +1163,10 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, |
|
|
|
|
grpc_stream *gs, void *and_free_memory) {} |
|
|
|
|
grpc_stream *gs, void *and_free_memory) { |
|
|
|
|
stream_obj *s = (stream_obj *)gs; |
|
|
|
|
GRPC_ERROR_UNREF(s->state.cancel_error); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {} |
|
|
|
|
|
|
|
|
|