Error handling cleanup

reviewable/pr8842/r3
Craig Tiller 8 years ago
parent 732351f826
commit dc21a4efb2
  1. 96
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  2. 13
      src/core/ext/transport/chttp2/transport/frame_rst_stream.c
  3. 14
      src/core/ext/transport/chttp2/transport/frame_settings.c
  4. 2
      src/core/ext/transport/chttp2/transport/hpack_parser.c
  5. 3
      src/core/ext/transport/chttp2/transport/internal.h
  6. 8
      src/core/ext/transport/chttp2/transport/parsing.c
  7. 6
      src/core/ext/transport/chttp2/transport/writing.c
  8. 8
      src/core/lib/surface/call.c
  9. 10
      src/core/lib/surface/server.c
  10. 66
      src/core/lib/transport/error_utils.c
  11. 10
      src/core/lib/transport/error_utils.h
  12. 30
      src/core/lib/transport/http2_errors.h
  13. 36
      src/core/lib/transport/status_conversion.c
  14. 11
      src/core/lib/transport/status_conversion.h
  15. 7
      src/core/lib/transport/transport.h
  16. 11
      src/core/lib/transport/transport_op_string.c

@ -1252,11 +1252,16 @@ void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
} }
static void send_goaway(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void send_goaway(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_error_code error, grpc_slice data) { grpc_error *error) {
t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED; t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED;
grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)error, data, grpc_http2_error_code http_error;
&t->qbuf); const char *msg;
grpc_error_get_status(error, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL, &msg,
&http_error);
grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)http_error,
grpc_slice_from_copied_string(msg), &t->qbuf);
grpc_chttp2_initiate_write(exec_ctx, t, false, "goaway_sent"); grpc_chttp2_initiate_write(exec_ctx, t, false, "goaway_sent");
GRPC_ERROR_UNREF(error);
} }
static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx, static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
@ -1272,10 +1277,8 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
op->on_connectivity_state_change); op->on_connectivity_state_change);
} }
if (op->send_goaway) { if (op->goaway_error) {
send_goaway(exec_ctx, t, send_goaway(exec_ctx, t, op->goaway_error);
grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
grpc_slice_ref_internal(*op->goaway_message));
} }
if (op->set_accept_stream) { if (op->set_accept_stream) {
@ -1428,33 +1431,6 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
maybe_start_some_streams(exec_ctx, t); maybe_start_some_streams(exec_ctx, t);
} }
static void status_codes_from_error(grpc_error *error, gpr_timespec deadline,
grpc_chttp2_error_code *http2_error,
grpc_status_code *grpc_status) {
intptr_t ip_http;
intptr_t ip_grpc;
bool have_http =
grpc_error_get_int(error, GRPC_ERROR_INT_HTTP2_ERROR, &ip_http);
bool have_grpc =
grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &ip_grpc);
if (have_http) {
*http2_error = (grpc_chttp2_error_code)ip_http;
} else if (have_grpc) {
*http2_error =
grpc_chttp2_grpc_status_to_http2_error((grpc_status_code)ip_grpc);
} else {
*http2_error = GRPC_CHTTP2_INTERNAL_ERROR;
}
if (have_grpc) {
*grpc_status = (grpc_status_code)ip_grpc;
} else if (have_http) {
*grpc_status = grpc_chttp2_http2_error_to_grpc_status(
(grpc_chttp2_error_code)ip_http, deadline);
} else {
*grpc_status = GRPC_STATUS_INTERNAL;
}
}
void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx, void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_chttp2_transport *t, grpc_chttp2_stream *s,
grpc_error *due_to_error) { grpc_error *due_to_error) {
@ -1465,28 +1441,14 @@ void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx,
} }
if (!s->read_closed || !s->write_closed) { if (!s->read_closed || !s->write_closed) {
grpc_status_code grpc_status;
grpc_chttp2_error_code http_error;
status_codes_from_error(due_to_error, s->deadline, &http_error,
&grpc_status);
if (s->id != 0) { if (s->id != 0) {
grpc_http2_error_code http_error;
grpc_error_get_status(due_to_error, s->deadline, NULL, NULL, &http_error);
grpc_slice_buffer_add( grpc_slice_buffer_add(
&t->qbuf, grpc_chttp2_rst_stream_create(s->id, (uint32_t)http_error, &t->qbuf, grpc_chttp2_rst_stream_create(s->id, (uint32_t)http_error,
&s->stats.outgoing)); &s->stats.outgoing));
grpc_chttp2_initiate_write(exec_ctx, t, false, "rst_stream"); grpc_chttp2_initiate_write(exec_ctx, t, false, "rst_stream");
} }
const char *msg =
grpc_error_get_str(due_to_error, GRPC_ERROR_STR_GRPC_MESSAGE);
bool free_msg = false;
if (msg == NULL) {
free_msg = true;
msg = grpc_error_string(due_to_error);
}
grpc_slice msg_slice = grpc_slice_from_copied_string(msg);
grpc_chttp2_fake_status(exec_ctx, t, s, grpc_status, &msg_slice);
if (free_msg) grpc_error_free_string(msg);
} }
if (due_to_error != GRPC_ERROR_NONE && !s->seen_error) { if (due_to_error != GRPC_ERROR_NONE && !s->seen_error) {
s->seen_error = true; s->seen_error = true;
@ -1496,8 +1458,11 @@ void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx,
} }
void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_stream *s, grpc_status_code status, grpc_chttp2_stream *s, grpc_error *error) {
grpc_slice *slice) { grpc_status_code status;
const char *msg;
grpc_error_get_status(error, s->deadline, &status, &msg, NULL);
if (status != GRPC_STATUS_OK) { if (status != GRPC_STATUS_OK) {
s->seen_error = true; s->seen_error = true;
} }
@ -1515,18 +1480,17 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
&s->metadata_buffer[1], &s->metadata_buffer[1],
grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_STATUS, grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_STATUS,
grpc_slice_from_copied_string(status_string))); grpc_slice_from_copied_string(status_string)));
if (slice) { if (msg != NULL) {
grpc_chttp2_incoming_metadata_buffer_add( grpc_chttp2_incoming_metadata_buffer_add(
&s->metadata_buffer[1], &s->metadata_buffer[1],
grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_MESSAGE, grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
grpc_slice_ref_internal(*slice))); grpc_slice_from_copied_string(msg)));
} }
s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE; s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE;
grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s); grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
} }
if (slice) {
grpc_slice_unref_internal(exec_ctx, *slice); GRPC_ERROR_UNREF(error);
}
} }
static void add_error(grpc_error *error, grpc_error **refs, size_t *nrefs) { static void add_error(grpc_error *error, grpc_error **refs, size_t *nrefs) {
@ -1596,6 +1560,7 @@ void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx,
return; return;
} }
if (close_reads && !s->read_closed) { if (close_reads && !s->read_closed) {
grpc_chttp2_fake_status(exec_ctx, t, s, GRPC_ERROR_REF(error));
s->read_closed_error = GRPC_ERROR_REF(error); s->read_closed_error = GRPC_ERROR_REF(error);
s->read_closed = true; s->read_closed = true;
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
@ -1636,7 +1601,7 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
uint32_t len = 0; uint32_t len = 0;
grpc_status_code grpc_status; grpc_status_code grpc_status;
const char *msg; const char *msg;
grpc_error_get_status(error, &grpc_status, &msg); grpc_error_get_status(error, s->deadline, &grpc_status, &msg, NULL);
GPR_ASSERT(grpc_status >= 0 && (int)grpc_status < 100); GPR_ASSERT(grpc_status >= 0 && (int)grpc_status < 100);
@ -1719,14 +1684,9 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_slice_buffer_add(&t->qbuf, grpc_slice_from_copied_string(msg)); grpc_slice_buffer_add(&t->qbuf, grpc_slice_from_copied_string(msg));
} }
grpc_slice_buffer_add( grpc_slice_buffer_add(
&t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR, &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_HTTP2_NO_ERROR,
&s->stats.outgoing)); &s->stats.outgoing));
grpc_slice msg_slice =
msg == NULL ? grpc_empty_slice() : grpc_slice_from_copied_string(msg);
grpc_chttp2_fake_status(exec_ctx, t, s, grpc_status,
msg == NULL ? NULL : &msg_slice);
grpc_chttp2_mark_stream_closed(exec_ctx, t, s, 1, 1, error); grpc_chttp2_mark_stream_closed(exec_ctx, t, s, 1, 1, error);
grpc_chttp2_initiate_write(exec_ctx, t, false, "close_from_api"); grpc_chttp2_initiate_write(exec_ctx, t, false, "close_from_api");
} }
@ -2173,8 +2133,10 @@ static void benign_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
gpr_log(GPR_DEBUG, "HTTP2: %s - send goaway to free memory", gpr_log(GPR_DEBUG, "HTTP2: %s - send goaway to free memory",
t->peer_string); t->peer_string);
} }
send_goaway(exec_ctx, t, GRPC_CHTTP2_ENHANCE_YOUR_CALM, send_goaway(exec_ctx, t,
grpc_slice_from_static_string("Buffers full")); grpc_error_set_int(GRPC_ERROR_CREATE("Buffers full"),
GRPC_ERROR_INT_HTTP2_ERROR,
GRPC_HTTP2_ENHANCE_YOUR_CALM));
} else if (error == GRPC_ERROR_NONE && grpc_resource_quota_trace) { } else if (error == GRPC_ERROR_NONE && grpc_resource_quota_trace) {
gpr_log(GPR_DEBUG, gpr_log(GPR_DEBUG,
"HTTP2: %s - skip benign reclamation, there are still %" PRIdPTR "HTTP2: %s - skip benign reclamation, there are still %" PRIdPTR
@ -2203,7 +2165,7 @@ static void destructive_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_chttp2_cancel_stream( grpc_chttp2_cancel_stream(
exec_ctx, t, s, grpc_error_set_int(GRPC_ERROR_CREATE("Buffers full"), exec_ctx, t, s, grpc_error_set_int(GRPC_ERROR_CREATE("Buffers full"),
GRPC_ERROR_INT_HTTP2_ERROR, GRPC_ERROR_INT_HTTP2_ERROR,
GRPC_CHTTP2_ENHANCE_YOUR_CALM)); GRPC_HTTP2_ENHANCE_YOUR_CALM));
if (n > 1) { if (n > 1) {
/* Since we cancel one stream per destructive reclamation, if /* Since we cancel one stream per destructive reclamation, if
there are more streams left, we can immediately post a new there are more streams left, we can immediately post a new

@ -39,8 +39,7 @@
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include "src/core/ext/transport/chttp2/transport/frame.h" #include "src/core/ext/transport/chttp2/transport/frame.h"
#include "src/core/ext/transport/chttp2/transport/http2_errors.h" #include "src/core/lib/transport/http2_errors.h"
#include "src/core/ext/transport/chttp2/transport/status_conversion.h"
grpc_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code, grpc_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code,
grpc_transport_one_way_stats *stats) { grpc_transport_one_way_stats *stats) {
@ -109,17 +108,9 @@ grpc_error *grpc_chttp2_rst_stream_parser_parse(grpc_exec_ctx *exec_ctx,
(((uint32_t)p->reason_bytes[2]) << 8) | (((uint32_t)p->reason_bytes[2]) << 8) |
(((uint32_t)p->reason_bytes[3])); (((uint32_t)p->reason_bytes[3]));
grpc_error *error = GRPC_ERROR_NONE; grpc_error *error = GRPC_ERROR_NONE;
if (reason != GRPC_CHTTP2_NO_ERROR) { if (reason != GRPC_HTTP2_NO_ERROR) {
error = grpc_error_set_int(GRPC_ERROR_CREATE("RST_STREAM"), error = grpc_error_set_int(GRPC_ERROR_CREATE("RST_STREAM"),
GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)reason); GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)reason);
grpc_status_code status_code = grpc_chttp2_http2_error_to_grpc_status(
(grpc_chttp2_error_code)reason, s->deadline);
char *status_details;
gpr_asprintf(&status_details, "Received RST_STREAM with error code %d",
reason);
grpc_slice slice_details = grpc_slice_from_copied_string(status_details);
gpr_free(status_details);
grpc_chttp2_fake_status(exec_ctx, t, s, status_code, &slice_details);
} }
grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, true, error); grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, true, error);
} }

@ -52,21 +52,21 @@
const grpc_chttp2_setting_parameters const grpc_chttp2_setting_parameters
grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = { grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {
{NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, {NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
GRPC_CHTTP2_PROTOCOL_ERROR}, GRPC_HTTP2_PROTOCOL_ERROR},
{"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff, {"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff,
GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR}, GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
{"ENABLE_PUSH", 1, 0, 1, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, {"ENABLE_PUSH", 1, 0, 1, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
GRPC_CHTTP2_PROTOCOL_ERROR}, GRPC_HTTP2_PROTOCOL_ERROR},
{"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu, {"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu,
GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR}, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
{"INITIAL_WINDOW_SIZE", 65535, 0, 0x7fffffffu, {"INITIAL_WINDOW_SIZE", 65535, 0, 0x7fffffffu,
GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
GRPC_CHTTP2_FLOW_CONTROL_ERROR}, GRPC_HTTP2_FLOW_CONTROL_ERROR},
{"MAX_FRAME_SIZE", 16384, 16384, 16777215, {"MAX_FRAME_SIZE", 16384, 16384, 16777215,
GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR}, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_HTTP2_PROTOCOL_ERROR},
{"MAX_HEADER_LIST_SIZE", MAX_MAX_HEADER_LIST_SIZE, 0, {"MAX_HEADER_LIST_SIZE", MAX_MAX_HEADER_LIST_SIZE, 0,
MAX_MAX_HEADER_LIST_SIZE, GRPC_CHTTP2_CLAMP_INVALID_VALUE, MAX_MAX_HEADER_LIST_SIZE, GRPC_CHTTP2_CLAMP_INVALID_VALUE,
GRPC_CHTTP2_PROTOCOL_ERROR}, GRPC_HTTP2_PROTOCOL_ERROR},
}; };
static uint8_t *fill_header(uint8_t *out, uint32_t length, uint8_t flags) { static uint8_t *fill_header(uint8_t *out, uint32_t length, uint8_t flags) {

@ -1644,7 +1644,7 @@ static void force_client_rst_stream(grpc_exec_ctx *exec_ctx, void *sp,
grpc_chttp2_transport *t = s->t; grpc_chttp2_transport *t = s->t;
if (!s->write_closed) { if (!s->write_closed) {
grpc_slice_buffer_add( grpc_slice_buffer_add(
&t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR, &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_HTTP2_NO_ERROR,
&s->stats.outgoing)); &s->stats.outgoing));
grpc_chttp2_initiate_write(exec_ctx, t, false, "force_rst_stream"); grpc_chttp2_initiate_write(exec_ctx, t, false, "force_rst_stream");
grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, true, GRPC_ERROR_NONE); grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, true, GRPC_ERROR_NONE);

@ -612,8 +612,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
uint32_t stream_id, int64_t val1, int64_t val2); uint32_t stream_id, int64_t val1, int64_t val2);
void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_stream *stream, grpc_chttp2_stream *stream, grpc_error *error);
grpc_status_code status, grpc_slice *details);
void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx, void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_transport *t,
grpc_chttp2_stream *s, int close_reads, grpc_chttp2_stream *s, int close_reads,

@ -39,11 +39,11 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
#include "src/core/ext/transport/chttp2/transport/status_conversion.h"
#include "src/core/lib/profiling/timers.h" #include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/transport/http2_errors.h"
#include "src/core/lib/transport/static_metadata.h" #include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/status_conversion.h"
#include "src/core/lib/transport/timeout_encoding.h" #include "src/core/lib/transport/timeout_encoding.h"
static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx, static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx,
@ -433,7 +433,7 @@ error_handler:
} }
grpc_slice_buffer_add( grpc_slice_buffer_add(
&t->qbuf, grpc_chttp2_rst_stream_create(t->incoming_stream_id, &t->qbuf, grpc_chttp2_rst_stream_create(t->incoming_stream_id,
GRPC_CHTTP2_PROTOCOL_ERROR, GRPC_HTTP2_PROTOCOL_ERROR,
&s->stats.outgoing)); &s->stats.outgoing));
return init_skip_frame_parser(exec_ctx, t, 0); return init_skip_frame_parser(exec_ctx, t, 0);
} else { } else {
@ -758,7 +758,7 @@ static grpc_error *parse_frame_slice(grpc_exec_ctx *exec_ctx,
s->forced_close_error = err; s->forced_close_error = err;
grpc_slice_buffer_add( grpc_slice_buffer_add(
&t->qbuf, grpc_chttp2_rst_stream_create(t->incoming_stream_id, &t->qbuf, grpc_chttp2_rst_stream_create(t->incoming_stream_id,
GRPC_CHTTP2_PROTOCOL_ERROR, GRPC_HTTP2_PROTOCOL_ERROR,
&s->stats.outgoing)); &s->stats.outgoing));
} else { } else {
GRPC_ERROR_UNREF(err); GRPC_ERROR_UNREF(err);

@ -37,9 +37,9 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
#include "src/core/lib/profiling/timers.h" #include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/transport/http2_errors.h"
static void add_to_write_list(grpc_chttp2_write_cb **list, static void add_to_write_list(grpc_chttp2_write_cb **list,
grpc_chttp2_write_cb *cb) { grpc_chttp2_write_cb *cb) {
@ -164,7 +164,7 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
s->sent_trailing_metadata = true; s->sent_trailing_metadata = true;
if (!t->is_client && !s->read_closed) { if (!t->is_client && !s->read_closed) {
grpc_slice_buffer_add(&t->outbuf, grpc_chttp2_rst_stream_create( grpc_slice_buffer_add(&t->outbuf, grpc_chttp2_rst_stream_create(
s->id, GRPC_CHTTP2_NO_ERROR, s->id, GRPC_HTTP2_NO_ERROR,
&s->stats.outgoing)); &s->stats.outgoing));
} }
} }
@ -197,7 +197,7 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
if (!t->is_client && !s->read_closed) { if (!t->is_client && !s->read_closed) {
grpc_slice_buffer_add( grpc_slice_buffer_add(
&t->outbuf, grpc_chttp2_rst_stream_create( &t->outbuf, grpc_chttp2_rst_stream_create(
s->id, GRPC_CHTTP2_NO_ERROR, &s->stats.outgoing)); s->id, GRPC_HTTP2_NO_ERROR, &s->stats.outgoing));
} }
now_writing = true; now_writing = true;
} }

@ -336,10 +336,7 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
args->server_transport_data, path, call->start_time, send_deadline, args->server_transport_data, path, call->start_time, send_deadline,
CALL_STACK_FROM_CALL(call)); CALL_STACK_FROM_CALL(call));
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
grpc_status_code status; cancel_with_error(exec_ctx, call, GRPC_ERROR_REF(error));
const char *error_str;
grpc_error_get_status(error, &status, &error_str);
cancel_with_status(exec_ctx, call, status, error_str);
} }
if (args->cq != NULL) { if (args->cq != NULL) {
GPR_ASSERT( GPR_ASSERT(
@ -612,7 +609,8 @@ static void get_final_status(grpc_call *call,
grpc_status_code code; grpc_status_code code;
const char *msg = NULL; const char *msg = NULL;
grpc_error_get_status(call->status[i].error, &code, &msg); grpc_error_get_status(call->status[i].error, call->send_deadline, &code,
&msg, NULL);
set_value(code, set_value_user_data); set_value(code, set_value_user_data);
if (details != NULL) { if (details != NULL) {
*details = grpc_slice_from_copied_string(msg); *details = grpc_slice_from_copied_string(msg);

@ -280,18 +280,20 @@ static void shutdown_cleanup(grpc_exec_ctx *exec_ctx, void *arg,
} }
static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel, static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
int send_goaway, grpc_error *send_disconnect) { bool send_goaway, grpc_error *send_disconnect) {
struct shutdown_cleanup_args *sc = gpr_malloc(sizeof(*sc)); struct shutdown_cleanup_args *sc = gpr_malloc(sizeof(*sc));
grpc_closure_init(&sc->closure, shutdown_cleanup, sc, grpc_closure_init(&sc->closure, shutdown_cleanup, sc,
grpc_schedule_on_exec_ctx); grpc_schedule_on_exec_ctx);
grpc_transport_op *op = grpc_make_transport_op(&sc->closure); grpc_transport_op *op = grpc_make_transport_op(&sc->closure);
grpc_channel_element *elem; grpc_channel_element *elem;
op->send_goaway = send_goaway; op->goaway_error =
send_goaway
? grpc_error_set_int(GRPC_ERROR_CREATE("Server shutdown"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_OK)
: GRPC_ERROR_NONE;
op->set_accept_stream = true; op->set_accept_stream = true;
sc->slice = grpc_slice_from_copied_string("Server shutdown"); sc->slice = grpc_slice_from_copied_string("Server shutdown");
op->goaway_message = &sc->slice;
op->goaway_status = GRPC_STATUS_OK;
op->disconnect_with_error = send_disconnect; op->disconnect_with_error = send_disconnect;
elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);

@ -32,12 +32,14 @@
*/ */
#include "src/core/lib/transport/error_utils.h" #include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/iomgr/error_internal.h" #include "src/core/lib/iomgr/error_internal.h"
#include "src/core/lib/transport/status_conversion.h"
static grpc_error *recursively_find_error_with_status(grpc_error *error, static grpc_error *recursively_find_error_with_field(grpc_error *error,
intptr_t *status) { grpc_error_ints which) {
// If the error itself has a status code, return it. // If the error itself has a status code, return it.
if (grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, status)) { if (grpc_error_get_int(error, which, NULL)) {
return error; return error;
} }
if (grpc_error_is_special(error)) return NULL; if (grpc_error_is_special(error)) return NULL;
@ -46,32 +48,64 @@ static grpc_error *recursively_find_error_with_status(grpc_error *error,
while (true) { while (true) {
grpc_error *child_error = gpr_avl_get(error->errs, (void *)key++); grpc_error *child_error = gpr_avl_get(error->errs, (void *)key++);
if (child_error == NULL) break; if (child_error == NULL) break;
grpc_error *result = grpc_error *result = recursively_find_error_with_field(child_error, which);
recursively_find_error_with_status(child_error, status);
if (result != NULL) return result; if (result != NULL) return result;
} }
return NULL; return NULL;
} }
void grpc_error_get_status(grpc_error *error, grpc_status_code *code, void grpc_error_get_status(grpc_error *error, gpr_timespec deadline,
const char **msg) { grpc_status_code *code, const char **msg,
// Populate code. grpc_http2_error_code *http_error) {
// Start with the parent error and recurse through the tree of children // Start with the parent error and recurse through the tree of children
// until we find the first one that has a status code. // until we find the first one that has a status code.
intptr_t status = GRPC_STATUS_UNKNOWN; // Default in case we don't find one. grpc_error *found_error =
grpc_error *found_error = recursively_find_error_with_status(error, &status); recursively_find_error_with_field(error, GRPC_ERROR_INT_GRPC_STATUS);
*code = (grpc_status_code)status; if (found_error == NULL) {
// Now populate msg. /// If no grpc-status exists, retry through the tree to find a http2 error
/// code
found_error =
recursively_find_error_with_field(error, GRPC_ERROR_INT_HTTP2_ERROR);
}
// If we found an error with a status code above, use that; otherwise, // If we found an error with a status code above, use that; otherwise,
// fall back to using the parent error. // fall back to using the parent error.
if (found_error == NULL) found_error = error; if (found_error == NULL) found_error = error;
grpc_status_code status = GRPC_STATUS_UNKNOWN;
intptr_t integer;
if (grpc_error_get_int(found_error, GRPC_ERROR_INT_GRPC_STATUS, &integer)) {
status = (grpc_status_code)integer;
} else if (grpc_error_get_int(found_error, GRPC_ERROR_INT_HTTP2_ERROR,
&integer)) {
status = grpc_http2_error_to_grpc_status((grpc_http2_error_code)integer,
deadline);
}
if (code != NULL) *code = status;
if (http_error != NULL) {
if (grpc_error_get_int(found_error, GRPC_ERROR_INT_HTTP2_ERROR, &integer)) {
*http_error = (grpc_http2_error_code)integer;
} else if (grpc_error_get_int(found_error, GRPC_ERROR_INT_GRPC_STATUS,
&integer)) {
*http_error = grpc_status_to_http2_error((grpc_status_code)integer);
} else {
*http_error = found_error == GRPC_ERROR_NONE ? GRPC_HTTP2_NO_ERROR
: GRPC_HTTP2_INTERNAL_ERROR;
}
}
// If the error has a status message, use it. Otherwise, fall back to // If the error has a status message, use it. Otherwise, fall back to
// the error description. // the error description.
*msg = grpc_error_get_str(found_error, GRPC_ERROR_STR_GRPC_MESSAGE); if (msg != NULL) {
if (*msg == NULL && status != GRPC_STATUS_OK) { *msg = grpc_error_get_str(found_error, GRPC_ERROR_STR_GRPC_MESSAGE);
*msg = grpc_error_get_str(found_error, GRPC_ERROR_STR_DESCRIPTION); if (*msg == NULL && error != GRPC_ERROR_NONE) {
if (*msg == NULL) *msg = "unknown error"; // Just in case. *msg = grpc_error_get_str(found_error, GRPC_ERROR_STR_DESCRIPTION);
if (*msg == NULL) *msg = "unknown error"; // Just in case.
}
} }
if (found_error == NULL) found_error = error;
} }
bool grpc_error_has_clear_grpc_status(grpc_error *error) { bool grpc_error_has_clear_grpc_status(grpc_error *error) {

@ -35,12 +35,18 @@
#define GRPC_ERROR_UTILS_H #define GRPC_ERROR_UTILS_H
#include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/error.h"
#include "src/core/lib/transport/http2_errors.h"
/// A utility function to get the status code and message to be returned /// A utility function to get the status code and message to be returned
/// to the application. If not set in the top-level message, looks /// to the application. If not set in the top-level message, looks
/// through child errors until it finds the first one with these attributes. /// through child errors until it finds the first one with these attributes.
void grpc_error_get_status(grpc_error *error, grpc_status_code *code, /// All attributes are pulled from the same child error. If any of the
const char **msg); /// attributes (code, msg, http_status) are unneeded, they can be passed as
/// NULL.
void grpc_error_get_status(grpc_error *error, gpr_timespec deadline,
grpc_status_code *code, const char **msg,
grpc_http2_error_code *http_status);
/// A utility function to check whether there is a clear status code that /// A utility function to check whether there is a clear status code that
/// doesn't need to be guessed in \a error. This means that \a error or some /// doesn't need to be guessed in \a error. This means that \a error or some
/// child has GRPC_ERROR_INT_GRPC_STATUS set, or that it is GRPC_ERROR_NONE or /// child has GRPC_ERROR_INT_GRPC_STATUS set, or that it is GRPC_ERROR_NONE or

@ -36,21 +36,21 @@
/* error codes for RST_STREAM from http2 draft 14 section 7 */ /* error codes for RST_STREAM from http2 draft 14 section 7 */
typedef enum { typedef enum {
GRPC_CHTTP2_NO_ERROR = 0x0, GRPC_HTTP2_NO_ERROR = 0x0,
GRPC_CHTTP2_PROTOCOL_ERROR = 0x1, GRPC_HTTP2_PROTOCOL_ERROR = 0x1,
GRPC_CHTTP2_INTERNAL_ERROR = 0x2, GRPC_HTTP2_INTERNAL_ERROR = 0x2,
GRPC_CHTTP2_FLOW_CONTROL_ERROR = 0x3, GRPC_HTTP2_FLOW_CONTROL_ERROR = 0x3,
GRPC_CHTTP2_SETTINGS_TIMEOUT = 0x4, GRPC_HTTP2_SETTINGS_TIMEOUT = 0x4,
GRPC_CHTTP2_STREAM_CLOSED = 0x5, GRPC_HTTP2_STREAM_CLOSED = 0x5,
GRPC_CHTTP2_FRAME_SIZE_ERROR = 0x6, GRPC_HTTP2_FRAME_SIZE_ERROR = 0x6,
GRPC_CHTTP2_REFUSED_STREAM = 0x7, GRPC_HTTP2_REFUSED_STREAM = 0x7,
GRPC_CHTTP2_CANCEL = 0x8, GRPC_HTTP2_CANCEL = 0x8,
GRPC_CHTTP2_COMPRESSION_ERROR = 0x9, GRPC_HTTP2_COMPRESSION_ERROR = 0x9,
GRPC_CHTTP2_CONNECT_ERROR = 0xa, GRPC_HTTP2_CONNECT_ERROR = 0xa,
GRPC_CHTTP2_ENHANCE_YOUR_CALM = 0xb, GRPC_HTTP2_ENHANCE_YOUR_CALM = 0xb,
GRPC_CHTTP2_INADEQUATE_SECURITY = 0xc, GRPC_HTTP2_INADEQUATE_SECURITY = 0xc,
/* force use of a default clause */ /* force use of a default clause */
GRPC_CHTTP2__ERROR_DO_NOT_USE = -1 GRPC_HTTP2__ERROR_DO_NOT_USE = -1
} grpc_chttp2_error_code; } grpc_http2_error_code;
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_ERRORS_H */ #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_ERRORS_H */

@ -33,49 +33,49 @@
#include "src/core/lib/transport/status_conversion.h" #include "src/core/lib/transport/status_conversion.h"
int grpc_chttp2_grpc_status_to_http2_error(grpc_status_code status) { int grpc_status_to_http2_error(grpc_status_code status) {
switch (status) { switch (status) {
case GRPC_STATUS_OK: case GRPC_STATUS_OK:
return GRPC_CHTTP2_NO_ERROR; return GRPC_HTTP2_NO_ERROR;
case GRPC_STATUS_CANCELLED: case GRPC_STATUS_CANCELLED:
return GRPC_CHTTP2_CANCEL; return GRPC_HTTP2_CANCEL;
case GRPC_STATUS_DEADLINE_EXCEEDED: case GRPC_STATUS_DEADLINE_EXCEEDED:
return GRPC_CHTTP2_CANCEL; return GRPC_HTTP2_CANCEL;
case GRPC_STATUS_RESOURCE_EXHAUSTED: case GRPC_STATUS_RESOURCE_EXHAUSTED:
return GRPC_CHTTP2_ENHANCE_YOUR_CALM; return GRPC_HTTP2_ENHANCE_YOUR_CALM;
case GRPC_STATUS_PERMISSION_DENIED: case GRPC_STATUS_PERMISSION_DENIED:
return GRPC_CHTTP2_INADEQUATE_SECURITY; return GRPC_HTTP2_INADEQUATE_SECURITY;
case GRPC_STATUS_UNAVAILABLE: case GRPC_STATUS_UNAVAILABLE:
return GRPC_CHTTP2_REFUSED_STREAM; return GRPC_HTTP2_REFUSED_STREAM;
default: default:
return GRPC_CHTTP2_INTERNAL_ERROR; return GRPC_HTTP2_INTERNAL_ERROR;
} }
} }
grpc_status_code grpc_chttp2_http2_error_to_grpc_status( grpc_status_code grpc_http2_error_to_grpc_status(grpc_http2_error_code error,
grpc_chttp2_error_code error, gpr_timespec deadline) { gpr_timespec deadline) {
switch (error) { switch (error) {
case GRPC_CHTTP2_NO_ERROR: case GRPC_HTTP2_NO_ERROR:
/* should never be received */ /* should never be received */
return GRPC_STATUS_INTERNAL; return GRPC_STATUS_INTERNAL;
case GRPC_CHTTP2_CANCEL: case GRPC_HTTP2_CANCEL:
/* http2 cancel translates to STATUS_CANCELLED iff deadline hasn't been /* http2 cancel translates to STATUS_CANCELLED iff deadline hasn't been
* exceeded */ * exceeded */
return gpr_time_cmp(gpr_now(deadline.clock_type), deadline) >= 0 return gpr_time_cmp(gpr_now(deadline.clock_type), deadline) >= 0
? GRPC_STATUS_DEADLINE_EXCEEDED ? GRPC_STATUS_DEADLINE_EXCEEDED
: GRPC_STATUS_CANCELLED; : GRPC_STATUS_CANCELLED;
case GRPC_CHTTP2_ENHANCE_YOUR_CALM: case GRPC_HTTP2_ENHANCE_YOUR_CALM:
return GRPC_STATUS_RESOURCE_EXHAUSTED; return GRPC_STATUS_RESOURCE_EXHAUSTED;
case GRPC_CHTTP2_INADEQUATE_SECURITY: case GRPC_HTTP2_INADEQUATE_SECURITY:
return GRPC_STATUS_PERMISSION_DENIED; return GRPC_STATUS_PERMISSION_DENIED;
case GRPC_CHTTP2_REFUSED_STREAM: case GRPC_HTTP2_REFUSED_STREAM:
return GRPC_STATUS_UNAVAILABLE; return GRPC_STATUS_UNAVAILABLE;
default: default:
return GRPC_STATUS_INTERNAL; return GRPC_STATUS_INTERNAL;
} }
} }
grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status) { grpc_status_code grpc_http2_status_to_grpc_status(int status) {
switch (status) { switch (status) {
/* these HTTP2 status codes are called out explicitly in status.proto */ /* these HTTP2 status codes are called out explicitly in status.proto */
case 200: case 200:
@ -110,6 +110,4 @@ grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status) {
} }
} }
int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status) { int grpc_status_to_http2_status(grpc_status_code status) { return 200; }
return 200;
}

@ -38,13 +38,12 @@
#include "src/core/lib/transport/http2_errors.h" #include "src/core/lib/transport/http2_errors.h"
/* Conversion of grpc status codes to http2 error codes (for RST_STREAM) */ /* Conversion of grpc status codes to http2 error codes (for RST_STREAM) */
grpc_chttp2_error_code grpc_chttp2_grpc_status_to_http2_error( grpc_http2_error_code grpc_status_to_http2_error(grpc_status_code status);
grpc_status_code status); grpc_status_code grpc_http2_error_to_grpc_status(grpc_http2_error_code error,
grpc_status_code grpc_chttp2_http2_error_to_grpc_status( gpr_timespec deadline);
grpc_chttp2_error_code error, gpr_timespec deadline);
/* Conversion of HTTP status codes (:status) to grpc status codes */ /* Conversion of HTTP status codes (:status) to grpc status codes */
grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status); grpc_status_code grpc_http2_status_to_grpc_status(int status);
int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status); int grpc_status_to_http2_status(grpc_status_code status);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STATUS_CONVERSION_H */ #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STATUS_CONVERSION_H */

@ -181,13 +181,8 @@ typedef struct grpc_transport_op {
grpc_connectivity_state *connectivity_state; grpc_connectivity_state *connectivity_state;
/** should the transport be disconnected */ /** should the transport be disconnected */
grpc_error *disconnect_with_error; grpc_error *disconnect_with_error;
/** should we send a goaway?
after a goaway is sent, once there are no more active calls on
the transport, the transport should disconnect */
bool send_goaway;
/** what should the goaway contain? */ /** what should the goaway contain? */
grpc_status_code goaway_status; grpc_error *goaway_error;
grpc_slice *goaway_message;
/** set the callback for accepting new streams; /** set the callback for accepting new streams;
this is a permanent callback, unlike the other one-shot closures. this is a permanent callback, unlike the other one-shot closures.
If true, the callback is set to set_accept_stream_fn, with its If true, the callback is set to set_accept_stream_fn, with its

@ -163,15 +163,12 @@ char *grpc_transport_op_string(grpc_transport_op *op) {
grpc_error_free_string(err); grpc_error_free_string(err);
} }
if (op->send_goaway) { if (op->goaway_error) {
if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
first = false; first = false;
char *msg = op->goaway_message == NULL const char *msg = grpc_error_string(op->goaway_error);
? "null" gpr_asprintf(&tmp, "SEND_GOAWAY:%s", msg);
: grpc_dump_slice(*op->goaway_message, grpc_error_free_string(msg);
GPR_DUMP_ASCII | GPR_DUMP_HEX);
gpr_asprintf(&tmp, "SEND_GOAWAY:status=%d:msg=%s", op->goaway_status, msg);
if (op->goaway_message != NULL) gpr_free(msg);
gpr_strvec_add(&b, tmp); gpr_strvec_add(&b, tmp);
} }

Loading…
Cancel
Save